devharness 0.9.6 → 0.9.8

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 (67) 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/network-monitor.d.ts.map +1 -1
  30. package/build/network-monitor.js +16 -21
  31. package/build/network-monitor.js.map +1 -1
  32. package/build/network-monitor.test.d.ts +11 -0
  33. package/build/network-monitor.test.d.ts.map +1 -0
  34. package/build/network-monitor.test.js +101 -0
  35. package/build/network-monitor.test.js.map +1 -0
  36. package/build/self-restart.d.ts +5 -1
  37. package/build/self-restart.d.ts.map +1 -1
  38. package/build/self-restart.js +35 -5
  39. package/build/self-restart.js.map +1 -1
  40. package/build/self-restart.test.js +61 -17
  41. package/build/self-restart.test.js.map +1 -1
  42. package/build/server-manager-relocation.test.d.ts +2 -0
  43. package/build/server-manager-relocation.test.d.ts.map +1 -0
  44. package/build/server-manager-relocation.test.js +115 -0
  45. package/build/server-manager-relocation.test.js.map +1 -0
  46. package/build/server-manager-root-rebind.test.d.ts +2 -0
  47. package/build/server-manager-root-rebind.test.d.ts.map +1 -0
  48. package/build/server-manager-root-rebind.test.js +158 -0
  49. package/build/server-manager-root-rebind.test.js.map +1 -0
  50. package/build/server-manager.d.ts +19 -0
  51. package/build/server-manager.d.ts.map +1 -1
  52. package/build/server-manager.js +98 -4
  53. package/build/server-manager.js.map +1 -1
  54. package/build/supervisor/pidfile.d.ts +33 -6
  55. package/build/supervisor/pidfile.d.ts.map +1 -1
  56. package/build/supervisor/pidfile.js +76 -14
  57. package/build/supervisor/pidfile.js.map +1 -1
  58. package/build/supervisor/pidfile.test.js +37 -1
  59. package/build/supervisor/pidfile.test.js.map +1 -1
  60. package/build/tools/config-tools.d.ts.map +1 -1
  61. package/build/tools/config-tools.js +5 -0
  62. package/build/tools/config-tools.js.map +1 -1
  63. package/build/utils/modal-detection-core.test.js +21 -17
  64. package/build/utils/modal-detection-core.test.js.map +1 -1
  65. package/docs/messages.md +11 -0
  66. package/package.json +2 -1
  67. package/plugin/skills/devharness/SKILL.md +1 -1
