spect8-mcp 0.1.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 (120) hide show
  1. package/README.md +69 -0
  2. package/dist/auth.d.ts +7 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +60 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +103 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/collectors/claude_jsonl.d.ts +28 -0
  11. package/dist/collectors/claude_jsonl.d.ts.map +1 -0
  12. package/dist/collectors/claude_jsonl.js +130 -0
  13. package/dist/collectors/claude_jsonl.js.map +1 -0
  14. package/dist/collectors/cursor_sqlite.d.ts +37 -0
  15. package/dist/collectors/cursor_sqlite.d.ts.map +1 -0
  16. package/dist/collectors/cursor_sqlite.js +164 -0
  17. package/dist/collectors/cursor_sqlite.js.map +1 -0
  18. package/dist/collectors/fs_metrics.d.ts +7 -0
  19. package/dist/collectors/fs_metrics.d.ts.map +1 -0
  20. package/dist/collectors/fs_metrics.js +36 -0
  21. package/dist/collectors/fs_metrics.js.map +1 -0
  22. package/dist/config.d.ts +63 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +108 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/hooks/claude_post_tool.d.ts +11 -0
  27. package/dist/hooks/claude_post_tool.d.ts.map +1 -0
  28. package/dist/hooks/claude_post_tool.js +77 -0
  29. package/dist/hooks/claude_post_tool.js.map +1 -0
  30. package/dist/hooks/claude_session_start.d.ts +9 -0
  31. package/dist/hooks/claude_session_start.d.ts.map +1 -0
  32. package/dist/hooks/claude_session_start.js +18 -0
  33. package/dist/hooks/claude_session_start.js.map +1 -0
  34. package/dist/hooks/claude_stop.d.ts +10 -0
  35. package/dist/hooks/claude_stop.d.ts.map +1 -0
  36. package/dist/hooks/claude_stop.js +51 -0
  37. package/dist/hooks/claude_stop.js.map +1 -0
  38. package/dist/hooks/cli.d.ts +8 -0
  39. package/dist/hooks/cli.d.ts.map +1 -0
  40. package/dist/hooks/cli.js +26 -0
  41. package/dist/hooks/cli.js.map +1 -0
  42. package/dist/hooks/shared.d.ts +27 -0
  43. package/dist/hooks/shared.d.ts.map +1 -0
  44. package/dist/hooks/shared.js +132 -0
  45. package/dist/hooks/shared.js.map +1 -0
  46. package/dist/interceptors/context.d.ts +11 -0
  47. package/dist/interceptors/context.d.ts.map +1 -0
  48. package/dist/interceptors/context.js +13 -0
  49. package/dist/interceptors/context.js.map +1 -0
  50. package/dist/interceptors/file_ops.d.ts +5 -0
  51. package/dist/interceptors/file_ops.d.ts.map +1 -0
  52. package/dist/interceptors/file_ops.js +21 -0
  53. package/dist/interceptors/file_ops.js.map +1 -0
  54. package/dist/interceptors/git_diff.d.ts +4 -0
  55. package/dist/interceptors/git_diff.d.ts.map +1 -0
  56. package/dist/interceptors/git_diff.js +37 -0
  57. package/dist/interceptors/git_diff.js.map +1 -0
  58. package/dist/interceptors/run_command.d.ts +9 -0
  59. package/dist/interceptors/run_command.d.ts.map +1 -0
  60. package/dist/interceptors/run_command.js +10 -0
  61. package/dist/interceptors/run_command.js.map +1 -0
  62. package/dist/interceptors/search_files.d.ts +4 -0
  63. package/dist/interceptors/search_files.d.ts.map +1 -0
  64. package/dist/interceptors/search_files.js +9 -0
  65. package/dist/interceptors/search_files.js.map +1 -0
  66. package/dist/logger.d.ts +11 -0
  67. package/dist/logger.d.ts.map +1 -0
  68. package/dist/logger.js +40 -0
  69. package/dist/logger.js.map +1 -0
  70. package/dist/server.d.ts +12 -0
  71. package/dist/server.d.ts.map +1 -0
  72. package/dist/server.js +218 -0
  73. package/dist/server.js.map +1 -0
  74. package/dist/session/developer_id.d.ts +6 -0
  75. package/dist/session/developer_id.d.ts.map +1 -0
  76. package/dist/session/developer_id.js +25 -0
  77. package/dist/session/developer_id.js.map +1 -0
  78. package/dist/session/session_id.d.ts +8 -0
  79. package/dist/session/session_id.d.ts.map +1 -0
  80. package/dist/session/session_id.js +32 -0
  81. package/dist/session/session_id.js.map +1 -0
  82. package/dist/tools/end_task.d.ts +14 -0
  83. package/dist/tools/end_task.d.ts.map +1 -0
  84. package/dist/tools/end_task.js +25 -0
  85. package/dist/tools/end_task.js.map +1 -0
  86. package/dist/tools/get_score.d.ts +29 -0
  87. package/dist/tools/get_score.d.ts.map +1 -0
  88. package/dist/tools/get_score.js +54 -0
  89. package/dist/tools/get_score.js.map +1 -0
  90. package/dist/tools/report_activity.d.ts +59 -0
  91. package/dist/tools/report_activity.d.ts.map +1 -0
  92. package/dist/tools/report_activity.js +44 -0
  93. package/dist/tools/report_activity.js.map +1 -0
  94. package/dist/tools/start_task.d.ts +28 -0
  95. package/dist/tools/start_task.d.ts.map +1 -0
  96. package/dist/tools/start_task.js +34 -0
  97. package/dist/tools/start_task.js.map +1 -0
  98. package/dist/transport/batcher.d.ts +40 -0
  99. package/dist/transport/batcher.d.ts.map +1 -0
  100. package/dist/transport/batcher.js +115 -0
  101. package/dist/transport/batcher.js.map +1 -0
  102. package/dist/transport/ingest_client.d.ts +20 -0
  103. package/dist/transport/ingest_client.d.ts.map +1 -0
  104. package/dist/transport/ingest_client.js +78 -0
  105. package/dist/transport/ingest_client.js.map +1 -0
  106. package/dist/transport/offline_queue.d.ts +30 -0
  107. package/dist/transport/offline_queue.d.ts.map +1 -0
  108. package/dist/transport/offline_queue.js +83 -0
  109. package/dist/transport/offline_queue.js.map +1 -0
  110. package/dist/transport/sign.d.ts +7 -0
  111. package/dist/transport/sign.d.ts.map +1 -0
  112. package/dist/transport/sign.js +14 -0
  113. package/dist/transport/sign.js.map +1 -0
  114. package/dist/types.d.ts +123 -0
  115. package/dist/types.d.ts.map +1 -0
  116. package/dist/types.js +53 -0
  117. package/dist/types.js.map +1 -0
  118. package/examples/claude/hooks.json +37 -0
  119. package/examples/cursor/mcp.json +14 -0
  120. package/package.json +53 -0
