tapline-host 1.6.2 → 1.7.0

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 (108) hide show
  1. package/dist/accounts.d.ts +129 -12
  2. package/dist/accounts.js +844 -75
  3. package/dist/accounts.js.map +1 -1
  4. package/dist/actionlog.d.ts +11 -4
  5. package/dist/actionlog.js +22 -1
  6. package/dist/actionlog.js.map +1 -1
  7. package/dist/animations.d.ts +4 -2
  8. package/dist/animations.js +7 -7
  9. package/dist/animations.js.map +1 -1
  10. package/dist/api.d.ts +7 -1
  11. package/dist/api.js +12 -1
  12. package/dist/api.js.map +1 -1
  13. package/dist/audit.d.ts +1 -0
  14. package/dist/auditlog.d.ts +40 -0
  15. package/dist/auditlog.js +150 -0
  16. package/dist/auditlog.js.map +1 -0
  17. package/dist/cli.d.ts +8 -0
  18. package/dist/cli.js +143 -7
  19. package/dist/cli.js.map +1 -1
  20. package/dist/control.d.ts +51 -0
  21. package/dist/control.js +110 -0
  22. package/dist/control.js.map +1 -1
  23. package/dist/doctor.d.ts +6 -0
  24. package/dist/doctor.js +61 -4
  25. package/dist/doctor.js.map +1 -1
  26. package/dist/drive.d.ts +5 -2
  27. package/dist/drive.js +50 -13
  28. package/dist/drive.js.map +1 -1
  29. package/dist/elicit.d.ts +47 -0
  30. package/dist/elicit.js +87 -0
  31. package/dist/elicit.js.map +1 -1
  32. package/dist/format.d.ts +6 -0
  33. package/dist/format.js +25 -4
  34. package/dist/format.js.map +1 -1
  35. package/dist/grants.d.ts +297 -0
  36. package/dist/grants.js +938 -0
  37. package/dist/grants.js.map +1 -0
  38. package/dist/grantscmd.d.ts +34 -0
  39. package/dist/grantscmd.js +100 -0
  40. package/dist/grantscmd.js.map +1 -0
  41. package/dist/hostfacts.d.ts +23 -0
  42. package/dist/hostfacts.js +65 -0
  43. package/dist/hostfacts.js.map +1 -0
  44. package/dist/inspect.d.ts +3 -2
  45. package/dist/inspect.js +20 -8
  46. package/dist/inspect.js.map +1 -1
  47. package/dist/mapcmd.d.ts +2 -2
  48. package/dist/mcp.js +1 -1
  49. package/dist/nochange.d.ts +1 -0
  50. package/dist/otpclient.d.ts +79 -0
  51. package/dist/otpclient.js +362 -0
  52. package/dist/otpclient.js.map +1 -0
  53. package/dist/pidlock.d.ts +99 -0
  54. package/dist/pidlock.js +382 -0
  55. package/dist/pidlock.js.map +1 -0
  56. package/dist/places.d.ts +11 -0
  57. package/dist/places.js +28 -2
  58. package/dist/places.js.map +1 -1
  59. package/dist/policy.d.ts +2 -1
  60. package/dist/policy.js +5 -2
  61. package/dist/policy.js.map +1 -1
  62. package/dist/protocol.d.ts +4 -0
  63. package/dist/protocol.js +2 -0
  64. package/dist/protocol.js.map +1 -1
  65. package/dist/report.d.ts +8 -0
  66. package/dist/report.js +34 -1
  67. package/dist/report.js.map +1 -1
  68. package/dist/routes.d.ts +1 -1
  69. package/dist/routes.js +27 -11
  70. package/dist/routes.js.map +1 -1
  71. package/dist/runschedule.d.ts +119 -0
  72. package/dist/runschedule.js +281 -0
  73. package/dist/runschedule.js.map +1 -0
  74. package/dist/runtime.d.ts +48 -1
  75. package/dist/runtime.js +214 -18
  76. package/dist/runtime.js.map +1 -1
  77. package/dist/schedule.d.ts +145 -0
  78. package/dist/schedule.js +401 -0
  79. package/dist/schedule.js.map +1 -0
  80. package/dist/schedulehost.d.ts +73 -0
  81. package/dist/schedulehost.js +391 -0
  82. package/dist/schedulehost.js.map +1 -0
  83. package/dist/script.d.ts +2 -0
  84. package/dist/script.js +2 -0
  85. package/dist/script.js.map +1 -1
  86. package/dist/server.d.ts +6 -0
  87. package/dist/server.js +3 -1
  88. package/dist/server.js.map +1 -1
  89. package/dist/thincall.d.ts +13 -0
  90. package/dist/thincall.js +139 -59
  91. package/dist/thincall.js.map +1 -1
  92. package/dist/tool-text-data.d.ts +1 -1
  93. package/dist/tool-text-data.js +1 -1
  94. package/dist/tool-text-data.js.map +1 -1
  95. package/dist/tool-text.d.ts +1 -1
  96. package/dist/tools.d.ts +116 -6
  97. package/dist/tools.js +758 -134
  98. package/dist/tools.js.map +1 -1
  99. package/dist/unlockcmd.d.ts +44 -0
  100. package/dist/unlockcmd.js +80 -0
  101. package/dist/unlockcmd.js.map +1 -0
  102. package/dist/uxcheck.d.ts +1 -0
  103. package/dist/vault.d.ts +75 -0
  104. package/dist/vault.js +395 -0
  105. package/dist/vault.js.map +1 -0
  106. package/package.json +1 -1
  107. package/skills/tapline/SKILL.md +34 -6
  108. package/skills/tapline/references/setup.md +11 -1