@@ -0,0 +1,200 @@
1
+ /**
2
+ * FROZEN CONTRACT - registry-and-transaction half.
3
+ *
4
+ * Specifies the root-bound resource registry and the `relocateRoot`
5
+ * transaction that `config({ action: 'useLocal', path: X })` is meant to
6
+ * drive, so a relocation moves every dependent subsystem's storage root live,
7
+ * in-process, with no MCP server restart:
8
+ *
9
+ * Every stored path derives from one root held in paths.ts; code resolves a
10
+ * path at use or registers a root-bound resource carrying rebind or veto; a
11
+ * root change rebinds every registered resource, and one veto returns the
12
+ * change unapplied, naming the resource.
13
+ *
14
+ * None of the surface below exists yet in src/helpers/paths.ts. This file's
15
+ * failures against that missing surface are the intended red state.
16
+ *
17
+ * TARGET INTERFACE (paths.ts):
18
+ *
19
+ * export interface RootBoundResource {
20
+ * name: string;
21
+ * rebind(root: string): void | Promise<void>;
22
+ * veto?(): string | null; // a non-null string is a refusal reason
23
+ * }
24
+ * export function registerRootBound(resource: RootBoundResource): void;
25
+ * export function unregisterRootBound(name: string): void;
26
+ * export function relocateRoot(dir: string): Promise<void>;
27
+ *
28
+ * `veto` (not `canRebind`): a predicate named `canRebind` returning `true` to
29
+ * mean "no objection" collides with a truthy STRING reason for a veto -
30
+ * `if (resource.canRebind())` passes for both, so a veto would silently stop
31
+ * vetoing. `veto()` returning `null` (or being absent) means "no objection";
32
+ * any non-null string is the refusal reason.
33
+ *
34
+ * `relocateRoot(dir)` is new and separate from `setWorkingDirOverride(dir)`,
35
+ * which keeps its current synchronous signature (used at startup, before
36
+ * anything is registered, and by every existing test that calls it
37
+ * synchronously today - none of that is touched here). `relocateRoot` is the
38
+ * transaction: collect every registered resource's `veto()` first; any
39
+ * non-null veto rejects (message names the vetoing resource), leaving the
40
+ * root AND every resource untouched; with no veto, mutate the root, then
41
+ * `await` every resource's `rebind(root)`, in registration order.
42
+ *
43
+ * `ConfigManager.useLocal` is specified (not implemented here - production
44
+ * source is untouched) to call `relocateRoot` when given an explicit `path`.
45
+ *
46
+ * This file's one opinionated design choice beyond the brief: a second
47
+ * `registerRootBound` call under a name already held REPLACES the earlier
48
+ * registration (last write wins) rather than erroring or accumulating both.
49
+ * That matches the "re-registering under a name replaces the old entry"
50
+ * convention command-recorder.ts already uses for sequence names
51
+ * (`removeSequenceByName`, command-recorder.ts:643-649, motivated at
52
+ * :562-564: a name maps to exactly one entry, otherwise a lookup by name
53
+ * resolves the stale one).
54
+ *
55
+ * `registerRootBound`/`unregisterRootBound`/`relocateRoot` are reached
56
+ * through a namespace import so a missing export fails inside each test body
57
+ * (a clear per-test red result), not at module load, which would crash every
58
+ * test in the file at once and hide individual results.
59
+ *
60
+ * SCOPE NOTE: this file is the ONLY relocation spec file permitted to call
61
+ * `registerRootBound` directly - it is testing the registry itself. Every
62
+ * other relocation spec file (issue-tracker-relocation.test.ts,
63
+ * command-recorder-relocation.test.ts, server-manager-relocation.test.ts)
64
+ * MUST drive relocation through production code only. The last test in this
65
+ * file enforces that boundary by grepping the other files on disk.
66
+ */
67
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
68
+ import { mkdtempSync, rmSync, promises as fsp } from 'fs';
69
+ import { join, relative, dirname } from 'path';
70
+ import { tmpdir } from 'os';
71
+ import { fileURLToPath } from 'url';
72
+ import { getOutputPath, resolveStateDir } from './paths.js';
73
+ import * as pathsModule from './paths.js';
74
+ let rootA;
75
+ let rootB;
76
+ function register(resource) {
77
+ pathsModule.registerRootBound(resource);
78
+ }
79
+ function unregister(name) {
80
+ pathsModule.unregisterRootBound(name);
81
+ }
82
+ function relocate(dir) {
83
+ return pathsModule.relocateRoot(dir);
84
+ }
85
+ beforeEach(() => {
86
+ rootA = mkdtempSync(join(tmpdir(), 'devharness-paths-reloc-a-'));
87
+ rootB = mkdtempSync(join(tmpdir(), 'devharness-paths-reloc-b-'));
88
+ });
89
+ afterEach(() => {
90
+ // Best-effort cleanup so a resource registered by one test can't rebind (or
91
+ // veto) a later test's relocation. No-op today since unregisterRootBound
92
+ // doesn't exist yet - becomes load-bearing once it does.
93
+ for (const name of ['probe-a', 'probe-b', 'probe-veto', 'probe-x']) {
94
+ try {
95
+ unregister(name);
96
+ }
97
+ catch { /* not implemented yet, or never registered */ }
98
+ }
99
+ rmSync(rootA, { recursive: true, force: true });
100
+ rmSync(rootB, { recursive: true, force: true });
101
+ });
102
+ describe('relocateRoot as a transaction', () => {
103
+ it('with no veto: updates the root and rebinds every registered resource, in registration order, with the new root', async () => {
104
+ const calls = [];
105
+ register({ name: 'probe-a', rebind: (root) => { calls.push(`a:${root}`); } });
106
+ register({ name: 'probe-b', rebind: (root) => { calls.push(`b:${root}`); } });
107
+ await relocate(rootB);
108
+ const expectedRoot = resolveStateDir(rootB);
109
+ expect(calls).toEqual([`a:${expectedRoot}`, `b:${expectedRoot}`]);
110
+ expect(getOutputPath()).toBe(expectedRoot);
111
+ });
112
+ it('one veto: the root is left unchanged, no resource is rebound, and the rejection names the vetoing resource', async () => {
113
+ await relocate(rootA); // establish a known baseline root
114
+ const baselineRoot = getOutputPath();
115
+ const rebindSpy = vi.fn();
116
+ register({ name: 'probe-a', rebind: rebindSpy });
117
+ register({
118
+ name: 'probe-veto',
119
+ rebind: vi.fn(),
120
+ veto: () => 'managed server "fitness-demo" is running and cannot move its log files',
121
+ });
122
+ await expect(relocate(rootB)).rejects.toThrow(/probe-veto/);
123
+ await expect(relocate(rootB)).rejects.toThrow(/fitness-demo/);
124
+ expect(rebindSpy).not.toHaveBeenCalled();
125
+ expect(getOutputPath()).toBe(baselineRoot);
126
+ });
127
+ it('veto() returning a truthy non-string is not treated as a refusal (guards against the canRebind/true collision this rename fixes)', async () => {
128
+ // A resource whose veto() (mis-)implemented as "true means blocked" would
129
+ // fail this - the contract is: only a string return value is a veto.
130
+ register({ name: 'probe-a', rebind: vi.fn(), veto: () => null });
131
+ await expect(relocate(rootB)).resolves.toBeUndefined();
132
+ });
133
+ it('a resource that does not veto is unaffected by a sibling resource that does: transaction is all-or-nothing', async () => {
134
+ await relocate(rootA);
135
+ const baselineRoot = getOutputPath();
136
+ const rebindSpy = vi.fn();
137
+ register({ name: 'probe-a', rebind: rebindSpy, veto: () => null });
138
+ register({ name: 'probe-veto', rebind: vi.fn(), veto: () => 'blocked' });
139
+ await expect(relocate(rootB)).rejects.toThrow();
140
+ expect(rebindSpy).not.toHaveBeenCalled();
141
+ expect(getOutputPath()).toBe(baselineRoot);
142
+ });
143
+ });
144
+ describe('registry contract', () => {
145
+ it('an unregistered resource does not rebind on a later relocation', async () => {
146
+ const rebindSpy = vi.fn();
147
+ register({ name: 'probe-a', rebind: rebindSpy });
148
+ unregister('probe-a');
149
+ await relocate(rootB);
150
+ expect(rebindSpy).not.toHaveBeenCalled();
151
+ });
152
+ it('re-registering the same name replaces the earlier registration (last write wins), not both firing', async () => {
153
+ const firstSpy = vi.fn();
154
+ const secondSpy = vi.fn();
155
+ register({ name: 'probe-x', rebind: firstSpy });
156
+ register({ name: 'probe-x', rebind: secondSpy }); // same name, no unregister in between
157
+ await relocate(rootB);
158
+ expect(firstSpy).not.toHaveBeenCalled();
159
+ expect(secondSpy).toHaveBeenCalledTimes(1);
160
+ });
161
+ it('a veto from the replacement registration is the one that applies, not the replaced original', async () => {
162
+ register({ name: 'probe-x', rebind: vi.fn(), veto: () => null });
163
+ register({ name: 'probe-x', rebind: vi.fn(), veto: () => 'replacement vetoes' });
164
+ await expect(relocate(rootB)).rejects.toThrow(/probe-x/);
165
+ });
166
+ });
167
+ describe('relocation spec contract (rule 1)', () => {
168
+ const THIS_FILE = fileURLToPath(import.meta.url);
169
+ const SRC_ROOT = join(dirname(THIS_FILE), '..');
170
+ async function findRelocationSpecFiles(dir) {
171
+ const entries = await fsp.readdir(dir, { withFileTypes: true });
172
+ const files = [];
173
+ for (const entry of entries) {
174
+ const full = join(dir, entry.name);
175
+ if (entry.isDirectory()) {
176
+ if (entry.name === 'node_modules')
177
+ continue;
178
+ files.push(...await findRelocationSpecFiles(full));
179
+ }
180
+ else if (entry.isFile() && entry.name.endsWith('-relocation.test.ts')) {
181
+ files.push(full);
182
+ }
183
+ }
184
+ return files;
185
+ }
186
+ it('no relocation spec file except this one drives relocation by calling registerRootBound(...) itself', async () => {
187
+ const specFiles = await findRelocationSpecFiles(SRC_ROOT);
188
+ const violations = [];
189
+ for (const file of specFiles) {
190
+ if (file === THIS_FILE)
191
+ continue; // this file's own registry-contract tests are exempt
192
+ const content = await fsp.readFile(file, 'utf-8');
193
+ if (content.includes('registerRootBound(')) {
194
+ violations.push(relative(SRC_ROOT, file));
195
+ }
196
+ }
197
+ expect(violations).toEqual([]);
198
+ });
199
+ });
200
+ //# sourceMappingURL=paths-relocation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths-relocation.test.js","sourceRoot":"","sources":["../../src/helpers/paths-relocation.test.ts"],"names":[],"mappings":"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"}
@@ -95,6 +95,41 @@ export declare function getTempPath(...segments: string[]): string;
95
95
  * Check if working directory storage is available (cwd is valid).
