@indigoai-us/hq-cloud 6.15.30 → 6.15.31

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 (119) hide show
  1. package/dist/bin/sync-runner-company.d.ts.map +1 -1
  2. package/dist/bin/sync-runner-company.js +24 -13
  3. package/dist/bin/sync-runner-company.js.map +1 -1
  4. package/dist/bin/sync-runner-company.test.js +0 -71
  5. package/dist/bin/sync-runner-company.test.js.map +1 -1
  6. package/dist/bin/sync-runner-watch-loop.d.ts +0 -10
  7. package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
  8. package/dist/bin/sync-runner-watch-loop.js +13 -170
  9. package/dist/bin/sync-runner-watch-loop.js.map +1 -1
  10. package/dist/bin/sync-runner-watch-routes.d.ts +1 -16
  11. package/dist/bin/sync-runner-watch-routes.d.ts.map +1 -1
  12. package/dist/bin/sync-runner-watch-routes.js +2 -40
  13. package/dist/bin/sync-runner-watch-routes.js.map +1 -1
  14. package/dist/bin/sync-runner-watch-routes.test.js +1 -53
  15. package/dist/bin/sync-runner-watch-routes.test.js.map +1 -1
  16. package/dist/bin/sync-runner.d.ts +3 -15
  17. package/dist/bin/sync-runner.d.ts.map +1 -1
  18. package/dist/bin/sync-runner.js +13 -66
  19. package/dist/bin/sync-runner.js.map +1 -1
  20. package/dist/bin/sync-runner.test.js +13 -433
  21. package/dist/bin/sync-runner.test.js.map +1 -1
  22. package/dist/cli/conflict.d.ts +2 -25
  23. package/dist/cli/conflict.d.ts.map +1 -1
  24. package/dist/cli/conflict.js +4 -29
  25. package/dist/cli/conflict.js.map +1 -1
  26. package/dist/cli/share.d.ts +4 -40
  27. package/dist/cli/share.d.ts.map +1 -1
  28. package/dist/cli/share.js +86 -478
  29. package/dist/cli/share.js.map +1 -1
  30. package/dist/cli/share.test.js +150 -845
  31. package/dist/cli/share.test.js.map +1 -1
  32. package/dist/cli/sync-scope.test.js +18 -147
  33. package/dist/cli/sync-scope.test.js.map +1 -1
  34. package/dist/cli/sync.d.ts +0 -20
  35. package/dist/cli/sync.d.ts.map +1 -1
  36. package/dist/cli/sync.js +29 -261
  37. package/dist/cli/sync.js.map +1 -1
  38. package/dist/cli/sync.test.js +90 -519
  39. package/dist/cli/sync.test.js.map +1 -1
  40. package/dist/journal.d.ts +0 -1
  41. package/dist/journal.d.ts.map +1 -1
  42. package/dist/journal.js +25 -155
  43. package/dist/journal.js.map +1 -1
  44. package/dist/journal.test.js +11 -29
  45. package/dist/journal.test.js.map +1 -1
  46. package/dist/object-io.d.ts +13 -34
  47. package/dist/object-io.d.ts.map +1 -1
  48. package/dist/object-io.js +29 -154
  49. package/dist/object-io.js.map +1 -1
  50. package/dist/outcome-telemetry.d.ts +1 -7
  51. package/dist/outcome-telemetry.d.ts.map +1 -1
  52. package/dist/outcome-telemetry.js +9 -15
  53. package/dist/outcome-telemetry.js.map +1 -1
  54. package/dist/outcome-telemetry.test.js +0 -15
  55. package/dist/outcome-telemetry.test.js.map +1 -1
  56. package/dist/outposts/client.d.ts +2 -2
  57. package/dist/outposts/client.d.ts.map +1 -1
  58. package/dist/outposts/client.js +3 -4
  59. package/dist/outposts/client.js.map +1 -1
  60. package/dist/outposts/command.d.ts.map +1 -1
  61. package/dist/outposts/command.js +6 -9
  62. package/dist/outposts/command.js.map +1 -1
  63. package/dist/outposts/command.test.js +2 -59
  64. package/dist/outposts/command.test.js.map +1 -1
  65. package/dist/outposts/remote-command.d.ts +8 -8
  66. package/dist/outposts/remote-command.d.ts.map +1 -1
  67. package/dist/outposts/remote-command.js +8 -10
  68. package/dist/outposts/remote-command.js.map +1 -1
  69. package/dist/prefix-coalesce.d.ts +0 -14
  70. package/dist/prefix-coalesce.d.ts.map +1 -1
  71. package/dist/prefix-coalesce.js +0 -29
  72. package/dist/prefix-coalesce.js.map +1 -1
  73. package/dist/prefix-coalesce.test.js +1 -22
  74. package/dist/prefix-coalesce.test.js.map +1 -1
  75. package/dist/skill-telemetry.d.ts +1 -6
  76. package/dist/skill-telemetry.d.ts.map +1 -1
  77. package/dist/skill-telemetry.js +8 -14
  78. package/dist/skill-telemetry.js.map +1 -1
  79. package/dist/skill-telemetry.test.js +0 -43
  80. package/dist/skill-telemetry.test.js.map +1 -1
  81. package/dist/sts-credential-refresh.test.js +2 -87
  82. package/dist/sts-credential-refresh.test.js.map +1 -1
  83. package/dist/sync/state-store.d.ts.map +1 -1
  84. package/dist/sync/state-store.js +1 -20
  85. package/dist/sync/state-store.js.map +1 -1
  86. package/dist/sync/state-store.test.js +0 -64
  87. package/dist/sync/state-store.test.js.map +1 -1
  88. package/dist/sync-core.d.ts.map +1 -1
  89. package/dist/sync-core.js +2 -7
  90. package/dist/sync-core.js.map +1 -1
  91. package/dist/sync-core.test.js +0 -36
  92. package/dist/sync-core.test.js.map +1 -1
  93. package/dist/telemetry.d.ts +6 -30
  94. package/dist/telemetry.d.ts.map +1 -1
  95. package/dist/telemetry.js +135 -331
  96. package/dist/telemetry.js.map +1 -1
  97. package/dist/telemetry.test.js +0 -403
  98. package/dist/telemetry.test.js.map +1 -1
  99. package/dist/types.d.ts +3 -26
  100. package/dist/types.d.ts.map +1 -1
  101. package/dist/watcher.d.ts +0 -76
  102. package/dist/watcher.d.ts.map +1 -1
  103. package/dist/watcher.js +3 -105
  104. package/dist/watcher.js.map +1 -1
  105. package/dist/watcher.test.js +1 -165
  106. package/dist/watcher.test.js.map +1 -1
  107. package/package.json +1 -1
  108. package/dist/bandwidth.d.ts +0 -128
  109. package/dist/bandwidth.d.ts.map +0 -1
  110. package/dist/bandwidth.js +0 -254
  111. package/dist/bandwidth.js.map +0 -1
  112. package/dist/bandwidth.test.d.ts +0 -2
  113. package/dist/bandwidth.test.d.ts.map +0 -1
  114. package/dist/bandwidth.test.js +0 -243
  115. package/dist/bandwidth.test.js.map +0 -1
  116. package/dist/journal-delta-writes.test.d.ts +0 -2
  117. package/dist/journal-delta-writes.test.d.ts.map +0 -1
  118. package/dist/journal-delta-writes.test.js +0 -140
  119. package/dist/journal-delta-writes.test.js.map +0 -1
