@indigoai-us/hq-cloud 6.14.39 → 6.14.40

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.
@@ -11,6 +11,7 @@ import {
11
11
  parseCodexSessionMeta,
12
12
  collectAndSendSkillTelemetry,
13
13
  computeSkillVersion,
14
+ MAX_DECODE_BYTES,
14
15
  readFileRegion,
15
16
  } from "./skill-telemetry.js";
16
17
  import { encodeLocalVaultSegment } from "./local-path-codec.js";
@@ -758,6 +759,244 @@ describe("collectAndSendSkillTelemetry — hqRoot scoping", () => {
758
759
  await fs.rm(tmp, { recursive: true, force: true });
759
760
  });
760
761
 
762
+ it("HQ-DESKTOP-47: settles at complete UTF-8 lines and drains a bounded backlog without gaps", async () => {
763
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-bounded-"));
764
+ const projects = path.join(tmp, "projects");
765
+ const dir = path.join(projects, "-p");
766
+ await fs.mkdir(dir, { recursive: true });
767
+ const file = path.join(dir, "s.jsonl");
768
+ const lines = [
769
+ row({ type: "user", sessionId: "s1", timestamp: "2026-08-02T10:00:00Z", cwd: "/x", uuid: "u1", message: { role: "user", content: "<command-name>/deploy</command-name>" } }),
770
+ row({ type: "user", sessionId: "s1", timestamp: "2026-08-02T10:01:00Z", cwd: "/x", uuid: "u2", message: { role: "user", content: "<command-name>/plán</command-name>" } }),
771
+ row({ type: "user", sessionId: "s1", timestamp: "2026-08-02T10:02:00Z", cwd: "/x", uuid: "u3", message: { role: "user", content: "<command-name>/ship</command-name>" } }),
772
+ ];
773
+ await fs.writeFile(file, `${lines.join("\n")}\n`, "utf-8");
774
+
775
+ const cursorPath = path.join(tmp, "cursor.json");
776
+ const captured: SkillInvocationBatch[] = [];
777
+ const client = stubClient(captured);
778
+ const base = {
779
+ client,
780
+ machineId: "m",
781
+ installerVersion: "t",
782
+ claudeProjectsRoot: projects,
783
+ codexSessionsRoot: path.join(tmp, "codex"),
784
+ cursorPath,
785
+ };
786
+ const cursorOffset = async (): Promise<number> => {
787
+ const cursor = JSON.parse(await fs.readFile(cursorPath, "utf-8")) as {
788
+ files: Record<string, { offset: number }>;
789
+ };
790
+ return cursor.files[file]?.offset ?? 0;
791
+ };
792
+
793
+ // Stop in the middle of the two-byte á. The first pass must commit only
794
+ // the preceding complete line rather than a character-counted position.
795
+ const accentOffset = lines[1].indexOf("á");
796
+ const firstBudget =
797
+ Buffer.byteLength(`${lines[0]}\n${lines[1].slice(0, accentOffset)}`, "utf-8") + 1;
798
+ const logs: string[] = [];
799
+ const first = await collectAndSendSkillTelemetry({
800
+ ...base,
801
+ maxScanBytesPerSource: firstBudget,
802
+ log: (message) => logs.push(message),
803
+ });
804
+ const afterFirst = await cursorOffset();
805
+ expect(first.eventsSent).toBe(1);
806
+ expect(afterFirst).toBe(Buffer.byteLength(`${lines[0]}\n`, "utf-8"));
807
+ expect(logs.some((message) => message.includes("scan budget reached"))).toBe(true);
808
+
809
+ // The second pass reaches the next complete line but not the third; the
810
+ // third drains the remainder. Together they must equal an unbounded scan.
811
+ const second = await collectAndSendSkillTelemetry({
812
+ ...base,
813
+ maxScanBytesPerSource: Buffer.byteLength(`${lines[1]}\n`, "utf-8") + 1,
814
+ });
815
+ const afterSecond = await cursorOffset();
816
+ const third = await collectAndSendSkillTelemetry({
817
+ ...base,
818
+ maxScanBytesPerSource: 1024 * 1024,
819
+ });
820
+ const afterThird = await cursorOffset();
821
+
822
+ expect(second.eventsSent).toBe(1);
823
+ expect(third.eventsSent).toBe(1);
824
+ expect(afterFirst).toBeLessThan(afterSecond);
825
+ expect(afterSecond).toBeLessThan(afterThird);
826
+ expect(afterThird).toBe(Buffer.byteLength(`${lines.join("\n")}\n`, "utf-8"));
827
+ expect(captured.flatMap((batch) => batch.events.map((event) => event.skill))).toEqual([
828
+ "deploy",
829
+ "plán",
830
+ "ship",
831
+ ]);
832
+
833
+ await fs.rm(tmp, { recursive: true, force: true });
834
+ });
835
+
836
+ it("HQ-DESKTOP-47: a transcript below the injected budget keeps the one-pass EOF behaviour", async () => {
837
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-small-budget-"));
838
+ const projects = path.join(tmp, "projects");
839
+ const dir = path.join(projects, "-p");
840
+ await fs.mkdir(dir, { recursive: true });
841
+ const file = path.join(dir, "s.jsonl");
842
+ const transcript = row({ type: "user", sessionId: "s1", timestamp: "2026-08-02T11:00:00Z", cwd: "/x", uuid: "u1", message: { role: "user", content: "<command-name>/deploy</command-name>" } }) + "\n";
843
+ await fs.writeFile(file, transcript, "utf-8");
844
+
845
+ const cursorPath = path.join(tmp, "cursor.json");
846
+ const captured: SkillInvocationBatch[] = [];
847
+ const result = await collectAndSendSkillTelemetry({
848
+ client: stubClient(captured),
849
+ machineId: "m",
850
+ installerVersion: "t",
851
+ claudeProjectsRoot: projects,
852
+ codexSessionsRoot: path.join(tmp, "codex"),
853
+ cursorPath,
854
+ maxScanBytesPerSource: Buffer.byteLength(transcript, "utf-8") + 1,
855
+ });
856
+ const cursor = JSON.parse(await fs.readFile(cursorPath, "utf-8")) as {
857
+ files: Record<string, { offset: number }>;
858
+ };
859
+
860
+ expect(result.eventsSent).toBe(1);
861
+ expect(cursor.files[file]?.offset).toBe(Buffer.byteLength(transcript, "utf-8"));
862
+ expect(captured.flatMap((batch) => batch.events.map((event) => event.skill))).toEqual([
863
+ "deploy",
864
+ ]);
865
+
866
+ await fs.rm(tmp, { recursive: true, force: true });
867
+ });
868
+
869
+ it("HQ-DESKTOP-47: a truncated bounded backlog resets to the replacement file", async () => {
870
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-budget-rotate-"));
871
+ const projects = path.join(tmp, "projects");
872
+ const dir = path.join(projects, "-p");
873
+ await fs.mkdir(dir, { recursive: true });
874
+ const file = path.join(dir, "s.jsonl");
875
+ const oldLine = row({ type: "user", sessionId: "old", timestamp: "2026-08-02T12:00:00Z", cwd: "/x", uuid: "old-1", message: { role: "user", content: "<command-name>/deploy</command-name>" } });
876
+ const oldTail = row({ type: "user", sessionId: "old", timestamp: "2026-08-02T12:01:00Z", cwd: "/x", uuid: "old-2", message: { role: "user", content: "<command-name>/ship</command-name>" } });
877
+ await fs.writeFile(file, `${oldLine}\n${oldTail}\n`, "utf-8");
878
+
879
+ const cursorPath = path.join(tmp, "cursor.json");
880
+ const captured: SkillInvocationBatch[] = [];
881
+ const base = {
882
+ client: stubClient(captured),
883
+ machineId: "m",
884
+ installerVersion: "t",
885
+ claudeProjectsRoot: projects,
886
+ codexSessionsRoot: path.join(tmp, "codex"),
887
+ cursorPath,
888
+ };
889
+ await collectAndSendSkillTelemetry({
890
+ ...base,
891
+ maxScanBytesPerSource: Buffer.byteLength(`${oldLine}\n`, "utf-8") + 1,
892
+ });
893
+
894
+ const replacement = row({ type: "user", sessionId: "new", timestamp: "2026-08-02T12:02:00Z", cwd: "/x", uuid: "new-1", message: { role: "user", content: "<command-name>/land</command-name>" } }) + "\n";
895
+ expect(Buffer.byteLength(replacement, "utf-8")).toBeLessThan(
896
+ Buffer.byteLength(`${oldLine}\n`, "utf-8"),
897
+ );
898
+ await fs.writeFile(file, replacement, "utf-8");
899
+
900
+ const result = await collectAndSendSkillTelemetry({
901
+ ...base,
902
+ maxScanBytesPerSource: 1024 * 1024,
903
+ });
904
+ const cursor = JSON.parse(await fs.readFile(cursorPath, "utf-8")) as {
905
+ files: Record<string, { offset: number }>;
906
+ };
907
+
908
+ expect(result.eventsSent).toBe(1);
909
+ expect(cursor.files[file]?.offset).toBe(Buffer.byteLength(replacement, "utf-8"));
910
+ expect(captured.flatMap((batch) => batch.events.map((event) => event.skill))).toEqual([
911
+ "deploy",
912
+ "land",
913
+ ]);
914
+
915
+ await fs.rm(tmp, { recursive: true, force: true });
916
+ });
917
+
918
+ it("HQ-DESKTOP-47: continues past a single JSONL record larger than the scan budget", async () => {
919
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-large-line-"));
920
+ const projects = path.join(tmp, "projects");
921
+ const dir = path.join(projects, "-p");
922
+ await fs.mkdir(dir, { recursive: true });
923
+ const file = path.join(dir, "s.jsonl");
924
+ const oversized = row({ type: "user", sessionId: "s1", timestamp: "2026-08-02T13:00:00Z", cwd: "/x", uuid: "u1", message: { role: "user", content: `<command-name>/deploy</command-name><command-args>${"x".repeat(900)}</command-args>` } });
925
+ const tail = row({ type: "user", sessionId: "s1", timestamp: "2026-08-02T13:01:00Z", cwd: "/x", uuid: "u2", message: { role: "user", content: "<command-name>/land</command-name>" } });
926
+ await fs.writeFile(file, `${oversized}\n${tail}\n`, "utf-8");
927
+
928
+ const cursorPath = path.join(tmp, "cursor.json");
929
+ const captured: SkillInvocationBatch[] = [];
930
+ const base = {
931
+ client: stubClient(captured),
932
+ machineId: "m",
933
+ installerVersion: "t",
934
+ claudeProjectsRoot: projects,
935
+ codexSessionsRoot: path.join(tmp, "codex"),
936
+ cursorPath,
937
+ maxScanBytesPerSource: 128,
938
+ };
939
+ const offsets: number[] = [];
940
+ for (let pass = 0; pass < 12; pass++) {
941
+ await collectAndSendSkillTelemetry(base);
942
+ const cursor = JSON.parse(await fs.readFile(cursorPath, "utf-8")) as {
943
+ files: Record<string, { offset: number; pendingLine?: { scannedOffset: number } }>;
944
+ };
945
+ offsets.push(cursor.files[file]?.offset ?? 0);
946
+ }
947
+
948
+ expect(offsets.some((offset) => offset > 0)).toBe(true);
949
+ expect(offsets[0]).toBe(0); // first pass only discovers a partial record
950
+ expect(captured.flatMap((batch) => batch.events.map((event) => event.skill))).toEqual([
951
+ "deploy",
952
+ "land",
953
+ ]);
954
+
955
+ await fs.rm(tmp, { recursive: true, force: true });
956
+ });
957
+
958
+ it("HQ-DESKTOP-47: rotates a shared runtime budget so a backlog cannot starve a later session", async () => {
959
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-fair-"));
960
+ const projects = path.join(tmp, "projects");
961
+ const backlogDir = path.join(projects, "a-backlog");
962
+ const currentDir = path.join(projects, "b-current");
963
+ await fs.mkdir(backlogDir, { recursive: true });
964
+ await fs.mkdir(currentDir, { recursive: true });
965
+ const backlogLine = row({ type: "user", sessionId: "old", timestamp: "2026-08-02T14:00:00Z", cwd: "/x", uuid: "old-1", message: { role: "user", content: "<command-name>/deploy</command-name>" } });
966
+ await fs.writeFile(
967
+ path.join(backlogDir, "old.jsonl"),
968
+ `${Array.from({ length: 4 }, () => backlogLine).join("\n")}\n`,
969
+ "utf-8",
970
+ );
971
+ await fs.writeFile(
972
+ path.join(currentDir, "current.jsonl"),
973
+ row({ type: "user", sessionId: "new", timestamp: "2026-08-02T14:01:00Z", cwd: "/x", uuid: "new-1", message: { role: "user", content: "<command-name>/land</command-name>" } }) + "\n",
974
+ "utf-8",
975
+ );
976
+
977
+ const captured: SkillInvocationBatch[] = [];
978
+ const cursorPath = path.join(tmp, "cursor.json");
979
+ const budget = Buffer.byteLength(`${backlogLine}\n`, "utf-8") + 1;
980
+ const base = {
981
+ client: stubClient(captured),
982
+ machineId: "m",
983
+ installerVersion: "t",
984
+ claudeProjectsRoot: projects,
985
+ codexSessionsRoot: path.join(tmp, "codex"),
986
+ cursorPath,
987
+ maxScanBytesPerSource: budget,
988
+ };
989
+
990
+ await collectAndSendSkillTelemetry(base);
991
+ await collectAndSendSkillTelemetry(base);
992
+
993
+ expect(captured.flatMap((batch) => batch.events.map((event) => event.skill))).toContain(
994
+ "land",
995
+ );
996
+
997
+ await fs.rm(tmp, { recursive: true, force: true });
998
+ });
999
+
761
1000
  it("captures every project when hqRoot is omitted", async () => {
762
1001
  const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-"));
763
1002
  const projects = path.join(tmp, "projects");
@@ -1031,6 +1270,49 @@ describe("collectAndSendSkillTelemetry — hqRoot scoping", () => {
1031
1270
  await fs.rm(tmp, { recursive: true, force: true });
1032
1271
  });
1033
1272
 
1273
+ it("HQ-DESKTOP-47: preserves Codex turn dedup across a bounded resume", async () => {
1274
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-codex-budget-"));
1275
+ const codex = path.join(tmp, "sessions", "2026", "08", "02");
1276
+ await fs.mkdir(codex, { recursive: true });
1277
+ const hqRoot = "/home/ec2-user/hq";
1278
+ const lines = [
1279
+ row({ timestamp: "2026-08-02T15:00:00.000Z", type: "session_meta", payload: { id: "sess-budget", cwd: hqRoot } }),
1280
+ row({ timestamp: "2026-08-02T15:00:01.000Z", type: "turn_context", payload: { turn_id: "turn-budget", cwd: hqRoot } }),
1281
+ row({ timestamp: "2026-08-02T15:00:02.000Z", type: "response_item", payload: { type: "function_call", name: "exec_command", arguments: JSON.stringify({ cmd: "sed -n '1,80p' .claude/skills/deploy/SKILL.md", workdir: hqRoot }) } }),
1282
+ row({ timestamp: "2026-08-02T15:00:03.000Z", type: "response_item", payload: { type: "function_call", name: "exec_command", arguments: JSON.stringify({ cmd: "wc -l .claude/skills/deploy/SKILL.md", workdir: hqRoot }) } }),
1283
+ ];
1284
+ const file = path.join(codex, "rollout-budget.jsonl");
1285
+ await fs.writeFile(file, `${lines.join("\n")}\n`, "utf-8");
1286
+
1287
+ const captured: SkillInvocationBatch[] = [];
1288
+ const cursorPath = path.join(tmp, "cursor.json");
1289
+ const base = {
1290
+ client: stubClient(captured),
1291
+ machineId: "m",
1292
+ installerVersion: "t",
1293
+ hqRoot,
1294
+ claudeProjectsRoot: path.join(tmp, "no-claude"),
1295
+ codexSessionsRoot: path.join(tmp, "sessions"),
1296
+ cursorPath,
1297
+ };
1298
+ // Commit the turn_context but stop in the next function_call row.
1299
+ await collectAndSendSkillTelemetry({
1300
+ ...base,
1301
+ maxScanBytesPerSource: Buffer.byteLength(`${lines[0]}\n${lines[1]}\n`, "utf-8") + 1,
1302
+ });
1303
+ await collectAndSendSkillTelemetry({ ...base, maxScanBytesPerSource: 1024 * 1024 });
1304
+ await collectAndSendSkillTelemetry({ ...base, maxScanBytesPerSource: 1024 * 1024 });
1305
+
1306
+ const events = captured.flatMap((batch) => batch.events);
1307
+ expect(events).toHaveLength(1);
1308
+ expect(events[0]).toMatchObject({
1309
+ skill: "deploy",
1310
+ uuid: "codex:skill:sess-budget:turn-budget:deploy",
1311
+ });
1312
+
1313
+ await fs.rm(tmp, { recursive: true, force: true });
1314
+ });
1315
+
1034
1316
  it("does not count SKILL.md edits (apply_patch / write) as skill usage", async () => {
1035
1317
  const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "skill-tel-edit-"));
1036
1318
  const codex = path.join(tmp, "sessions", "2026", "06", "08");
@@ -1248,6 +1530,10 @@ describe("collectAndSendSkillTelemetry — companyUid attribution", () => {
1248
1530
  describe("readFileRegion — HQ-SYNC-WEB-15 (SIGABRT on >2GiB single read)", () => {
1249
1531
  const INT32_MAX = 2 ** 31 - 1;
1250
1532
 
1533
+ it("keeps the skill scanner's decode ceiling below V8's fatal 2 GiB boundary", () => {
1534
+ expect(MAX_DECODE_BYTES).toBeLessThan(2 ** 31);
1535
+ });
1536
+
1251
1537
  it("never issues a single read whose length exceeds Int32, even for a multi-GiB region", async () => {
1252
1538
  // The original code did `fh.read(buf, 0, currentSize - offset, offset)` in
1253
1539
  // one shot. Once a session log's unread tail passed ~2 GiB, the length