96
96
  */
97
97
  export declare function hasWorkingDirStorage(): boolean;
98
+ /**
99
+ * A subsystem whose storage derives from the state root and so must react
100
+ * when `relocateRoot` moves it - a watcher left bound to the old root serves
101
+ * stale data forever, since nothing else invalidates it.
102
+ */
103
+ export interface RootBoundResource {
104
+ name: string;
105
+ rebind(root: string): void | Promise<void>;
106
+ /**
107
+ * A non-null string blocks relocation and becomes the rejection's message.
108
+ * Not `canRebind(): boolean` - a truthy `true` and a truthy refusal string
109
+ * both pass `if (resource.canRebind())`, so a boolean-returning predicate
110
+ * silently loses its veto. `null` (or omitting `veto`) is the only "no
111
+ * objection" value.
112
+ */
113
+ veto?(): string | null;
114
+ }
115
+ /**
116
+ * Register (or replace) a root-bound resource. A second registration under a
117
+ * name already held replaces the first - two entries for the same name would
118
+ * leave the earlier one still veto-checked and rebound after the caller
119
+ * that registered it has moved on, with no way to tell which one applies.
120
+ */
121
+ export declare function registerRootBound(resource: RootBoundResource): void;
122
+ /** Drop a resource from the registry - it stops receiving future rebind/veto calls. */
123
+ export declare function unregisterRootBound(name: string): void;
124
+ /**
125
+ * Move the state root live, in-process. Every registered resource's `veto()`
126
+ * runs first; a non-null string from any of them stops the transaction
127
+ * before the root or any resource is touched, so a partial relocation never
128
+ * leaves one resource pointed at the new root while another still holds the
129
+ * old one. With no veto, the root updates, then every resource's `rebind`
130
+ * runs in registration order with the new root.
131
+ */
132
+ export declare function relocateRoot(dir: string): Promise<void>;
98
133
  /** @deprecated Use getOutputPath() */