@@ -12,7 +12,6 @@ import * as os from "os";
12
12
  import * as path from "path";
13
13
  import { runRunner, runRunnerWithLoop, resolveDeletePolicy, resolveSkipPersonal, resolveSkipCompanies, selectObjectIOFactory, routeChangeToTarget, buildTargetedPushArgv, resolvePullScope, readPinnedPrefixes, SESSIONS_SCOPE_PREFIX, defaultCollectTelemetry, AUTH_REQUIRED_PASS_EXIT, } from "./sync-runner.js";
14
14
  import { PresignObjectIO, S3SdkObjectIO } from "../object-io.js";
15
- import { setBandwidthGovernorForTesting } from "../bandwidth.js";
16
15
  import { FakeClock, } from "../watcher.js";
17
16
  import { adaptivePollMs, advanceMonotonicDeadline, journalEntriesForWatcherDelete, shouldQuarantineWatcherDeleteIntents, } from "./sync-runner-watch-loop.js";
18
17
  import { PERSONAL_VAULT_JOURNAL_SLUG, readJournal, writeJournal, } from "../journal.js";
@@ -216,63 +215,6 @@ describe("argv parsing", () => {
216
215
  });
217
216
  });
218
217
  // ---------------------------------------------------------------------------
219
- // bandwidth governor startup line
220
- // ---------------------------------------------------------------------------
221
- describe("bandwidth governor startup line", () => {
222
- const ENV_KEYS = [
223
- "HQ_SYNC_MAX_BYTES_PER_SEC",
224
- "HQ_SYNC_MAX_CONCURRENCY",
225
- "HQ_SYNC_BANDWIDTH_PERCENT",
226
- ];
227
- let saved;
228
- beforeEach(() => {
229
- saved = Object.fromEntries(ENV_KEYS.map((k) => [k, process.env[k]]));
230
- for (const k of ENV_KEYS)
231
- delete process.env[k];
232
- setBandwidthGovernorForTesting(null); // re-read env per test
233
- });
234
- afterEach(() => {
235
- for (const k of ENV_KEYS) {
236
- if (saved[k] === undefined)
237
- delete process.env[k];
238
- else
239
- process.env[k] = saved[k];
240
- }
241
- setBandwidthGovernorForTesting(null);
242
- });
243
- it("states the effective policy on stderr when the env vars are set", async () => {
244
- process.env.HQ_SYNC_MAX_BYTES_PER_SEC = "500000";
245
- process.env.HQ_SYNC_MAX_CONCURRENCY = "2";
246
- const deps = makeDeps({
247
- createVaultClient: () => makeVaultStub({ memberships: [] }),
248
- });
249
- const code = await runRunner(["--companies"], deps);
250
- expect(code).toBe(0);
251
- expect(deps.stderr.events()).toContainEqual({
252
- type: "bandwidth-policy",
253
- message: "bandwidth governor: 500000 B/s cap, concurrency 2",
254
- });
255
- });
256
- it("stays silent (exact legacy stream) when no policy is configured", async () => {
257
- const deps = makeDeps({
258
- createVaultClient: () => makeVaultStub({ memberships: [] }),
259
- });
260
- const code = await runRunner(["--companies"], deps);
261
- expect(code).toBe(0);
262
- expect(deps.stderr.events().some((e) => e.type === "bandwidth-policy")).toBe(false);
263
- });
264
- it("treats invalid env values as off (no policy line)", async () => {
265
- process.env.HQ_SYNC_MAX_BYTES_PER_SEC = "0";
266
- process.env.HQ_SYNC_BANDWIDTH_PERCENT = "101";
267
- const deps = makeDeps({
268
- createVaultClient: () => makeVaultStub({ memberships: [] }),
269
- });
270
- const code = await runRunner(["--companies"], deps);
271
- expect(code).toBe(0);
272
- expect(deps.stderr.events().some((e) => e.type === "bandwidth-policy")).toBe(false);
273
- });
274
- });
275
- // ---------------------------------------------------------------------------
276
218
  // auth