@@ -0,0 +1,382 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { randomBytes } from "node:crypto";
3
+ import { closeSync, linkSync, openSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
4
+ function parseHolder(text) {
5
+ try {
6
+ const parsed = JSON.parse(text);
7
+ return typeof parsed === "object" && parsed !== null ? parsed : {};
8
+ }
9
+ catch {
10
+ return {};
11
+ }
12
+ }
13
+ const runProgram = (file, args) => execFileSync(file, args, { encoding: "utf8", timeout: 5000, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] });
14
+ /**
15
+ * When a process started, as text that is the same each time it is asked for the same process; null when it can't be told. A lock
16
+ * keeps it beside the process id, so a process id that was reused by another program is not mistaken for the holder. Windows asks
17
+ * PowerShell (`Get-Process -Id N`, about half a second, asked only for a lock's own holder and when a lock is found), elsewhere `ps`.
18
+ */
19
+ export function processStartTime(pid, platform = process.platform, run = runProgram) {
20
+ if (!Number.isInteger(pid) || pid <= 0)
21
+ return null;
22
+ try {
23
+ const out = platform === "win32"
24
+ ? run("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", `(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToUniversalTime().ToString('o')`])
25
+ : run("ps", ["-o", "lstart=", "-p", String(pid)]);
26
+ const text = out.trim();
27
+ return text === "" ? null : text;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ /** Whether a process runs (signal 0); a process we may not signal still runs. */
34
+ export function processAlive(pid) {
35
+ try {
36
+ process.kill(pid, 0);
37
+ return true;
38
+ }
39
+ catch (error) {
40
+ return error.code === "EPERM";
41
+ }
42
+ }
43
+ let ownStart;
44
+ /** The deps of this process for a lock of its own (this process's start time is asked once and kept). */
45
+ export function ownLockDeps() {
46
+ return {
47
+ pid: process.pid,
48
+ alive: processAlive,
49
+ startOf: (pid) => {
50
+ if (pid !== process.pid)
51
+ return processStartTime(pid);
52
+ if (ownStart === undefined)
53
+ ownStart = processStartTime(pid);
54
+ return ownStart;
55
+ },
56
+ };
57
+ }
58
+ /** Whether the holder a lock names is provably gone: its process doesn't run, or the process that has that id started at another time. */
59
+ function holderIsDead(deps, holder) {
60
+ if (typeof holder.pid !== "number" || !Number.isInteger(holder.pid))
61
+ return false;
62
+ if (!deps.alive(holder.pid))
63
+ return true;
64
+ if (typeof holder.started === "string" && deps.startOf !== undefined) {
65
+ const now = deps.startOf(holder.pid);
66
+ return now !== null && now !== holder.started;
67
+ }
68
+ return false;
69
+ }
70
+ /** A lock's text is a leftover only when it names a holder that is provably dead. Empty, cut-short or garbage text never is (no age rule). */
71
+ function isLeftover(deps, text) {
72
+ const holder = parseHolder(text);
73
+ return typeof holder.pid === "number" && typeof holder.owner === "string" && holderIsDead(deps, holder);
74
+ }
75
+ function readText(path) {
76
+ try {
77
+ return readFileSync(path, "utf8");
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ }
83
+ const codeOf = (error) => error.code;
84
+ /** Errors that mean this file system can't hard-link (so the fallback is used), as opposed to "the name is taken". */
85
+ const NO_LINK = new Set(["EPERM", "ENOSYS", "EXDEV", "ENOTSUP", "EOPNOTSUPP", "EMLINK", "EACCES"]);
86
+ /**
87
+ * Creates `path` with `text`, whole, only if it doesn't exist: "published", or "exists" (someone's file stands there), or "error".
88
+ * The text is written to a unique temp file first and hard-linked into place, so `path` is never seen empty.
89
+ */
90
+ export function publishNew(deps, path, text) {
91
+ const temp = `${path}.${randomBytes(6).toString("hex")}.pub`;
92
+ try {
93
+ writeFileSync(temp, text, { flag: "wx", mode: 0o600 });
94
+ }
95
+ catch {
96
+ return "error";
97
+ }
98
+ try {
99
+ deps.beforePublish?.(path);
100
+ try {
101
+ (deps.link ?? linkSync)(temp, path);
102
+ return "published";
103
+ }
104
+ catch (error) {
105
+ const code = codeOf(error);
106
+ if (code === "EEXIST")
107
+ return "exists";
108
+ if (code === undefined || !NO_LINK.has(code))
109
+ return "error";
110
+ }
111
+ // No hard links here: an exclusive create, then the content. Readers treat what can't be read as a holder as a writer in progress.
112
+ let fd;
113
+ try {
114
+ fd = openSync(path, "wx", 0o600);
115
+ }
116
+ catch (error) {
117
+ return codeOf(error) === "EEXIST" ? "exists" : "error";
118
+ }
119
+ try {
120
+ deps.afterCreate?.(path);
121
+ writeSync(fd, text);
122
+ return "published";
123
+ }
124
+ catch {
125
+ return "error";
126
+ }
127
+ finally {
128
+ closeSync(fd);
129
+ }
130
+ }
131
+ finally {
132
+ rmSync(temp, { force: true });
133
+ }
134
+ }
135
+ /** A unique name for a file moved aside: only the one who moved it ever touches it. */
136
+ function tombstone(path) {
137
+ return `${path}.${randomBytes(6).toString("hex")}.tomb`;
138
+ }
139
+ /**
140
+ * Removes the file at `path` only when it still holds `seen`: it is moved to a name of its own (one move, so only one remover gets
141
+ * it), and what was moved is checked; a file that changed hands in between is put back, never deleted.
142
+ */
143
+ function removeIfUnchanged(deps, path, seen) {
144
+ const tomb = tombstone(path);
145
+ try {
146
+ renameSync(path, tomb);
147
+ }
148
+ catch {
149
+ return false;
150
+ }
151
+ try {
152
+ const moved = readFileSync(tomb, "utf8");
153
+ if (moved === seen)
154
+ return true;
155
+ publishNew(deps, path, moved);
156
+ }
157
+ catch {
158
+ // put back by someone else already, or unreadable: the next round decides
159
+ }
160
+ finally {
161
+ rmSync(tomb, { force: true });
162
+ }
163
+ return false;
164
+ }
165
+ /**
166
+ * Takes the lock at `path` (its folder must exist): the owner token, or null when a live holder has it. A live holder is never
167
+ * displaced, however long it takes. A leftover (holder provably dead) is taken over under `<path>.takeover`, published the same way:
168
+ * under it the lock is read again, and only if it is unchanged and its holder is still dead is it deleted and replaced by the taker's.
169
+ * A `.takeover` whose own process is dead is cleared the same way.
170
+ */
171
+ export function takePidLock(deps, path) {
172
+ const takeoverPath = `${path}.takeover`;
173
+ const token = `${randomBytes(8).toString("hex")}-${deps.pid}`;
174
+ const mine = `${JSON.stringify({ owner: token, pid: deps.pid, started: deps.startOf?.(deps.pid) ?? null })}\n`;
175
+ for (let attempt = 0; attempt < 6; attempt++) {
176
+ // Acquisition honours `.takeover`: while a takeover or an unlock holds it (a live holder), nobody creates the lock.
177
+ const gate = readText(takeoverPath);
178
+ if (gate !== null && typeof parseHolder(gate).pid === "number" && !isLeftover(deps, gate))
179
+ return null;
180
+ const first = publishNew(deps, path, mine);
181
+ if (first === "published")
182
+ return token;
183
+ if (first === "error")
184
+ return null;
185
+ const seen = readText(path);
186
+ if (seen === null)
187
+ continue; // released between our create and our read: try to create again
188
+ if (!isLeftover(deps, seen))
189
+ return null;
190
+ deps.beforeReclaim?.();
191
+ // Under .takeover only one contender at a time looks at a leftover.
192
+ const claimed = publishNew(deps, takeoverPath, mine);
193
+ if (claimed === "error")
194
+ return null;
195
+ if (claimed === "exists") {
196
+ const other = readText(takeoverPath);
197
+ // Someone else is taking it over now (or was, and died): a dead taker's .takeover is cleared, a live one's is waited out.
198
+ if (other !== null && isLeftover(deps, other))
199
+ removeIfUnchanged(deps, takeoverPath, other);
200
+ continue;
201
+ }
202
+ try {
203
+ const now = readText(path);
204
+ if (now === seen && isLeftover(deps, now)) {
205
+ try {
206
+ unlinkSync(path);
207
+ }
208
+ catch {
209
+ continue;
210
+ }
211
+ if (publishNew(deps, path, mine) === "published")
212
+ return token;
213
+ continue; // a run that came in first holds it now
214
+ }
215
+ }
216
+ finally {
217
+ // only our own .takeover is removed
218
+ const held = readText(takeoverPath);
219
+ if (held === mine)
220
+ removeIfUnchanged(deps, takeoverPath, mine);
221
+ }
222
+ }
223
+ return null;
224
+ }
225
+ /** Releases the lock only while its content is still the holder's own (`token`); another's lock is never removed. */
226
+ export function dropPidLock(path, token) {
227
+ const text = readText(path);
228
+ if (text === null || parseHolder(text).owner !== token)
229
+ return;
230
+ try {
231
+ unlinkSync(path);
232
+ }
233
+ catch {
234
+ // already gone
235
+ }
236
+ }
237
+ /** Whether the lock's holder is `token` right now (for a holder that wants to know it still has it). */
238
+ export function holdsPidLock(path, token) {
239
+ const text = readText(path);
240
+ return text !== null && parseHolder(text).owner === token;
241
+ }
242
+ /** Judges the exact bytes of a lock file (a snapshot): the holder is looked at in THIS text, never in a later read of the file. */
243
+ function judgeText(deps, text) {
244
+ if (text.trim() === "")
245
+ return { state: "stuck", why: "empty" };
246
+ const holder = parseHolder(text);
247
+ if (typeof holder.pid !== "number" || !Number.isInteger(holder.pid) || typeof holder.owner !== "string")
248
+ return { state: "stuck", why: "unreadable" };
249
+ return holderIsDead(deps, holder) ? { state: "stuck", why: "dead", pid: holder.pid } : { state: "live", pid: holder.pid };
250
+ }
251
+ function snapshotOf(path) {
252
+ try {
253
+ return { kind: "text", text: readFileSync(path, "utf8") };
254
+ }
255
+ catch (error) {
256
+ return codeOf(error) === "ENOENT" ? { kind: "absent" } : { kind: "unreadable" };
257
+ }
258
+ }
259
+ function judgeSnapshot(deps, snap) {
260
+ if (snap.kind === "absent")
261
+ return { state: "absent" };
262
+ return snap.kind === "unreadable" ? { state: "stuck", why: "unreadable" } : judgeText(deps, snap.text);
263
+ }
264
+ /** Looks at the lock at `path` without changing it. */
265
+ export function inspectPidLock(deps, path) {
266
+ return judgeSnapshot(deps, snapshotOf(path));
267
+ }
268
+ /** The words for a stuck lock's cause. */
269
+ export function stuckWords(state) {
270
+ if (state.why === "empty")
271
+ return "empty";
272
+ if (state.why === "unreadable")
273
+ return "unreadable";
274
+ return `held by a process that is gone (pid ${state.pid ?? "?"})`;
275
+ }
276
+ /**
277
+ * Removes the file at `path` that was judged stuck from `snap`, only if it still is what was judged: it is moved to a name of its
278
+ * own, and what was moved is compared with the snapshot (an unreadable snapshot is judged again on what was moved). A file that
279
+ * turns out to be another, live holder's is linked back and never deleted. Answers `removed`, `live` (with the pid of the holder
280
+ * put back) or `failed`.
281
+ */
282
+ function removeJudged(deps, path, snap) {
283
+ if (snap.kind === "absent")
284
+ return "removed";
285
+ const tomb = tombstone(path);
286
+ try {
287
+ renameSync(path, tomb);
288
+ }
289
+ catch {
290
+ return "failed";
291
+ }
292
+ const moved = snapshotOf(tomb);
293
+ const same = snap.kind === "text" ? moved.kind === "text" && moved.text === snap.text : judgeSnapshot(deps, moved).state !== "live";
294
+ if (same) {
295
+ try {
296
+ rmSync(tomb, { force: true });
297
+ return "removed";
298
+ }
299
+ catch {
300
+ // can't be deleted (a folder, say): it is put back where it was
301
+ }
302
+ }
303
+ const state = judgeSnapshot(deps, moved);
304
+ const live = state.state === "live" ? { live: state.pid } : "failed";
305
+ if (moved.kind !== "text") {
306
+ try {
307
+ renameSync(tomb, path);
308
+ }
309
+ catch {
310
+ // the name was taken meanwhile: what was moved stays under its tombstone for a person to look at
311
+ }
312
+ return live;
313
+ }
314
+ // Link it back (published whole); a live holder is never unlinked. If the name was taken meanwhile, the tombstone stays for a person.
315
+ if (publishNew(deps, path, moved.text) === "published")
316
+ rmSync(tomb, { force: true });
317
+ return live;
318
+ }
319
+ /**
320
+ * Removes the lock at `path` and its `.takeover`, but only when no holder is proven alive: an empty or unreadable file, or one whose
321
+ * holder is dead (its process is gone, or has another start time). A live holder in either file refuses and removes nothing.
322
+ *
323
+ * It runs under the lock's own `.takeover` (published whole, as a takeover is), so it never overlaps a takeover, and acquisition
324
+ * honours `.takeover` too. Under it the exact bytes of the lock are read once, THAT snapshot's holder is judged, and the file is
325
+ * removed only if it still holds exactly those bytes (moved to a tombstone and compared; a different file is linked back).
326
+ * A `.takeover` that is itself stuck is cleared the same way first.
327
+ */
328
+ export function unlockPidLock(deps, path) {
329
+ const takeoverPath = `${path}.takeover`;
330
+ const mine = `${JSON.stringify({ owner: `${randomBytes(8).toString("hex")}-${deps.pid}`, pid: deps.pid, started: deps.startOf?.(deps.pid) ?? null })}\n`;
331
+ const removed = [];
332
+ const failed = (file) => ({ status: "failed", removed, path: file });
333
+ let held = false;
334
+ for (let attempt = 0; attempt < 6 && !held; attempt++) {
335
+ const got = publishNew(deps, takeoverPath, mine);
336
+ if (got === "published") {
337
+ held = true;
338
+ break;
339
+ }
340
+ if (got === "error")
341
+ return failed(takeoverPath);
342
+ const snap = snapshotOf(takeoverPath);
343
+ const state = judgeSnapshot(deps, snap);
344
+ if (state.state === "live")
345
+ return { status: "live", pid: state.pid, removed, path: takeoverPath };
346
+ if (state.state === "absent")
347
+ continue;
348
+ deps.beforeRemove?.(takeoverPath);
349
+ const outcome = removeJudged(deps, takeoverPath, snap);
350
+ if (outcome === "removed")
351
+ removed.push({ path: takeoverPath, why: stuckWords(state) });
352
+ else if (outcome === "failed")
353
+ return failed(takeoverPath);
354
+ else
355
+ return { status: "live", pid: outcome.live, removed, path: takeoverPath };
356
+ }
357
+ if (!held)
358
+ return failed(takeoverPath);
359
+ try {
360
+ const snap = snapshotOf(path);
361
+ const state = judgeSnapshot(deps, snap);
362
+ if (state.state === "live")
363
+ return { status: "live", pid: state.pid, removed, path };
364
+ if (state.state === "absent")
365
+ return removed.length === 0 ? { status: "none", removed } : { status: "removed", removed };
366
+ deps.beforeRemove?.(path);
367
+ const outcome = removeJudged(deps, path, snap);
368
+ if (outcome === "removed")
369
+ removed.push({ path, why: stuckWords(state) });
370
+ else if (outcome === "failed")
371
+ return failed(path);
372
+ else
373
+ return { status: "live", pid: outcome.live, removed, path };
374
+ return { status: "removed", removed };
375
+ }
376
+ finally {
377
+ // only our own .takeover is released
378
+ if (readText(takeoverPath) === mine)
379
+ removeIfUnchanged(deps, takeoverPath, mine);
380
+ }
381
+ }
382
+ //# sourceMappingURL=pidlock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pidlock.js","sourceRoot":"","sources":["../src/pidlock.ts"],"names":[],"mappings":"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"}
package/dist/places.d.ts CHANGED
@@ -114,6 +114,8 @@ export declare class AppMap {
114
114
  private known;
115
115
  private knownFor;
116
116
  private dirty;
117
+ /** Set by `discard`: this copy was dropped for a fresh read of the file and never writes again. */
118
+ private dead;
117
119
  private version;
118
120
  private timer;
119
121
  private saving;
@@ -188,6 +190,13 @@ export declare class AppMap {
188
190
  private schedule;
189
191
  /** Writes what changed now (the close, and tests). A failed write stays dirty and is tried again by the next flush. */
190
192
  flush(): Promise<void>;
193
+ /** How the file loaded: "ok", "new" (no file) or "unreadable". */
194
+ loadedStatus(): "ok" | "new" | "unreadable";
195
+ /**
196
+ * Drops this copy without writing it: what it learned and hadn't saved is let go, and it never saves again, so a file a person has
197
+ * edited can't be written over (or a deleted reflex brought back) by a stale copy. A save already under way is waited for.
198
+ */
199
+ discard(): Promise<void>;
191
200
  private write;
192
201
  /** The merged file is the map from now on: another tool's work, and a name a clash changed, come with it. */
193
202
  private adopt;
@@ -207,6 +216,8 @@ export declare class MapRegistry {
207
216
  /** The app's map; none for an app that has no id of its own. */
208
217
  forApp(app: MapApp): AppMap | undefined;
209
218
  flushAll(): Promise<void>;
219
+ /** Lets go of every map held in memory unsaved; the next `forApp` reads the file again. */
220
+ reload(): Promise<void>;
210
221
  }
211
222
  export interface PlaceSource {
212
223
  capabilities: string[];
package/dist/places.js CHANGED
@@ -289,6 +289,8 @@ export class AppMap {
289
289
  known;
290
290
  knownFor;
291
291
  dirty = false;
292
+ /** Set by `discard`: this copy was dropped for a fresh read of the file and never writes again. */
293
+ dead = false;
292
294
  version = 0;
293
295
  timer;
294
296
  saving;
@@ -639,7 +641,7 @@ export class AppMap {
639
641
  this.schedule();
640
642
  }
641
643
  schedule() {
642
- if (this.readOnly || this.timer !== undefined || this.saving !== undefined)
644
+ if (this.dead || this.readOnly || this.timer !== undefined || this.saving !== undefined)
643
645
  return;
644
646
  const wait = Math.max(0, this.lastWriteAt + this.gapMs - this.clock());
645
647
  this.timer = setTimeout(() => {
@@ -658,9 +660,27 @@ export class AppMap {
658
660
  return;
659
661
  while (this.saving !== undefined)
660
662
  await this.saving;
661
- if (this.dirty)
663
+ if (this.dirty && !this.dead)
662
664
  await this.write();
663
665
  }
666
+ /** How the file loaded: "ok", "new" (no file) or "unreadable". */
667
+ loadedStatus() {
668
+ return this.loadStatus;
669
+ }
670
+ /**
671
+ * Drops this copy without writing it: what it learned and hadn't saved is let go, and it never saves again, so a file a person has
672
+ * edited can't be written over (or a deleted reflex brought back) by a stale copy. A save already under way is waited for.
673
+ */
674
+ async discard() {
675
+ this.dead = true;
676
+ if (this.timer !== undefined) {
677
+ clearTimeout(this.timer);
678
+ this.timer = undefined;
679
+ }
680
+ while (this.saving !== undefined)
681
+ await this.saving;
682
+ this.dirty = false;
683
+ }
664
684
  write() {
665
685
  if (this.saving !== undefined)
666
686
  return this.saving;
@@ -767,6 +787,12 @@ export class MapRegistry {
767
787
  async flushAll() {
768
788
  await Promise.all([...this.maps.values()].map((map) => map.flush()));
769
789
  }
790
+ /** Lets go of every map held in memory unsaved; the next `forApp` reads the file again. */
791
+ async reload() {
792
+ const held = [...this.maps.values()];
793
+ this.maps.clear();
794
+ await Promise.all(held.map((map) => map.discard()));
795
+ }
770
796
  }
771
797
  /** Where the app was before a move: the host's latest `place` event when it names a route, else the last place seen. */
772
798
  export function placeBefore(source, map) {