99
134
  export declare function getWorkingDirPath(...segments: string[]): string;
100
135
  /** @deprecated Use getOutputPath(...segments, { global: true }) */
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/helpers/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAyBtD;AAED,kDAAkD;AAClD,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,QAAA,MAAM,iBAAiB;;;;;;EAEZ,CAAC;AAEZ,UAAU,UAAU;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAsBD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAW5C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC,GACxE,MAAM,CA0BR;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAUxE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAGzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAG9C;AAGD,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAE/D;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3D;AAED,sCAAsC;AACtC,eAAO,MAAM,iBAAiB,sBAAgB,CAAC"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/helpers/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAyBtD;AAED,kDAAkD;AAClD,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,QAAA,MAAM,iBAAiB;;;;;;EAEZ,CAAC;AAEZ,UAAU,UAAU;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAsBD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAW5C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,GAAG,IAAI,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC,GACxE,MAAM,CA0BR;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAatC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAUxE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAGzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAG9C;AAOD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,MAAM,GAAG,IAAI,CAAC;CACxB;AAID;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAEnE;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEtD;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc7D;AAGD,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAE/D;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAE3D;AAED,sCAAsC;AACtC,eAAO,MAAM,iBAAiB,sBAAgB,CAAC"}
@@ -213,6 +213,41 @@ export function hasWorkingDirStorage() {
213
213
  initializePaths();
214
214
  return pathConfig.workingDirBase !== null;
215
215
  }