277
219
  // ---------------------------------------------------------------------------
278
220
  describe("auth", () => {
@@ -4581,18 +4523,7 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
4581
4523
  "--hq-root",
4582
4524
  "/tmp/hq",
4583
4525
  ],
4584
- // The drain pull is route-targeted AND path-scoped now: it lists only
4585
- // the touched subtree instead of running a full --companies pull.
4586
- [
4587
- "--company",
4588
- "indigo",
4589
- "--direction",
4590
- "pull",
4591
- "--scope-path",
4592
- "knowledge/a.md",
4593
- "--hq-root",
4594
- "/tmp/hq",
4595
- ],
4526
+ fullPullArgv,
4596
4527
  ]);
4597
4528
  shutdown();
4598
4529
  tick();
@@ -4609,7 +4540,7 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
4609
4540
  await flushLoopMicrotasks();
4610
4541
  const pushCalls = runPass.mock.calls
4611
4542
  .map((call) => call[0])
4612
- .filter((argv) => argv.includes("--company") && argv.includes("push"));
4543
+ .filter((argv) => argv.includes("--company"));
4613
4544
  expect(pushCalls).toEqual([
4614
4545
  [
4615
4546
  "--company",
@@ -4689,21 +4620,11 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
4689
4620
  await flushLoopMicrotasks();
4690
4621
  const calls = runPass.mock.calls.map((call) => call[0]);
4691
4622
  // No scoped push of any kind ran...
4623
+ expect(calls.some((argv) => argv.includes("--company"))).toBe(false);
4692
4624
  expect(calls.some((argv) => argv.includes("--direction") &&
4693
4625
  argv[argv.indexOf("--direction") + 1] === "push")).toBe(false);
4694
- // ...only the pull leg ran — route-targeted and path-scoped now.
4695
- expect(calls).toEqual([
4696
- [
4697
- "--company",
4698
- "indigo",
4699
- "--direction",
4700
- "pull",
4701
- "--scope-path",
4702
- "knowledge/a.md",
4703
- "--hq-root",
4704
- "/tmp/hq",
4705
- ],
4706
- ]);
4626
+ // ...only the pull leg ran.
4627
+ expect(calls).toEqual([fullPullArgv]);
4707
4628
  shutdown();
4708
4629
  tick();
4709
4630
  await loop;
@@ -4726,7 +4647,7 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
4726
4647
  await flushLoopMicrotasks();
4727
4648
  const pushCalls = runPass.mock.calls
4728
4649
  .map((call) => call[0])
4729
- .filter((argv) => argv.includes("--company") && argv.includes("push"));
4650
+ .filter((argv) => argv.includes("--company"));
4730
4651
  expect(pushCalls).toEqual([
4731
4652
  [
4732
4653
  "--company",
@@ -4793,17 +4714,7 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
4793
4714
  "--hq-root",
4794
4715
  "/tmp/hq",
4795
4716
  ],
4796
- // Path-scoped now: the personal pull leg lists only the touched
4797
- // subtree instead of re-walking the whole vault on every event batch.
4798
- [
4799
- "--personal",
4800
- "--direction",
4801
- "pull",
4802
- "--scope-path",
4803
- "knowledge/a.md",
4804
- "--hq-root",
4805
- "/tmp/hq",
4806
- ],
4717
+ ["--personal", "--direction", "pull", "--hq-root", "/tmp/hq"],
4807
4718
  ]);
4808
4719
  shutdown();
4809
4720
  tick();
@@ -4839,16 +4750,7 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
4839
4750
  "--hq-root",
4840
4751
  "/tmp/hq",
4841
4752
  ],
4842
- [
4843
- "--company",
4844
- "acme",
4845
- "--direction",
4846
- "pull",
4847
- "--scope-path",
4848
- "knowledge/a.md",
4849
- "--hq-root",
4850
- "/tmp/hq",
4851
- ],
4753
+ ["--company", "acme", "--direction", "pull", "--hq-root", "/tmp/hq"],
4852
4754
  ]);
