@indigoai-us/hq-cloud 6.18.20-alpha.732 → 6.18.21
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/dist/cli/push-scan-exclusions.test.js +0 -12
- package/dist/cli/push-scan-exclusions.test.js.map +1 -1
- package/dist/lib/flag-company-uid.d.ts +3 -0
- package/dist/lib/flag-company-uid.d.ts.map +1 -0
- package/dist/lib/flag-company-uid.js +6 -0
- package/dist/lib/flag-company-uid.js.map +1 -0
- package/dist/sync/secret-path-policy.d.ts.map +1 -1
- package/dist/sync/secret-path-policy.js +3 -1
- package/dist/sync/secret-path-policy.js.map +1 -1
- package/dist/sync/secret-path-policy.test.js +16 -0
- package/dist/sync/secret-path-policy.test.js.map +1 -1
- package/dist/sync/targeted-upsert-exact-list.d.ts.map +1 -1
- package/dist/sync/targeted-upsert-exact-list.js +3 -1
- package/dist/sync/targeted-upsert-exact-list.js.map +1 -1
- package/dist/sync/targeted-upsert-exact-list.test.js +16 -0
- package/dist/sync/targeted-upsert-exact-list.test.js.map +1 -1
- package/dist/watch-roots.d.ts +1 -1
- package/dist/watch-roots.d.ts.map +1 -1
- package/dist/watch-roots.js +7 -17
- package/dist/watch-roots.js.map +1 -1
- package/dist/watch-roots.test.js +1 -25
- package/dist/watch-roots.test.js.map +1 -1
- package/dist/watcher.d.ts +0 -24
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +4 -37
- package/dist/watcher.js.map +1 -1
- package/dist/watcher.test.js +1 -128
- package/dist/watcher.test.js.map +1 -1
- package/package.json +1 -1
package/dist/watcher.test.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { EventEmitter } from "node:events";
|
|
3
2
|
import * as fs from "fs";
|
|
4
3
|
import * as os from "os";
|
|
5
4
|
import * as path from "path";
|
|
6
5
|
import { createHash } from "node:crypto";
|
|
7
6
|
import { monitorEventLoopDelay } from "node:perf_hooks";
|
|
8
7
|
import { watch } from "chokidar";
|
|
9
|
-
import { FakeClock, WatchPushDriver, TreeWatcher, ChokidarWatchBudget, createWatchPathFilter, toChokidarIgnored, PushEventEmitter, PUBLISH_OUTCOME_JOURNALD_CEILING_BYTES, PUBLISH_OUTCOME_SUCCESS_SAMPLE_CAP, resolveEventDebounceConfig, summarizePublishBatchOutcome, DEFAULT_EVENT_DEBOUNCE_MS, DEFAULT_EVENT_MAX_WAIT_MS, DEFAULT_EVENT_SMALL_BATCH_DEBOUNCE_MS, DEFAULT_EVENT_SMALL_BATCH_MAX_PATHS, DEFAULT_EVENT_SMALL_BATCH_MAX_BYTES, DEFAULT_PUBLISH_MIN_INTERVAL_MS, EVENT_DEBOUNCE_MS_ENV, EVENT_MAX_WAIT_MS_ENV, EVENT_SMALL_BATCH_DEBOUNCE_MS_ENV, EVENT_SMALL_BATCH_MAX_PATHS_ENV, EVENT_SMALL_BATCH_MAX_BYTES_ENV, DEFAULT_TREE_WATCHER_MAX_WATCHED_PATHS, MAX_TREE_WATCHER_MAX_WATCHED_PATHS, TREE_WATCHER_MAX_WATCHED_PATHS_ENV, resolveMaxWatchedPaths, PUBLISH_MIN_INTERVAL_MS_ENV, resolvePublishMinIntervalMs, DurablePublishedContentHashes, DURABLE_PUBLISHED_HASH_BATCH_FLUSH_MS, replayDurablePublishedContentHashRecordsForTest, startScopedRecursiveWatch,
|
|
8
|
+
import { FakeClock, WatchPushDriver, TreeWatcher, ChokidarWatchBudget, createWatchPathFilter, toChokidarIgnored, PushEventEmitter, PUBLISH_OUTCOME_JOURNALD_CEILING_BYTES, PUBLISH_OUTCOME_SUCCESS_SAMPLE_CAP, resolveEventDebounceConfig, summarizePublishBatchOutcome, DEFAULT_EVENT_DEBOUNCE_MS, DEFAULT_EVENT_MAX_WAIT_MS, DEFAULT_EVENT_SMALL_BATCH_DEBOUNCE_MS, DEFAULT_EVENT_SMALL_BATCH_MAX_PATHS, DEFAULT_EVENT_SMALL_BATCH_MAX_BYTES, DEFAULT_PUBLISH_MIN_INTERVAL_MS, EVENT_DEBOUNCE_MS_ENV, EVENT_MAX_WAIT_MS_ENV, EVENT_SMALL_BATCH_DEBOUNCE_MS_ENV, EVENT_SMALL_BATCH_MAX_PATHS_ENV, EVENT_SMALL_BATCH_MAX_BYTES_ENV, DEFAULT_TREE_WATCHER_MAX_WATCHED_PATHS, MAX_TREE_WATCHER_MAX_WATCHED_PATHS, TREE_WATCHER_MAX_WATCHED_PATHS_ENV, resolveMaxWatchedPaths, PUBLISH_MIN_INTERVAL_MS_ENV, resolvePublishMinIntervalMs, DurablePublishedContentHashes, DURABLE_PUBLISHED_HASH_BATCH_FLUSH_MS, replayDurablePublishedContentHashRecordsForTest, startScopedRecursiveWatch, selectTreeWatchBackend } from "./watcher.js";
|
|
10
9
|
import { StateStore, StateStoreLockError } from "./sync/state-store.js";
|
|
11
10
|
import { HttpPushTransport, PushScopeForbiddenError, RealtimeUnavailableError, } from "./sync/push-transport.js";
|
|
12
11
|
import { computePersonalVaultPaths } from "./personal-vault.js";
|
|
@@ -20,46 +19,6 @@ import { computePersonalVaultPaths } from "./personal-vault.js";
|
|
|
20
19
|
* serve as regression guards for the contract those stories depend on.
|
|
21
20
|
*/
|
|
22
21
|
const DEBOUNCE = 2000;
|
|
23
|
-
describe("scoped watcher resource errors", () => {
|
|
24
|
-
let root;
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "watch-resource-error-")));
|
|
27
|
-
});
|
|
28
|
-
afterEach(() => {
|
|
29
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
30
|
-
});
|
|
31
|
-
it("does not reopen a directory watch after EMFILE", () => {
|
|
32
|
-
const docs = path.join(root, "docs");
|
|
33
|
-
fs.mkdirSync(docs);
|
|
34
|
-
class FakeWatcher extends EventEmitter {
|
|
35
|
-
close() {
|
|
36
|
-
this.emit("close");
|
|
37
|
-
return this;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const handles = new Map();
|
|
41
|
-
const watchedPaths = [];
|
|
42
|
-
const backend = startScopedRecursiveWatch(root, createWatchPathFilter(root, false), () => { }, () => { }, undefined, {
|
|
43
|
-
recursiveWatches: false,
|
|
44
|
-
listChildDirs: (dir) => dir === root ? [docs] : [],
|
|
45
|
-
watchDirectory: (dir) => {
|
|
46
|
-
const watchPath = dir.toString();
|
|
47
|
-
watchedPaths.push(watchPath);
|
|
48
|
-
const handle = new FakeWatcher();
|
|
49
|
-
handles.set(watchPath, handle);
|
|
50
|
-
return handle;
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
try {
|
|
54
|
-
expect(watchedPaths.filter((dir) => dir === docs)).toHaveLength(1);
|
|
55
|
-
handles.get(docs).emit("error", Object.assign(new Error("too many open files"), { code: "EMFILE" }));
|
|
56
|
-
expect(watchedPaths.filter((dir) => dir === docs)).toHaveLength(1);
|
|
57
|
-
}
|
|
58
|
-
finally {
|
|
59
|
-
backend.close();
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
22
|
function publishedHashRecords(count) {
|
|
64
23
|
const maxPaths = Math.max(1, Math.floor(count / 2));
|
|
65
24
|
let seed = 0x14c0ffee;
|
|
@@ -995,92 +954,6 @@ describe("US-002: chokidar descent scope", () => {
|
|
|
995
954
|
}
|
|
996
955
|
});
|
|
997
956
|
});
|
|
998
|
-
describe("chokidar polling symlink boundaries", () => {
|
|
999
|
-
async function waitFor(check) {
|
|
1000
|
-
const deadline = Date.now() + 6000;
|
|
1001
|
-
while (Date.now() < deadline) {
|
|
1002
|
-
if (check())
|
|
1003
|
-
return;
|
|
1004
|
-
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
1005
|
-
}
|
|
1006
|
-
expect(check()).toBe(true);
|
|
1007
|
-
}
|
|
1008
|
-
async function waitReady(backend) {
|
|
1009
|
-
await new Promise((resolve, reject) => {
|
|
1010
|
-
if (!backend.onReady)
|
|
1011
|
-
return resolve();
|
|
1012
|
-
const timer = setTimeout(() => reject(new Error("watcher did not become ready")), 6000);
|
|
1013
|
-
backend.onReady(() => {
|
|
1014
|
-
clearTimeout(timer);
|
|
1015
|
-
resolve();
|
|
1016
|
-
});
|
|
1017
|
-
});
|
|
1018
|
-
}
|
|
1019
|
-
it("polls ordinary paths without descending or budgeting symlink targets, while reporting the link entry", async () => {
|
|
1020
|
-
const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "watch-poll-link-root-")));
|
|
1021
|
-
const external = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "watch-poll-link-target-")));
|
|
1022
|
-
const link = path.join(root, ".agents");
|
|
1023
|
-
const events = [];
|
|
1024
|
-
const budgetExceeded = vi.fn();
|
|
1025
|
-
const errors = [];
|
|
1026
|
-
try {
|
|
1027
|
-
fs.mkdirSync(path.join(external, "many", "nested", "directories", "under", "the", "alias"), { recursive: true });
|
|
1028
|
-
fs.mkdirSync(path.join(root, ".codex"), { recursive: true });
|
|
1029
|
-
fs.writeFileSync(path.join(root, ".codex", "config.toml"), "model = 'test'\n");
|
|
1030
|
-
fs.mkdirSync(path.join(root, "workspace", "agency", "scratch"), { recursive: true });
|
|
1031
|
-
fs.writeFileSync(path.join(root, "workspace", "agency", "scratch", "notes.md"), "notes\n");
|
|
1032
|
-
fs.symlinkSync(external, link, "dir");
|
|
1033
|
-
const filter = createWatchPathFilter(root, true);
|
|
1034
|
-
expect(filter(path.join(root, ".codex", "config.toml"))).toBe(true);
|
|
1035
|
-
expect(filter(path.join(root, "workspace", "agency", "scratch", "notes.md"))).toBe(true);
|
|
1036
|
-
const backend = startTreeWatch(root, filter, (absolutePath, kind) => events.push({ path: absolutePath, kind }), (error) => errors.push(error), 7, budgetExceeded, undefined, true);
|
|
1037
|
-
try {
|
|
1038
|
-
await waitReady(backend);
|
|
1039
|
-
expect(backend.mode).toBe("polling");
|
|
1040
|
-
// Root + .codex + workspace/agency/scratch; the link target costs no watches.
|
|
1041
|
-
expect(backend.watchedPathCount()).toBe(5);
|
|
1042
|
-
expect(budgetExceeded).not.toHaveBeenCalled();
|
|
1043
|
-
expect(errors).toEqual([]);
|
|
1044
|
-
fs.unlinkSync(link);
|
|
1045
|
-
await waitFor(() => events.some((event) => event.path === link && event.kind === "unlink"));
|
|
1046
|
-
fs.symlinkSync(external, link, "dir");
|
|
1047
|
-
await waitFor(() => events.some((event) => event.path === link && event.kind === "add"));
|
|
1048
|
-
expect(backend.watchedPathCount()).toBe(5);
|
|
1049
|
-
}
|
|
1050
|
-
finally {
|
|
1051
|
-
backend.close();
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
finally {
|
|
1055
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
1056
|
-
fs.rmSync(external, { recursive: true, force: true });
|
|
1057
|
-
}
|
|
1058
|
-
});
|
|
1059
|
-
it("continues watching when the supplied HQ root is itself a symlink", async () => {
|
|
1060
|
-
const realRoot = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "watch-poll-real-root-")));
|
|
1061
|
-
const parent = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "watch-poll-root-link-")));
|
|
1062
|
-
const linkedRoot = path.join(parent, "hq");
|
|
1063
|
-
const events = [];
|
|
1064
|
-
const errors = [];
|
|
1065
|
-
fs.mkdirSync(path.join(realRoot, "workspace", "agency", "scratch"), { recursive: true });
|
|
1066
|
-
fs.symlinkSync(realRoot, linkedRoot, "dir");
|
|
1067
|
-
const filter = createWatchPathFilter(linkedRoot, true);
|
|
1068
|
-
const backend = startTreeWatch(linkedRoot, filter, (absolutePath) => events.push(absolutePath), (error) => errors.push(error), 20, () => { }, undefined, true);
|
|
1069
|
-
try {
|
|
1070
|
-
await waitReady(backend);
|
|
1071
|
-
const file = path.join(linkedRoot, "workspace", "agency", "scratch", "after-ready.md");
|
|
1072
|
-
fs.writeFileSync(file, "observed\n");
|
|
1073
|
-
await waitFor(() => events.includes(file));
|
|
1074
|
-
expect(errors).toEqual([]);
|
|
1075
|
-
}
|
|
1076
|
-
finally {
|
|
1077
|
-
backend.close();
|
|
1078
|
-
fs.rmSync(linkedRoot, { recursive: true, force: true });
|
|
1079
|
-
fs.rmSync(parent, { recursive: true, force: true });
|
|
1080
|
-
fs.rmSync(realRoot, { recursive: true, force: true });
|
|
1081
|
-
}
|
|
1082
|
-
});
|
|
1083
|
-
});
|
|
1084
957
|
describe("US-002: TreeWatcher — debounce coalesce (FakeClock seam)", () => {
|
|
1085
958
|
function makeWatcher(opts) {
|
|
1086
959
|
const clock = new FakeClock();
|