@@ -0,0 +1,25 @@
1
+ import { execSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ /**
4
+ * Returns a stable developer identifier.
5
+ * Priority: explicit config/env > hashed `git config user.email` > "anonymous".
6
+ */
7
+ export function resolveDeveloperId(explicit) {
8
+ if (explicit && explicit.trim() !== "") {
9
+ return explicit.trim();
10
+ }
11
+ try {
12
+ const email = execSync("git config --global user.email", {
13
+ stdio: ["ignore", "pipe", "ignore"],
14
+ encoding: "utf8",
15
+ }).trim();
16
+ if (email) {
17
+ return "dev_" + createHash("sha256").update(email).digest("hex").slice(0, 16);
18
+ }
19
+ }
20
+ catch {
21
+ // git missing or unconfigured
22
+ }
23
+ return "anonymous";
24
+ }
25
+ //# sourceMappingURL=developer_id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"developer_id.js","sourceRoot":"","sources":["../../src/session/developer_id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAwB;IACzD,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACvC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,gCAAgC,EAAE;YACvD,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Reads an existing session id if the file exists (and is a valid UUID), or
3
+ * mints and persists a new one. Persistence survives IDE restarts within a
4
+ * day; tweak `sessionFilePath` or delete the file to force a new session.
5
+ */
6
+ export declare function getOrCreateSessionId(sessionFilePath: string): string;
7
+ export declare function rotateSessionId(sessionFilePath: string): string;
8
+ //# sourceMappingURL=session_id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session_id.d.ts","sourceRoot":"","sources":["../../src/session/session_id.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAepE;AAED,wBAAgB,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAK/D"}
@@ -0,0 +1,32 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ /**
5
+ * Reads an existing session id if the file exists (and is a valid UUID), or
6
+ * mints and persists a new one. Persistence survives IDE restarts within a
7
+ * day; tweak `sessionFilePath` or delete the file to force a new session.
8
+ */
9
+ export function getOrCreateSessionId(sessionFilePath) {
10
+ if (existsSync(sessionFilePath)) {
11
+ try {
12
+ const existing = readFileSync(sessionFilePath, "utf8").trim();
13
+ if (existing && /^[0-9a-fA-F-]{8,}$/.test(existing)) {
14
+ return existing;
15
+ }
16
+ }
17
+ catch {
18
+ // fall through to regenerate
19
+ }
20
+ }
21
+ const fresh = randomUUID();
22
+ mkdirSync(dirname(sessionFilePath), { recursive: true });
23
+ writeFileSync(sessionFilePath, fresh, "utf8");
24
+ return fresh;
25
+ }
26
+ export function rotateSessionId(sessionFilePath) {
27
+ const fresh = randomUUID();
28
+ mkdirSync(dirname(sessionFilePath), { recursive: true });
29
+ writeFileSync(sessionFilePath, fresh, "utf8");
30
+ return fresh;
31
+ }
32
+ //# sourceMappingURL=session_id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session_id.js","sourceRoot":"","sources":["../../src/session/session_id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,eAAuB;IAC1D,IAAI,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9D,IAAI,QAAQ,IAAI,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpD,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;QAC/B,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,SAAS,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,aAAa,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,eAAuB;IACrD,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,SAAS,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,aAAa,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Batcher } from "../transport/batcher.js";
2
+ import { type InterceptorCtx } from "../interceptors/context.js";
3
+ export interface EndTaskDeps {
4
+ ctx: InterceptorCtx;
5
+ batcher: Batcher;
6
+ onTaskEnded: () => void;
7
+ }
8
+ export declare function runEndTask(deps: EndTaskDeps): {
9
+ content: {
10
+ type: "text";
11
+ text: string;
12
+ }[];
13
+ };
14
+ //# sourceMappingURL=end_task.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"end_task.d.ts","sourceRoot":"","sources":["../../src/tools/end_task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,cAAc,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,GAChB;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAsB/C"}
@@ -0,0 +1,25 @@
1
+ import { baseEvent } from "../interceptors/context.js";
2
+ export function runEndTask(deps) {
3
+ const taskId = deps.ctx.getTaskId();
4
+ if (!taskId) {
5
+ return {
6
+ content: [
7
+ {
8
+ type: "text",
9
+ text: "No active task. Call `start_task` first.",
10
+ },
11
+ ],
12
+ };
13
+ }
14
+ deps.batcher.enqueueEvent({
15
+ ...baseEvent(deps.ctx, "end_task"),
16
+ task_id: taskId,
17
+ });
18
+ deps.onTaskEnded();
19
+ return {
20
+ content: [
21
+ { type: "text", text: `Ended task ${taskId}.` },
22
+ ],
23
+ };
24
+ }
25
+ //# sourceMappingURL=end_task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"end_task.js","sourceRoot":"","sources":["../../src/tools/end_task.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAuB,MAAM,4BAA4B,CAAC;AAQ5E,MAAM,UAAU,UAAU,CACxB,IAAiB;IAEjB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;IACpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,0CAA0C;iBACjD;aACF;SACF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;QACxB,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC;QAClC,OAAO,EAAE,MAAM;KAChB,CAAC,CAAC;IACH,IAAI,CAAC,WAAW,EAAE,CAAC;IACnB,OAAO;QACL,OAAO,EAAE;YACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,MAAM,GAAG,EAAE;SAChD;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { IngestClient } from "../transport/ingest_client.js";
3
+ import type { Logger } from "../logger.js";
4
+ export declare const GetScoreArgsSchema: z.ZodObject<{
5
+ session_id: z.ZodOptional<z.ZodString>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ session_id?: string | undefined;
8
+ }, {
9
+ session_id?: string | undefined;
10
+ }>;
11
+ export interface GetScoreArgs extends z.infer<typeof GetScoreArgsSchema> {
12
+ }
13
+ export interface ScoreCardText {
14
+ type: "text";
15
+ text: string;
16
+ }
17
+ export interface GetScoreDeps {
18
+ client: IngestClient;
19
+ developerId: string;
20
+ logger: Logger;
21
+ }
22
+ /**
23
+ * Fetches the developer's live posterior score and, when a `session_id` is
24
+ * supplied, the most recent session score.
25
+ */
26
+ export declare function runGetScore(args: GetScoreArgs, deps: GetScoreDeps): Promise<{
27
+ content: ScoreCardText[];
28
+ }>;
29
+ //# sourceMappingURL=get_score.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get_score.d.ts","sourceRoot":"","sources":["../../src/tools/get_score.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,eAAO,MAAM,kBAAkB;;;;;;EAE7B,CAAC;AAEH,MAAM,WAAW,YAAa,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC;CAAG;AAE3E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CAqEvC"}
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ export const GetScoreArgsSchema = z.object({
3
+ session_id: z.string().optional(),
4
+ });
5
+ /**
6
+ * Fetches the developer's live posterior score and, when a `session_id` is
7
+ * supplied, the most recent session score.
8
+ */
9
+ export async function runGetScore(args, deps) {
10
+ const lines = [];
11
+ const posteriorRes = await deps.client.get(`/api/v1/posterior/${encodeURIComponent(deps.developerId)}`);
12
+ if (posteriorRes.ok) {
13
+ try {
14
+ const body = JSON.parse(posteriorRes.body);
15
+ if (body.exists && body.posterior) {
16
+ const p = body.posterior;
17
+ lines.push(`Developer ${deps.developerId} score: ${p.score.toFixed(3)} ` +
18
+ `(confidence ${p.confidence.toFixed(2)}; ` +
19
+ `95% CI ${p.ci_lower.toFixed(3)}-${p.ci_upper.toFixed(3)}; ` +
20
+ `${p.sessions_observed} sessions observed)`);
21
+ }
22
+ else {
23
+ lines.push(`No posterior yet for developer '${deps.developerId}' - score will populate after the first scored session.`);
24
+ }
25
+ }
26
+ catch (err) {
27
+ lines.push(`posterior: failed to parse response (${err.message})`);
28
+ }
29
+ }
30
+ else {
31
+ lines.push(`posterior lookup failed (${posteriorRes.status}): ${posteriorRes.body.slice(0, 120)}`);
32
+ }
33
+ if (args.session_id) {
34
+ const scoreRes = await deps.client.get(`/api/v1/score/${encodeURIComponent(args.session_id)}?include_advanced=true`);
35
+ if (scoreRes.ok) {
36
+ try {
37
+ const body = JSON.parse(scoreRes.body);
38
+ if (typeof body.score === "number") {
39
+ lines.push(`Session ${args.session_id} score: ${body.score.toFixed(3)}`);
40
+ }
41
+ }
42
+ catch {
43
+ lines.push(`session score: failed to parse response for ${args.session_id}`);
44
+ }
45
+ }
46
+ else {
47
+ lines.push(`session score lookup failed (${scoreRes.status}): ${scoreRes.body.slice(0, 120)}`);
48
+ }
49
+ }
50
+ return {
51
+ content: [{ type: "text", text: lines.join("\n") }],
52
+ };
53
+ }
54
+ //# sourceMappingURL=get_score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get_score.js","sourceRoot":"","sources":["../../src/tools/get_score.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+ import type { Batcher } from "../transport/batcher.js";
3
+ import { type InterceptorCtx } from "../interceptors/context.js";
4
+ export declare const ReportActivityArgsSchema: z.ZodObject<{
5
+ activity_type: z.ZodEnum<["read_file", "write_file", "run_command", "git_diff", "search_files"]>;
6
+ file_path: z.ZodOptional<z.ZodString>;
7
+ file_size_bytes: z.ZodOptional<z.ZodNumber>;
8
+ lines_count: z.ZodOptional<z.ZodNumber>;
9
+ command: z.ZodOptional<z.ZodString>;
10
+ exit_code: z.ZodOptional<z.ZodNumber>;
11
+ command_duration_ms: z.ZodOptional<z.ZodNumber>;
12
+ search_query: z.ZodOptional<z.ZodString>;
13
+ search_results_count: z.ZodOptional<z.ZodNumber>;
14
+ diff_lines_added: z.ZodOptional<z.ZodNumber>;
15
+ diff_lines_removed: z.ZodOptional<z.ZodNumber>;
16
+ diff_files_changed: z.ZodOptional<z.ZodNumber>;
17
+ ide_name: z.ZodOptional<z.ZodString>;
18
+ }, "strip", z.ZodTypeAny, {
19
+ activity_type: "read_file" | "write_file" | "run_command" | "git_diff" | "search_files";
20
+ ide_name?: string | undefined;
21
+ file_path?: string | undefined;
22
+ file_size_bytes?: number | undefined;
23
+ lines_count?: number | undefined;
24
+ command?: string | undefined;
25
+ exit_code?: number | undefined;
26
+ command_duration_ms?: number | undefined;
27
+ search_query?: string | undefined;
28
+ search_results_count?: number | undefined;
29
+ diff_lines_added?: number | undefined;
30
+ diff_lines_removed?: number | undefined;
31
+ diff_files_changed?: number | undefined;
32
+ }, {
33
+ activity_type: "read_file" | "write_file" | "run_command" | "git_diff" | "search_files";
34
+ ide_name?: string | undefined;
35
+ file_path?: string | undefined;
36
+ file_size_bytes?: number | undefined;
37
+ lines_count?: number | undefined;
38
+ command?: string | undefined;
39
+ exit_code?: number | undefined;
40
+ command_duration_ms?: number | undefined;
41
+ search_query?: string | undefined;
42
+ search_results_count?: number | undefined;
43
+ diff_lines_added?: number | undefined;
44
+ diff_lines_removed?: number | undefined;
45
+ diff_files_changed?: number | undefined;
46
+ }>;
47
+ export interface ReportActivityArgs extends z.infer<typeof ReportActivityArgsSchema> {
48
+ }
49
+ export interface ReportActivityDeps {
50
+ ctx: InterceptorCtx;
51
+ batcher: Batcher;
52
+ }
53
+ export declare function runReportActivity(args: ReportActivityArgs, deps: ReportActivityDeps): {
54
+ content: {
55
+ type: "text";
56
+ text: string;
57
+ }[];
58
+ };
59
+ //# sourceMappingURL=report_activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report_activity.d.ts","sourceRoot":"","sources":["../../src/tools/report_activity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5E,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcnC,CAAC;AAEH,MAAM,WAAW,kBAAmB,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC;CAAG;AAEvF,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,cAAc,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,kBAAkB,GACvB;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CA4B/C"}
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ import { baseEvent } from "../interceptors/context.js";
3
+ export const ReportActivityArgsSchema = z.object({
4
+ activity_type: z.enum(["read_file", "write_file", "run_command", "git_diff", "search_files"]),
5
+ file_path: z.string().optional(),
6
+ file_size_bytes: z.number().int().optional(),
7
+ lines_count: z.number().int().optional(),
8
+ command: z.string().optional(),
9
+ exit_code: z.number().int().optional(),
10
+ command_duration_ms: z.number().int().optional(),
11
+ search_query: z.string().optional(),
12
+ search_results_count: z.number().int().optional(),
13
+ diff_lines_added: z.number().int().optional(),
14
+ diff_lines_removed: z.number().int().optional(),
15
+ diff_files_changed: z.number().int().optional(),
16
+ ide_name: z.string().optional(),
17
+ });
18
+ export function runReportActivity(args, deps) {
19
+ const event = {
20
+ ...baseEvent(deps.ctx, args.activity_type),
21
+ file_path: args.file_path,
22
+ file_size_bytes: args.file_size_bytes,
23
+ lines_count: args.lines_count,
24
+ command: args.command,
25
+ exit_code: args.exit_code,
26
+ command_duration_ms: args.command_duration_ms,
27
+ search_query: args.search_query,
28
+ search_results_count: args.search_results_count,
29
+ diff_lines_added: args.diff_lines_added,
30
+ diff_lines_removed: args.diff_lines_removed,
31
+ diff_files_changed: args.diff_files_changed,
32
+ ide_name: args.ide_name || deps.ctx.ideName,
33
+ };
34
+ deps.batcher.enqueueEvent(event);
35
+ return {
36
+ content: [
37
+ {
38
+ type: "text",
39
+ text: `Reported activity '${args.activity_type}' successfully.`,
40
+ },
41
+ ],
42
+ };
43
+ }
44
+ //# sourceMappingURL=report_activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report_activity.js","sourceRoot":"","sources":["../../src/tools/report_activity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,SAAS,EAAuB,MAAM,4BAA4B,CAAC;AAE5E,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;IAC7F,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAChD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC7C,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC/C,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC/C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AASH,MAAM,UAAU,iBAAiB,CAC/B,IAAwB,EACxB,IAAwB;IAGxB,MAAM,KAAK,GAAc;QACvB,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,aAAyB,CAAC;QACtD,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;QAC/C,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO;KAC5C,CAAC;IAEF,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAEjC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,sBAAsB,IAAI,CAAC,aAAa,iBAAiB;aAChE;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ import type { Batcher } from "../transport/batcher.js";
3
+ import { type InterceptorCtx } from "../interceptors/context.js";
4
+ export declare const StartTaskArgsSchema: z.ZodObject<{
5
+ task_label: z.ZodString;
6
+ ide_name: z.ZodOptional<z.ZodString>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ task_label: string;
9
+ ide_name?: string | undefined;
10
+ }, {
11
+ task_label: string;
12
+ ide_name?: string | undefined;
13
+ }>;
14
+ export interface StartTaskArgs extends z.infer<typeof StartTaskArgsSchema> {
15
+ }
16
+ export interface StartTaskDeps {
17
+ ctx: Omit<InterceptorCtx, "getTaskId">;
18
+ batcher: Batcher;
19
+ onTaskStarted: (taskId: string) => void;
20
+ }
21
+ export declare function runStartTask(args: StartTaskArgs, deps: StartTaskDeps): {
22
+ content: {
23
+ type: "text";
24
+ text: string;
25
+ }[];
26
+ taskId: string;
27
+ };
28
+ //# sourceMappingURL=start_task.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start_task.d.ts","sourceRoot":"","sources":["../../src/tools/start_task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5E,eAAO,MAAM,mBAAmB;;;;;;;;;EAG9B,CAAC;AAEH,MAAM,WAAW,aAAc,SAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC;CAAG;AAE7E,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,aAAa,GAClB;IAAE,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA6B/D"}
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ import { randomUUID } from "node:crypto";
3
+ import { baseEvent } from "../interceptors/context.js";
4
+ export const StartTaskArgsSchema = z.object({
5
+ task_label: z.string().min(1),
6
+ ide_name: z.string().optional(),
7
+ });
8
+ export function runStartTask(args, deps) {
9
+ const taskId = randomUUID();
10
+ deps.onTaskStarted(taskId);
11
+ const ctx = { ...deps.ctx, getTaskId: () => taskId };
12
+ const prompt = {
13
+ ...baseEvent(ctx, "prompt_start"),
14
+ task_label: args.task_label,
15
+ ide_name: args.ide_name || ctx.ideName,
16
+ };
17
+ const start = {
18
+ ...baseEvent(ctx, "start_task"),
19
+ task_label: args.task_label,
20
+ ide_name: args.ide_name || ctx.ideName,
21
+ };
22
+ deps.batcher.enqueueEvent(prompt);
23
+ deps.batcher.enqueueEvent(start);
24
+ return {
25
+ content: [
26
+ {
27
+ type: "text",
28
+ text: `Started task '${args.task_label}' with id ${taskId}.`,
29
+ },
30
+ ],
31
+ taskId,
32
+ };
33
+ }
34
+ //# sourceMappingURL=start_task.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start_task.js","sourceRoot":"","sources":["../../src/tools/start_task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,OAAO,EAAE,SAAS,EAAuB,MAAM,4BAA4B,CAAC;AAE5E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAUH,MAAM,UAAU,YAAY,CAC1B,IAAmB,EACnB,IAAmB;IAEnB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAE3B,MAAM,GAAG,GAAmB,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;IAErE,MAAM,MAAM,GAAc;QACxB,GAAG,SAAS,CAAC,GAAG,EAAE,cAAc,CAAC;QACjC,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,OAAO;KACvC,CAAC;IACF,MAAM,KAAK,GAAc;QACvB,GAAG,SAAS,CAAC,GAAG,EAAE,YAAY,CAAC;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,OAAO;KACvC,CAAC;IAEF,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAEjC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,iBAAiB,IAAI,CAAC,UAAU,aAAa,MAAM,GAAG;aAC7D;SACF;QACD,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,40 @@
1
+ import type { Logger } from "../logger.js";
2
+ import type { IngestClient } from "./ingest_client.js";
3
+ import type { OfflineQueue } from "./offline_queue.js";
4
+ import type { ToolEvent, TokenEvent } from "../types.js";
5
+ export interface BatcherOptions {
6
+ intervalMs: number;
7
+ maxEvents: number;
8
+ client: IngestClient;
9
+ queue: OfflineQueue;
10
+ logger: Logger;
11
+ }
12
+ /**
13
+ * Buffers incoming events in memory and flushes them on whichever of these
14
+ * happens first:
15
+ *
16
+ * - `maxEvents` accumulated for that kind
17
+ * - `intervalMs` has elapsed since the last flush attempt
18
+ * - an explicit call to `flush()` (e.g. at process shutdown)
19
+ *
20
+ * Failed POSTs are persisted into the offline queue. Every tick also replays a
21
+ * small slice of the offline queue so recovery is automatic once the endpoint
22
+ * comes back online.
23
+ */
24
+ export declare class Batcher {
25
+ private readonly opts;
26
+ private readonly events;
27
+ private readonly tokenEvents;
28
+ private timer;
29
+ private flushing;
30
+ private stopped;
31
+ constructor(opts: BatcherOptions);
32
+ start(): void;
33
+ enqueueEvent(ev: ToolEvent): void;
34
+ enqueueTokenEvent(ev: TokenEvent): void;
35
+ flush(): Promise<void>;
36
+ stop(): Promise<void>;
37
+ private flushBuffer;
38
+ private drainQueue;
39
+ }
40
+ //# sourceMappingURL=batcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batcher.d.ts","sourceRoot":"","sources":["../../src/transport/batcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAID;;;;;;;;;;;GAWG;AACH,qBAAa,OAAO;IAcN,OAAO,CAAC,QAAQ,CAAC,IAAI;IAbjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGrB;IACF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAG1B;IAEF,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEK,IAAI,EAAE,cAAc;IAEjD,KAAK,IAAI,IAAI;IAQb,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAOjC,iBAAiB,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI;IAOjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YASb,WAAW;YA6BX,UAAU;CAiCzB"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Buffers incoming events in memory and flushes them on whichever of these
3
+ * happens first:
4
+ *
5
+ * - `maxEvents` accumulated for that kind
6
+ * - `intervalMs` has elapsed since the last flush attempt
7
+ * - an explicit call to `flush()` (e.g. at process shutdown)
8
+ *
9
+ * Failed POSTs are persisted into the offline queue. Every tick also replays a
10
+ * small slice of the offline queue so recovery is automatic once the endpoint
11
+ * comes back online.
12
+ */
13
+ export class Batcher {
14
+ opts;
15
+ events = {
16
+ items: [],
17
+ kind: "event",
18
+ };
19
+ tokenEvents = {
20
+ items: [],
21
+ kind: "token_event",
22
+ };
23
+ timer = null;
24
+ flushing = false;
25
+ stopped = false;
26
+ constructor(opts) {
27
+ this.opts = opts;
28
+ }
29
+ start() {
30
+ if (this.timer)
31
+ return;
32
+ this.timer = setInterval(() => {
33
+ void this.flush();
34
+ }, this.opts.intervalMs);
35
+ this.timer.unref?.();
36
+ }
37
+ enqueueEvent(ev) {
38
+ this.events.items.push(ev);
39
+ if (this.events.items.length >= this.opts.maxEvents) {
40
+ void this.flush();
41
+ }
42
+ }
43
+ enqueueTokenEvent(ev) {
44
+ this.tokenEvents.items.push(ev);
45
+ if (this.tokenEvents.items.length >= this.opts.maxEvents) {
46
+ void this.flush();
47
+ }
48
+ }
49
+ async flush() {
50
+ if (this.flushing || this.stopped)
51
+ return;
52
+ this.flushing = true;
53
+ try {
54
+ await this.flushBuffer(this.events, (items) => this.opts.client.postEvents(items));
55
+ await this.flushBuffer(this.tokenEvents, (items) => this.opts.client.postTokenEvents(items));
56
+ await this.drainQueue("event", (items) => this.opts.client.postEvents(items));
57
+ await this.drainQueue("token_event", (items) => this.opts.client.postTokenEvents(items));
58
+ }
59
+ finally {
60
+ this.flushing = false;
61
+ }
62
+ }
63
+ async stop() {
64
+ if (this.timer) {
65
+ clearInterval(this.timer);
66
+ this.timer = null;
67
+ }
68
+ await this.flush();
69
+ this.stopped = true;
70
+ }
71
+ async flushBuffer(buf, send) {
72
+ if (buf.items.length === 0)
73
+ return;
74
+ const batch = buf.items.splice(0, this.opts.maxEvents);
75
+ try {
76
+ const result = await send(batch);
77
+ if (!result.ok) {
78
+ this.opts.queue.enqueueMany(buf.kind, batch.map((e) => JSON.stringify(e)));
79
+ this.opts.logger.debug(`flush: buffered ${batch.length} ${buf.kind} rows to offline queue (status=${result.status})`);
80
+ }
81
+ }
82
+ catch (err) {
83
+ this.opts.queue.enqueueMany(buf.kind, batch.map((e) => JSON.stringify(e)));
84
+ this.opts.logger.warn(`flush: buffered ${batch.length} ${buf.kind} rows after exception`, err.message);
85
+ }
86
+ }
87
+ async drainQueue(kind, send) {
88
+ const rows = this.opts.queue.dequeue(kind, this.opts.maxEvents);
89
+ if (rows.length === 0)
90
+ return;
91
+ let parsed;
92
+ try {
93
+ parsed = rows.map((r) => JSON.parse(r.payload));
94
+ }
95
+ catch (err) {
96
+ this.opts.logger.warn(`drain: dropping ${rows.length} malformed rows`, err.message);
97
+ this.opts.queue.ack(rows.map((r) => r.id));
98
+ return;
99
+ }
100
+ try {
101
+ const result = await send(parsed);
102
+ if (result.ok) {
103
+ this.opts.queue.ack(rows.map((r) => r.id));
104
+ this.opts.logger.debug(`drain: flushed ${rows.length} queued ${kind} rows`);
105
+ }
106
+ else {
107
+ this.opts.queue.bump(rows.map((r) => r.id));
108
+ }
109
+ }
110
+ catch {
111
+ this.opts.queue.bump(rows.map((r) => r.id));
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=batcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batcher.js","sourceRoot":"","sources":["../../src/transport/batcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Logger } from "../logger.js";
2
+ import type { ToolEvent, TokenEvent } from "../types.js";
3
+ export interface PostResult {
4
+ ok: boolean;
5
+ status: number;
6
+ body: string;
7
+ }
8
+ export declare class IngestClient {
9
+ private readonly baseUrl;
10
+ private readonly hmacKey;
11
+ private readonly developerId;
12
+ private readonly logger;
13
+ private readonly timeoutMs;
14
+ constructor(baseUrl: string, hmacKey: string, developerId: string, logger: Logger, timeoutMs?: number);
15
+ postEvents(events: ToolEvent[]): Promise<PostResult>;
16
+ postTokenEvents(events: TokenEvent[]): Promise<PostResult>;
17
+ get(path: string): Promise<PostResult>;
18
+ private post;
19
+ }
20
+ //# sourceMappingURL=ingest_client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest_client.d.ts","sourceRoot":"","sources":["../../src/transport/ingest_client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAJT,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAe;IAGvC,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIpD,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAI1D,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;YAuB9B,IAAI;CAmCnB"}