4853
4755
  shutdown();
4854
4756
  tick();
@@ -4926,245 +4828,6 @@ describe("runRunnerWithLoop — accumulate-and-drain scoped push", () => {
4926
4828
  sleep.tick();
4927
4829
  await loop;
4928
4830
  });
4929
- it("overflow with known dropped-route hints fans out per touched route instead of a full reconcile", async () => {
4930
- const watcher = makeBatchWatcherStub();
4931
- const sleep = makeSteppableSleep();
4932
- let triggerShutdown = () => { };
4933
- const runPass = vi.fn().mockResolvedValue(completedPassOutcome());
4934
- const loop = runRunnerWithLoop(watchArgv, {
4935
- runPass,
4936
- clock: new FakeClock(),
4937
- createWatcher: () => watcher,
4938
- sleep: sleep.sleep,
4939
- onShutdownSignal: (handler) => {
4940
- triggerShutdown = handler;
4941
- return () => { };
4942
- },
4943
- });
4944
- await flushLoopMicrotasks();
4945
- runPass.mockClear();
4946
- // A burst overflowed, but every dropped path recorded route evidence:
4947
- // retained path in indigo, dropped paths in acme. The drain must run one
4948
- // whole-route pass per touched route — never the all-companies fanout.
4949
- watcher.emit("companies/indigo/a.md", {
4950
- paths: new Map([
4951
- ["/tmp/hq/companies/indigo/a.md", "companies/indigo/a.md"],
4952
- ]),
4953
- overflowed: true,
4954
- droppedPaths: 3,
4955
- droppedRouteHints: ["companies/acme/dropped.md"],
4956
- });
4957
- sleep.tick();
4958
- // Four guarded passes run sequentially — give the loop room to finish.
4959
- await flushLoopMicrotasks(40);
4960
- const calls = runPass.mock.calls.map((call) => call[0]);
4961
- expect(calls).toEqual([
4962
- // indigo: whole-route push (no --scope-path — dropped paths unknown)…
4963
- ["--company", "indigo", "--direction", "push", "--hq-root", "/tmp/hq"],
4964
- // …then the route's pull.
4965
- ["--company", "indigo", "--direction", "pull", "--hq-root", "/tmp/hq"],
4966
- ["--company", "acme", "--direction", "push", "--hq-root", "/tmp/hq"],
4967
- ["--company", "acme", "--direction", "pull", "--hq-root", "/tmp/hq"],
4968
- ]);
4969
- expect(calls).not.toContainEqual(fullArgv);
4970
- triggerShutdown();
4971
- await loop;
4972
- });
4973
- it("falls back to a full reconcile when an event batch exceeds HQ_SYNC_EVENT_BATCH_LIMIT", async () => {
4974
- const saved = process.env.HQ_SYNC_EVENT_BATCH_LIMIT;
4975
- process.env.HQ_SYNC_EVENT_BATCH_LIMIT = "2";
4976
- try {
4977
- const watcher = makeBatchWatcherStub();
4978
- const sleep = makeSteppableSleep();
4979
- let triggerShutdown = () => { };
4980
- const runPass = vi.fn().mockResolvedValue(completedPassOutcome());
4981
- const loop = runRunnerWithLoop(watchArgv, {
4982
- runPass,
4983
- clock: new FakeClock(),
4984
- createWatcher: () => watcher,
4985
- sleep: sleep.sleep,
4986
- onShutdownSignal: (handler) => {
4987
- triggerShutdown = handler;
4988
- return () => { };
4989
- },
4990
- });
4991
- await flushLoopMicrotasks();
4992
- runPass.mockClear();
4993
- watcher.emit("companies/indigo/a.md", {
4994
- paths: new Map([
4995
- ["/tmp/hq/companies/indigo/a.md", "companies/indigo/a.md"],
4996
- ["/tmp/hq/companies/indigo/b.md", "companies/indigo/b.md"],
4997
- ["/tmp/hq/companies/indigo/c.md", "companies/indigo/c.md"],
4998
- ]),
4999
- });
5000
- sleep.tick();
5001
- await flushLoopMicrotasks();
5002
- // Mass change: one full reconcile, no per-path scoped passes.
5003
- expect(runPass.mock.calls.map((call) => call[0])).toEqual([fullArgv]);
5004
- triggerShutdown();
5005
- await loop;
5006
- }
5007
- finally {
5008
- if (saved === undefined)
5009
- delete process.env.HQ_SYNC_EVENT_BATCH_LIMIT;
5010
- else
5011
- process.env.HQ_SYNC_EVENT_BATCH_LIMIT = saved;
5012
- }
5013
- });
5014
- it("a batch under the default limit stays on the targeted path", async () => {
5015
- const watcher = makeBatchWatcherStub();
5016
- const sleep = makeSteppableSleep();
5017
- let triggerShutdown = () => { };
5018
- const runPass = vi.fn().mockResolvedValue(completedPassOutcome());
5019
- const loop = runRunnerWithLoop(watchArgv, {
5020
- runPass,
5021
- clock: new FakeClock(),
5022
- createWatcher: () => watcher,
5023
- sleep: sleep.sleep,
5024
- onShutdownSignal: (handler) => {
5025
- triggerShutdown = handler;
5026
- return () => { };
5027
- },
5028
- });
5029
- await flushLoopMicrotasks();
5030
- runPass.mockClear();
5031
- watcher.emit("companies/indigo/a.md", {
5032
- paths: new Map([
5033
- ["/tmp/hq/companies/indigo/a.md", "companies/indigo/a.md"],
5034
- ["/tmp/hq/companies/indigo/b.md", "companies/indigo/b.md"],
5035
- ["/tmp/hq/companies/indigo/c.md", "companies/indigo/c.md"],
5036
- ]),
5037
- });
5038
- sleep.tick();
5039
- await flushLoopMicrotasks();
5040
- const calls = runPass.mock.calls.map((call) => call[0]);
5041
- expect(calls).not.toContainEqual(fullArgv);
5042
- expect(calls[0]).toEqual([
5043
- "--company",
5044
- "indigo",
5045
- "--direction",
5046
- "push",
5047
- "--scope-path",
5048
- "a.md",
5049
- "--scope-path",
5050
- "b.md",
5051
- "--scope-path",
5052
- "c.md",
5053
- "--hq-root",
5054
- "/tmp/hq",
5055
- ]);
5056
- triggerShutdown();
5057
- await loop;
5058
- });
5059
- it("a throwing targeted pass falls back to one full reconcile instead of dropping the change", async () => {
5060
- const runPass = vi.fn(async (argv) => {
5061
- if (argv.includes("pull") && argv.includes("--scope-path")) {
5062
- throw new Error("scoped pull exploded");
5063
- }
5064
- return completedPassOutcome();
5065
- });
5066
- const { loop, watcher, tick, shutdown } = startDrainLoop(runPass);
5067
- await flushLoopMicrotasks();
5068
- runPass.mockClear();
5069
- watcher.emit("companies/indigo/knowledge/a.md");
5070
- tick();
5071
- await flushLoopMicrotasks(40);
5072
- expect(runPass.mock.calls.map((call) => call[0])).toEqual([
5073
- [
5074
- "--company",
5075
- "indigo",
5076
- "--direction",
5077
- "push",
5078
- "--scope-path",
5079
- "knowledge/a.md",
5080
- "--hq-root",
5081
- "/tmp/hq",
5082
- ],
5083
- // The scoped pull throws…
5084
- [
5085
- "--company",
5086
- "indigo",
5087
- "--direction",
5088
- "pull",
5089
- "--scope-path",
5090
- "knowledge/a.md",
5091
- "--hq-root",
5092
- "/tmp/hq",
5093
- ],
5094
- // …and the loop degrades to the full reconcile, never dropping the tick.
5095
- fullArgv,
5096
- ]);
5097
- shutdown();
5098
- tick();
5099
- await loop;
5100
- });
5101
- it("wires the event debounce config (default 15s quiet / 120s max-wait) into the watcher factory", async () => {
5102
- const captured = [];
5103
- const watcher = makeWatcherStub();
5104
- const sleep = makeSteppableSleep();
5105
- let triggerShutdown = () => { };
5106
- const runPass = vi.fn().mockResolvedValue(completedPassOutcome());
5107
- const loop = runRunnerWithLoop(watchArgv, {
5108
- runPass,
5109
- clock: new FakeClock(),
5110
- createWatcher: (opts) => {
5111
- captured.push({ debounceMs: opts.debounceMs, maxWaitMs: opts.maxWaitMs });
5112
- return watcher;
5113
- },
5114
- sleep: sleep.sleep,
5115
- onShutdownSignal: (handler) => {
5116
- triggerShutdown = handler;
5117
- return () => { };
5118
- },
5119
- });
5120
- await flushLoopMicrotasks();
5121
- expect(captured).toEqual([{ debounceMs: 15_000, maxWaitMs: 120_000 }]);
5122
- triggerShutdown();
5123
- await loop;
5124
- });
5125
- it("HQ_SYNC_EVENT_DEBOUNCE_MS / HQ_SYNC_EVENT_MAX_WAIT_MS override the watcher debounce", async () => {
5126
- const savedDebounce = process.env.HQ_SYNC_EVENT_DEBOUNCE_MS;
5127
- const savedMaxWait = process.env.HQ_SYNC_EVENT_MAX_WAIT_MS;
5128
- process.env.HQ_SYNC_EVENT_DEBOUNCE_MS = "5000";
5129
- process.env.HQ_SYNC_EVENT_MAX_WAIT_MS = "45000";
5130
- try {
5131
- const captured = [];
5132
- const watcher = makeWatcherStub();
5133
- const sleep = makeSteppableSleep();
5134
- let triggerShutdown = () => { };
5135
- const runPass = vi.fn().mockResolvedValue(completedPassOutcome());
5136
- const loop = runRunnerWithLoop(watchArgv, {
5137
- runPass,
5138
- clock: new FakeClock(),
5139
- createWatcher: (opts) => {
5140
- captured.push({
5141
- debounceMs: opts.debounceMs,
5142
- maxWaitMs: opts.maxWaitMs,
5143
- });
5144
- return watcher;
5145
- },
5146
- sleep: sleep.sleep,
5147
- onShutdownSignal: (handler) => {
5148
- triggerShutdown = handler;
5149
- return () => { };
5150
- },
5151
- });
5152
- await flushLoopMicrotasks();
5153
- expect(captured).toEqual([{ debounceMs: 5000, maxWaitMs: 45_000 }]);
5154
- triggerShutdown();
5155
- await loop;
5156
- }
5157
- finally {
5158
- if (savedDebounce === undefined)
5159
- delete process.env.HQ_SYNC_EVENT_DEBOUNCE_MS;
5160
- else
5161
- process.env.HQ_SYNC_EVENT_DEBOUNCE_MS = savedDebounce;
5162
- if (savedMaxWait === undefined)
5163
- delete process.env.HQ_SYNC_EVENT_MAX_WAIT_MS;
5164
- else
5165
- process.env.HQ_SYNC_EVENT_MAX_WAIT_MS = savedMaxWait;
5166
- }
5167
- });
5168
4831
  });
