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.
- package/build/command-recorder-relocation.test.d.ts +2 -0
- package/build/command-recorder-relocation.test.d.ts.map +1 -0
- package/build/command-recorder-relocation.test.js +76 -0
- package/build/command-recorder-relocation.test.js.map +1 -0
- package/build/command-recorder.d.ts +1 -0
- package/build/command-recorder.d.ts.map +1 -1
- package/build/command-recorder.js +19 -1
- package/build/command-recorder.js.map +1 -1
- package/build/config.d.ts.map +1 -1
- package/build/config.js +5 -2
- package/build/config.js.map +1 -1
- package/build/helpers/paths-relocation.test.d.ts +2 -0
- package/build/helpers/paths-relocation.test.d.ts.map +1 -0
- package/build/helpers/paths-relocation.test.js +200 -0
- package/build/helpers/paths-relocation.test.js.map +1 -0
- package/build/helpers/paths.d.ts +35 -0
- package/build/helpers/paths.d.ts.map +1 -1
- package/build/helpers/paths.js +35 -0
- package/build/helpers/paths.js.map +1 -1
- package/build/issue-tracker-relocation.test.d.ts +2 -0
- package/build/issue-tracker-relocation.test.d.ts.map +1 -0
- package/build/issue-tracker-relocation.test.js +193 -0
- package/build/issue-tracker-relocation.test.js.map +1 -0
- package/build/issue-tracker.d.ts.map +1 -1
- package/build/issue-tracker.js +20 -4
- package/build/issue-tracker.js.map +1 -1
- package/build/mcp-supervisor.js +4 -3
- package/build/mcp-supervisor.js.map +1 -1
- package/build/self-restart.d.ts +5 -1
- package/build/self-restart.d.ts.map +1 -1
- package/build/self-restart.js +35 -5
- package/build/self-restart.js.map +1 -1
- package/build/self-restart.test.js +61 -17
- package/build/self-restart.test.js.map +1 -1
- package/build/server-manager-relocation.test.d.ts +2 -0
- package/build/server-manager-relocation.test.d.ts.map +1 -0
- package/build/server-manager-relocation.test.js +115 -0
- package/build/server-manager-relocation.test.js.map +1 -0
- package/build/server-manager-root-rebind.test.d.ts +2 -0
- package/build/server-manager-root-rebind.test.d.ts.map +1 -0
- package/build/server-manager-root-rebind.test.js +158 -0
- package/build/server-manager-root-rebind.test.js.map +1 -0
- package/build/server-manager.d.ts +19 -0
- package/build/server-manager.d.ts.map +1 -1
- package/build/server-manager.js +98 -4
- package/build/server-manager.js.map +1 -1
- package/build/supervisor/pidfile.d.ts +33 -6
- package/build/supervisor/pidfile.d.ts.map +1 -1
- package/build/supervisor/pidfile.js +76 -14
- package/build/supervisor/pidfile.js.map +1 -1
- package/build/supervisor/pidfile.test.js +37 -1
- package/build/supervisor/pidfile.test.js.map +1 -1
- package/build/tools/config-tools.d.ts.map +1 -1
- package/build/tools/config-tools.js +5 -0
- package/build/tools/config-tools.js.map +1 -1
- package/build/utils/modal-detection-core.test.js +21 -17
- package/build/utils/modal-detection-core.test.js.map +1 -1
- package/docs/messages.md +11 -0
- package/package.json +1 -1
- 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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"}
|
package/build/helpers/paths.d.ts
CHANGED
|
@@ -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"}
|
package/build/helpers/paths.js
CHANGED
|
@@ -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 @@
|
|
|
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":"AAAA;;;;;;;;GAQG;AAWH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;AAC1C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,cAAc,GAAG,aAAa,GAAG,OAAO,GAAG,aAAa,CAAC;AAE/F;;;oDAGoD;AACpD,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,aAAa,GAAG,WAAW,CAAC;AAK1E,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW,CAE/D;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,IAAI,CAAC;IACjB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,yEAAyE;IACzE,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;6EACyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAiED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAI7E;AA8ID,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAExF;
|
|
1
|
+
{"version":3,"file":"issue-tracker.d.ts","sourceRoot":"","sources":["../src/issue-tracker.ts"],"names":[],"mappings":"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"}
|
package/build/issue-tracker.js
CHANGED
|
@@ -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
|
-
*
|
|
378
|
-
*
|
|
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
|
-
|
|
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();
|