216
+ const rootBoundRegistry = new Map();
217
+ /**
218
+ * Register (or replace) a root-bound resource. A second registration under a
219
+ * name already held replaces the first - two entries for the same name would
220
+ * leave the earlier one still veto-checked and rebound after the caller
221
+ * that registered it has moved on, with no way to tell which one applies.
222
+ */
223
+ export function registerRootBound(resource) {
224
+ rootBoundRegistry.set(resource.name, resource);
225
+ }
226
+ /** Drop a resource from the registry - it stops receiving future rebind/veto calls. */
227
+ export function unregisterRootBound(name) {
228
+ rootBoundRegistry.delete(name);
229
+ }
230
+ /**
231
+ * Move the state root live, in-process. Every registered resource's `veto()`
232
+ * runs first; a non-null string from any of them stops the transaction
233
+ * before the root or any resource is touched, so a partial relocation never
234
+ * leaves one resource pointed at the new root while another still holds the
235
+ * old one. With no veto, the root updates, then every resource's `rebind`
236
+ * runs in registration order with the new root.
237
+ */
238
+ export async function relocateRoot(dir) {
239
+ for (const resource of rootBoundRegistry.values()) {
240
+ const reason = resource.veto?.();
241
+ if (reason) {
242
+ throw new Error(`relocateRoot: '${resource.name}' vetoed the relocation: ${reason}`);
243
+ }
244
+ }
245
+ setWorkingDirOverride(dir);
246
+ const root = getOutputPath();
247
+ for (const resource of rootBoundRegistry.values()) {
248
+ await resource.rebind(root);
249
+ }
250
+ }
216
251
  // Deprecated aliases for backwards compatibility
217
252
  /** @deprecated Use getOutputPath() */