5169
4832
  // ---------------------------------------------------------------------------
5170
4833
  // Re-initialize for each test (mock state hygiene)
@@ -6387,17 +6050,7 @@ describe("runRunnerWithLoop — Phase 3 event-sync wiring (US-017/018/019)", ()
6387
6050
  "--hq-root",
6388
6051
  "/tmp/hq",
6389
6052
  ],
6390
- // The receiver's targeted pull is path-scoped to the pushed key now.
6391
- [
6392
- "--company",
6393
- "acme",
6394
- "--direction",
6395
- "pull",
6396
- "--scope-path",
6397
- "remote.md",
6398
- "--hq-root",
6399
- "/tmp/hq",
6400
- ],
6053
+ ["--company", "acme", "--direction", "pull", "--hq-root", "/tmp/hq"],
6401
6054
  ]));
6402
6055
  const pushedRoutes = new Set();
6403
6056
  for (const passArgv of passArgvs) {
@@ -6498,7 +6151,7 @@ describe("runRunnerWithLoop — Phase 3 event-sync wiring (US-017/018/019)", ()
6498
6151
  // the differential signal for "did telemetry run".
6499
6152
  // ---------------------------------------------------------------------------
6500
6153
  describe("defaultCollectTelemetry person-entity gate", () => {
6501
- function makeTelemetryClient(persons, agents = []) {
6154
+ function makeTelemetryClient(persons) {
6502
6155
  const calls = {
6503
6156
  listByType: 0,
6504
6157
  getTelemetryOptIn: 0,
@@ -6508,9 +6161,9 @@ describe("defaultCollectTelemetry person-entity gate", () => {
6508
6161
  const client = {
6509
6162
  entity: {
6510
6163
  get: async () => ({}),
6511
- listByType: async (type) => {
6164
+ listByType: async (_type) => {
6512
6165
  calls.listByType++;
6513
- return type === "agent" ? agents : persons;
6166
+ return persons;
6514
6167
  },
6515
6168
  },
6516
6169
  // Telemetry surface (cast-to internally by defaultCollectTelemetry). With
@@ -6545,7 +6198,7 @@ describe("defaultCollectTelemetry person-entity gate", () => {
6545
6198
  try {
6546
6199
  const { client, calls } = makeTelemetryClient([]); // unprovisioned caller
6547
6200
  await defaultCollectTelemetry(client, false, hqRoot);
6548
- expect(calls.listByType).toBe(2); // person probe then agent probe
6201
+ expect(calls.listByType).toBe(1); // orphan-safe probe ran
6549
6202
  expect(calls.getTelemetryOptIn).toBe(0); // collectors never ran
6550
6203
  expect(calls.postUsage).toBe(0);
6551
6204
  expect(calls.postSkillInvocations).toBe(0);
@@ -6567,79 +6220,6 @@ describe("defaultCollectTelemetry person-entity gate", () => {
6567
6220
  fs.rmSync(hqRoot, { recursive: true, force: true });
6568
6221
  }
6569
6222
  });
6570
- it("runs telemetry for an agent machine identity with no person entity", async () => {
6571
- const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-tele-agent-"));
6572
- try {
6573
- const AGENT = {
6574
- uid: "agt_01KUSAGEAGENTTEST00000000",
6575
- type: "agent",
6576
- slug: "jeff",
6577
- status: "active",
6578
- bucketName: "hq-vault-agt_01KUSAGEAGENTTEST00000000",
6579
- createdAt: "2026-06-01T00:00:00Z",
6580
- };
6581
- const { client, calls } = makeTelemetryClient([], [AGENT]);
6582
- await defaultCollectTelemetry(client, false, hqRoot, undefined, undefined, AGENT.uid);
6583
- expect(calls.listByType).toBe(2);
6584
- // Both collectors forceCollect — neither probes GET /v1/usage/opt-in.
6585
- expect(calls.getTelemetryOptIn).toBe(0);
6586
- // Passed the gate: identity resolution writes machine-id before collecting.
6587
- expect(fs.existsSync(path.join(hqRoot, ".hq", "machine-id"))).toBe(true);
6588
- }
6589
- finally {
6590
- fs.rmSync(hqRoot, { recursive: true, force: true });
6591
- }
6592
- });
6593
- it("does not force-collect when a claimed agent uid is absent from the self-listing", async () => {
6594
- const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-tele-agent-miss-"));
6595
- try {
6596
- const AGENT = {
6597
- uid: "agt_01KUSAGEAGENTTEST00000000",
6598
- type: "agent",
6599
- slug: "jeff",
6600
- status: "active",
6601
- bucketName: "hq-vault-agt_01KUSAGEAGENTTEST00000000",
6602
- createdAt: "2026-06-01T00:00:00Z",
6603
- };
6604
- const { client, calls } = makeTelemetryClient([], [AGENT]);
6605
- await defaultCollectTelemetry(client, false, hqRoot, undefined, undefined, "agt_01KSOMEONEELSE00000000000");
6606
- expect(calls.listByType).toBe(2);
6607
- expect(calls.getTelemetryOptIn).toBe(0);
6608
- expect(fs.existsSync(path.join(hqRoot, ".hq", "machine-id"))).toBe(false);
6609
- }
6610
- finally {
6611
- fs.rmSync(hqRoot, { recursive: true, force: true });
6612
- }
6613
- });
6614
- it("does not treat any agt_ listing as self when more than one agent is visible", async () => {
6615
- const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-tele-agent-many-"));
6616
- try {
6617
- const a = {
6618
- uid: "agt_01KUSAGEAGENTTEST00000000",
6619
- type: "agent",
6620
- slug: "jeff",
6621
- status: "active",
6622
- bucketName: "hq-vault-agt_01KUSAGEAGENTTEST00000000",
6623
- createdAt: "2026-06-01T00:00:00Z",
6624
- };
6625
- const b = {
6626
- uid: "agt_01KUSAGEAGENTOTHER0000000",
6627
- type: "agent",
6628
- slug: "cx",
6629
- status: "active",
6630
- bucketName: "hq-vault-agt_01KUSAGEAGENTOTHER0000000",
6631
- createdAt: "2026-06-02T00:00:00Z",
6632
- };
6633
- const { client, calls } = makeTelemetryClient([], [a, b]);
6634
- await defaultCollectTelemetry(client, false, hqRoot);
6635
- expect(calls.listByType).toBe(2);
6636
- expect(calls.getTelemetryOptIn).toBe(0);
6637
- expect(fs.existsSync(path.join(hqRoot, ".hq", "machine-id"))).toBe(false);
6638
- }
6639
- finally {
6640
- fs.rmSync(hqRoot, { recursive: true, force: true });
6641
- }
6642
- });
6643
6223
  it("fails open: a thrown person probe still lets telemetry run (no provisioned-user regression)", async () => {
6644
6224
  const hqRoot = fs.mkdtempSync(path.join(os.tmpdir(), "hq-tele-throw-"));
6645
6225
  try {