218
253
  export function getWorkingDirPath(...segments) {
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/helpers/paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/helpers/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=issue-tracker-relocation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-tracker-relocation.test.d.ts","sourceRoot":"","sources":["../src/issue-tracker-relocation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * FROZEN CONTRACT - issue-tracker half.
3
+ *
4
+ * Specifies what `config({ action: 'useLocal', path: X })` must do to the
5
+ * issue tracker's storage root, live, in-process, with no MCP server restart.
6
+ *
7
+ * BACKGROUND (why this exists): `checkBugBlocking` (src/tool-response.ts:364)
8
+ * calls `hasPendingBugs()` on EVERY tool call, `config` included, BEFORE that
9
+ * tool's own handler runs (index.ts:1683 vs :1702). `hasPendingBugs()` calls
10
+ * `ensureIndexLoaded()` (issue-tracker.ts:538), a one-shot gate
11
+ * (`if (index) return`, :539) that scans `getItemsDir()` and binds an
12
+ * `fs.watch` to it ONCE per process. Nothing today invalidates that cache when
13
+ * `useLocal path=X` moves the storage root - `issues list` keeps serving
14
+ * whatever directory happened to be current the first time ANY tool call
15
+ * touched the tracker, which in the reported incident was the pre-relocation
16
+ * root, by then emptied by a manual file move.
17
+ *
18
+ * TARGET DESIGN: issue-tracker.ts registers a `RootBoundResource` (see
19
+ * src/helpers/paths-relocation.test.ts for that registry's own contract)
20
+ * whose `rebind()` closes the current watcher, drops the in-memory index, and
21
+ * lets the next read rescan `getItemsDir()` - which by then resolves under
22
+ * the new root because `relocateRoot` mutates the root before calling any
23
+ * `rebind`.
24
+ *
25
+ * RULE (imposed by the coordinator on this revision): a test in this file
26
+ * must NOT call `registerRootBound` itself - simulating the module's own
27
+ * production registration in-test would make these tests validate registry
28
+ * mechanics while leaving the actual bug (the index staying pinned to the old
29
+ * root) able to survive a green suite. Every test here drives relocation
30
+ * through `relocateRoot` (the production transaction, paths.ts) or
31
+ * `ConfigManager.useLocal` (the MCP-facing entry point, config.ts) only, and
32
+ * only imports and calls issue-tracker.ts's own real functions
33
+ * (`getIssues`, `addIssue`, `hasPendingBugs`, `getIssueItemsDir`,
34
+ * `__resetForTests`). `paths-relocation.test.ts`'s own registry-contract
35
+ * tests are the only ones exempt from this rule.
36
+ *
37
+ * Reached through namespace imports so a missing export fails inside each
38
+ * test body (a clear per-test red result), not at module load - which would
39
+ * crash every test in the file at once and hide individual results.
40
+ *
41
+ * FAILURE CLASSES a test in this file can show, in the order a real build
42
+ * would retire them:
43
+ * 1. "missing export" - `relocateRoot` (or the registry it depends on)
44
+ * does not exist in paths.ts yet. Surfaces as a thrown TypeError before
45
+ * any assertion runs. This is everything's current state - paths.ts has
46
+ * none of this surface today.
47
+ * 2. "missing wiring" - `relocateRoot` exists and runs to completion
48
+ * (no veto, since nothing has registered), but issue-tracker.ts never
49
+ * registered a resource, so nothing rebinds. Surfaces as a normal
50
+ * assertion failure (stale data), not a crash - it can only be observed
51
+ * once class 1 is fixed, so it is not separately reproducible today.
52
+ * 3. "useLocal does not forward" - `relocateRoot` and issue-tracker's
53
+ * wiring both work, but `ConfigManager.useLocal` was never updated to
54
+ * call `relocateRoot`, so it silently keeps running its old
55
+ * `setWorkingDirOverride`-only behavior. Only the one test that drives
56
+ * relocation through `ConfigManager.useLocal` (marked below) can show
57
+ * this class; right now it manifests exactly like class 1/2 (an
58
+ * assertion failure, because `useLocal` throws nothing either way).
59
+ */
60
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
61
+ import { promises as fsp } from 'fs';
62
+ import { tmpdir } from 'os';
63
+ import { join } from 'path';
64
+ import { setWorkingDirOverride } from './helpers/paths.js';
65
+ import * as pathsModule from './helpers/paths.js';
66
+ import { ConfigManager } from './config.js';
67
+ import { __resetForTests, addIssue, getIssues, getIssueItemsDir, hasPendingBugs, } from './issue-tracker.js';
68
+ let rootA;
69
+ let rootB;
70
+ function relocate(dir) {
71
+ return pathsModule.relocateRoot(dir);
72
+ }
73
+ beforeEach(async () => {
74
+ rootA = await fsp.mkdtemp(join(tmpdir(), 'devharness-it-reloc-a-'));
75
+ rootB = await fsp.mkdtemp(join(tmpdir(), 'devharness-it-reloc-b-'));
76
+ setWorkingDirOverride(rootA);
77
+ __resetForTests();
78
+ });
79
+ afterEach(async () => {
80
+ __resetForTests();
81
+ await fsp.rm(rootA, { recursive: true, force: true });
82
+ await fsp.rm(rootB, { recursive: true, force: true });
83
+ });
84
+ function issueFrontmatter(id, type, title) {
85
+ return [
86
+ '---',
87
+ `id: ${id}`,
88
+ `type: ${type}`,
89
+ 'status: pending',
90
+ `title: "${title}"`,
91
+ 'reportedAt: 2026-01-01T00:00:00.000Z',
92
+ '---',
93
+ '',
94
+ 'Body.',
95
+ '',
96
+ ].join('\n');
97
+ }
98
+ describe('relocateRoot: issue-tracker index (scenario a)', () => {
99
+ it('reflects X\'s items dir after relocateRoot(X), even though the index was primed from A first (the reported scenario)', async () => {
100
+ // Prime the in-memory index/watcher from root A, exactly like
101
+ // checkBugBlocking's hasPendingBugs() does on every tool call before a
102
+ // handler ever runs (index.ts:1683).
103
+ await hasPendingBugs();
104
+ // Root B already has issues on disk - as if created by another process,
105
+ // or manually moved there, before relocation ever ran.
106
+ const itemsDirB = join(rootB, '.devharness', 'issues', 'items');
107
+ await fsp.mkdir(itemsDirB, { recursive: true });
108
+ await fsp.writeFile(join(itemsDirB, 'feature-001-first.md'), issueFrontmatter(1, 'feature', 'First'), 'utf-8');
109
+ await fsp.writeFile(join(itemsDirB, 'feature-002-second.md'), issueFrontmatter(2, 'feature', 'Second'), 'utf-8');
110
+ await relocate(rootB);
111
+ const issues = await getIssues();
112
+ expect(issues.map(i => i.id).sort((a, b) => a - b)).toEqual([1, 2]);
113
+ expect(issues.map(i => i.title).sort()).toEqual(['First', 'Second']);
114
+ });
115
+ });
116
+ describe('relocateRoot: issue numbering (scenario b)', () => {
117
+ it('a created issue after relocation numbers after what already exists on disk at X (collision case: feature-001 pre-exists at X)', async () => {
118
+ const itemsDirB = join(rootB, '.devharness', 'issues', 'items');
119
+ await fsp.mkdir(itemsDirB, { recursive: true });
120
+ await fsp.writeFile(join(itemsDirB, 'feature-001-existing.md'), issueFrontmatter(1, 'feature', 'Existing'), 'utf-8');
121
+ await relocate(rootB);
122
+ const created = await addIssue({ type: 'feature', title: 'New after relocation' });
123
+ // Must not restart numbering from 1 - that would collide with the
124
+ // feature-001 file already on disk at X.
125
+ expect(created.id).toBe(2);
126
+ const items = await fsp.readdir(itemsDirB);
127
+ expect(items.filter(f => f.startsWith('feature-001-'))).toHaveLength(1);
128
+ expect(items.some(f => f.startsWith('feature-002-'))).toBe(true);
129
+ });
130
+ });
131
+ describe('relocateRoot: fs.watch rebind (scenario c)', () => {
132
+ it('a file added to X/items after relocation appears in the index', async () => {
133
+ await hasPendingBugs(); // prime from A first, as in the reported scenario
134
+ await relocate(rootB);
135
+ const itemsDirB = getIssueItemsDir();
136
+ expect(itemsDirB.startsWith(rootB)).toBe(true);
137
+ await fsp.mkdir(itemsDirB, { recursive: true });
138
+ await fsp.writeFile(join(itemsDirB, 'feature-007-external.md'), issueFrontmatter(7, 'feature', 'External after relocation'), 'utf-8');
139
+ // Wait past the watcher's debounce window (250ms, issue-tracker.ts's
140
+ // RELOAD_DEBOUNCE_MS) - same margin issue-tracker.test.ts's own
141
+ // "picks up an externally-written issue file" case uses.
142
+ await new Promise(resolve => setTimeout(resolve, 500));
143
+ const issues = await getIssues();
144
+ expect(issues.some(i => i.id === 7 && i.title === 'External after relocation')).toBe(true);
145
+ });
146
+ });
147
+ describe('relocateRoot: ordering independence (scenario f, simulated)', () => {
148
+ it('[ordering, simulated] a checkBugBlocking-style priming call against A does not pin the index to A once relocateRoot(B) runs', async () => {
149
+ // This simulates, rather than drives through the real MCP
150
+ // CallToolRequestSchema pipeline, the ordering index.ts actually produces
151
+ // on every tool call: index.ts:1683 runs checkBugBlocking() ->
152
+ // hasPendingBugs() BEFORE index.ts:1702 runs the tool's own handler - and
153
+ // this happens even when the tool call IS `config` itself, since
154
+ // checkBugBlocking has no `toolName !== 'config'` exemption (unlike
155
+ // index.ts:1599 and :1604). Driving the actual handler in-process would
156
+ // require constructing a full MCP server instance (chromeLauncher,
157
+ // connectionManager, serverManager, commandRecorder, startupGate, ...),
158
+ // which no existing test does; this reproduces the same two-call
159
+ // ordering directly instead. Under the registry design this ordering
160
+ // should stop mattering: rebind happens inside relocateRoot's own
161
+ // transaction, not depending on nothing having touched the tracker
162
+ // beforehand.
163
+ await hasPendingBugs(); // the checkBugBlocking-triggered priming call, against A
164
+ const itemsDirB = join(rootB, '.devharness', 'issues', 'items');
165
+ await fsp.mkdir(itemsDirB, { recursive: true });
166
+ await fsp.writeFile(join(itemsDirB, 'feature-009-ordering.md'), issueFrontmatter(9, 'feature', 'Ordering case'), 'utf-8');
167
+ await relocate(rootB); // the tool's own handler, running after the priming call above
168
+ const issues = await getIssues();
169
+ expect(issues.some(i => i.id === 9 && i.title === 'Ordering case')).toBe(true);
170
+ });
171
+ });
172
+ describe('ConfigManager.useLocal forwards to relocateRoot (extra coverage, not part of scenarios a-e)', () => {
173
+ it('[useLocal end-to-end] useLocal(path=X) alone reproduces the reported bug fix - it must not be possible to pass every other test here while useLocal itself still only calls the old setWorkingDirOverride', async () => {
174
+ // This is the one test in this file driven through ConfigManager.useLocal
175
+ // rather than relocateRoot directly - closing the loop the coordinator's
176
+ // rule 3 specifies ("ConfigManager.useLocal is specified to call
177
+ // relocateRoot") but that no other test here exercises, since every
178
+ // other test intentionally calls relocateRoot directly to isolate
179
+ // registry/wiring failures from a config.ts forwarding bug. Today this
180
+ // fails as a plain assertion mismatch: config.ts's useLocal still only
181
+ // calls the old (unrelocated) setWorkingDirOverride, so it throws
182
+ // nothing - the relocation silently does not happen.
183
+ await hasPendingBugs();
184
+ const itemsDirB = join(rootB, '.devharness', 'issues', 'items');
185
+ await fsp.mkdir(itemsDirB, { recursive: true });
186
+ await fsp.writeFile(join(itemsDirB, 'feature-011-useLocal.md'), issueFrontmatter(11, 'feature', 'Via useLocal'), 'utf-8');
187
+ const manager = new ConfigManager();
188
+ await manager.useLocal(false, rootB);
189
+ const issues = await getIssues();
190
+ expect(issues.some(i => i.id === 11 && i.title === 'Via useLocal')).toBe(true);
191
+ });
192
+ });
193
+ //# sourceMappingURL=issue-tracker-relocation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-tracker-relocation.test.js","sourceRoot":"","sources":["../src/issue-tracker-relocation.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"issue-tracker.d.ts","sourceRoot":"","sources":["../src/issue-tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"issue-tracker.d.ts","sourceRoot":"","sources":["../src/issue-tracker.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { promises as fs, watch as fsWatch } from 'fs';
11
11
  import { join } from 'path';
12
- import { getOutputPath } from './helpers/paths.js';
12
+ import { getOutputPath, registerRootBound } from './helpers/paths.js';
13
13
  import { atomicWriteFile } from './atomic-write.js';
14
14
  const CLOSED_REASONS = new Set(['completed', 'not_planned', 'duplicate']);
15
15
  const COMPLETED_STATUSES = new Set(['fixed', 'implemented']);
@@ -374,10 +374,12 @@ let watcher = null;
374
374
  let reloadTimer = null;
375
375
  const RELOAD_DEBOUNCE_MS = 250;
376
376
  /**
377
- * Test-only: resets in-memory state (closing any active watcher) so the next
378
- * ensureIndexLoaded() re-scans from disk. Not part of the tool-facing API.
377
+ * Close the watcher, drop the pending debounced reload, and clear the index
378
+ * so the next read misses the one-shot `if (index) return` gate in
379
+ * ensureIndexLoaded() and rescans from disk instead of continuing to serve
380
+ * whatever directory was current when the index was first primed.
379
381
  */
380
- export function __resetForTests() {
382
+ function resetIndexState() {
381
383
  if (watcher) {
382
384
  watcher.close();
383
385
  watcher = null;
@@ -389,6 +391,20 @@ export function __resetForTests() {
389
391
  index = null;
390
392
  nextIssueId = 1;
391
393
  }
394
+ /**
395
+ * Test-only: resets in-memory state (closing any active watcher) so the next
396
+ * ensureIndexLoaded() re-scans from disk. Not part of the tool-facing API.
397
+ */
398
+ export function __resetForTests() {
399
+ resetIndexState();
400
+ }
401
+ // A root relocation moves getItemsDir()'s target directory (it derives from
402
+ // getOutputPath()); without this, the index and watcher opened against the
403
+ // old root would keep serving it, silently, for the rest of the process.
404
+ registerRootBound({
405
+ name: 'issue-tracker',
406
+ rebind: () => resetIndexState(),
407
+ });
392
408
  async function scanIssuesDir() {
393
409
  const dir = getItemsDir();
394
410
  const map = new Map();