@ironbee-ai/cli 0.5.3 → 0.6.1

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 (135) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/clients/claude/hooks/require-verification.d.ts.map +1 -1
  3. package/dist/clients/claude/hooks/require-verification.js +21 -2
  4. package/dist/clients/claude/hooks/require-verification.js.map +1 -1
  5. package/dist/clients/claude/hooks/session-end.d.ts.map +1 -1
  6. package/dist/clients/claude/hooks/session-end.js +4 -0
  7. package/dist/clients/claude/hooks/session-end.js.map +1 -1
  8. package/dist/clients/claude/hooks/session-start.d.ts.map +1 -1
  9. package/dist/clients/claude/hooks/session-start.js +14 -4
  10. package/dist/clients/claude/hooks/session-start.js.map +1 -1
  11. package/dist/clients/claude/hooks/track-action.d.ts +25 -4
  12. package/dist/clients/claude/hooks/track-action.d.ts.map +1 -1
  13. package/dist/clients/claude/hooks/track-action.js +145 -25
  14. package/dist/clients/claude/hooks/track-action.js.map +1 -1
  15. package/dist/clients/claude/hooks/verify-gate.d.ts.map +1 -1
  16. package/dist/clients/claude/hooks/verify-gate.js +5 -0
  17. package/dist/clients/claude/hooks/verify-gate.js.map +1 -1
  18. package/dist/clients/claude/index.d.ts.map +1 -1
  19. package/dist/clients/claude/index.js +18 -1
  20. package/dist/clients/claude/index.js.map +1 -1
  21. package/dist/clients/claude/util.d.ts +74 -0
  22. package/dist/clients/claude/util.d.ts.map +1 -0
  23. package/dist/clients/claude/util.js +352 -0
  24. package/dist/clients/claude/util.js.map +1 -0
  25. package/dist/clients/cursor/hooks/require-verification.d.ts.map +1 -1
  26. package/dist/clients/cursor/hooks/require-verification.js +18 -2
  27. package/dist/clients/cursor/hooks/require-verification.js.map +1 -1
  28. package/dist/clients/cursor/hooks/session-end.d.ts.map +1 -1
  29. package/dist/clients/cursor/hooks/session-end.js +4 -0
  30. package/dist/clients/cursor/hooks/session-end.js.map +1 -1
  31. package/dist/clients/cursor/hooks/session-start.d.ts.map +1 -1
  32. package/dist/clients/cursor/hooks/session-start.js +4 -1
  33. package/dist/clients/cursor/hooks/session-start.js.map +1 -1
  34. package/dist/clients/cursor/hooks/track-action.d.ts +30 -8
  35. package/dist/clients/cursor/hooks/track-action.d.ts.map +1 -1
  36. package/dist/clients/cursor/hooks/track-action.js +179 -52
  37. package/dist/clients/cursor/hooks/track-action.js.map +1 -1
  38. package/dist/clients/cursor/hooks/verify-gate.d.ts.map +1 -1
  39. package/dist/clients/cursor/hooks/verify-gate.js +4 -0
  40. package/dist/clients/cursor/hooks/verify-gate.js.map +1 -1
  41. package/dist/clients/cursor/index.d.ts.map +1 -1
  42. package/dist/clients/cursor/index.js +13 -2
  43. package/dist/clients/cursor/index.js.map +1 -1
  44. package/dist/clients/cursor/util.d.ts +52 -0
  45. package/dist/clients/cursor/util.d.ts.map +1 -0
  46. package/dist/clients/cursor/util.js +264 -0
  47. package/dist/clients/cursor/util.js.map +1 -0
  48. package/dist/commands/hook.js +1 -2
  49. package/dist/commands/hook.js.map +1 -1
  50. package/dist/commands/process-job-file.d.ts +10 -0
  51. package/dist/commands/process-job-file.d.ts.map +1 -0
  52. package/dist/commands/process-job-file.js +19 -0
  53. package/dist/commands/process-job-file.js.map +1 -0
  54. package/dist/commands/queue.d.ts +12 -0
  55. package/dist/commands/queue.d.ts.map +1 -0
  56. package/dist/commands/queue.js +495 -0
  57. package/dist/commands/queue.js.map +1 -0
  58. package/dist/hooks/core/actions.d.ts +73 -2
  59. package/dist/hooks/core/actions.d.ts.map +1 -1
  60. package/dist/hooks/core/actions.js +36 -2
  61. package/dist/hooks/core/actions.js.map +1 -1
  62. package/dist/hooks/core/session-state.d.ts +27 -0
  63. package/dist/hooks/core/session-state.d.ts.map +1 -1
  64. package/dist/hooks/core/session-state.js +97 -0
  65. package/dist/hooks/core/session-state.js.map +1 -1
  66. package/dist/hooks/core/verify-gate.d.ts.map +1 -1
  67. package/dist/hooks/core/verify-gate.js +13 -5
  68. package/dist/hooks/core/verify-gate.js.map +1 -1
  69. package/dist/index.js +12 -3
  70. package/dist/index.js.map +1 -1
  71. package/dist/lib/collector.d.ts +62 -3
  72. package/dist/lib/collector.d.ts.map +1 -1
  73. package/dist/lib/collector.js +107 -35
  74. package/dist/lib/collector.js.map +1 -1
  75. package/dist/lib/config.d.ts +72 -8
  76. package/dist/lib/config.d.ts.map +1 -1
  77. package/dist/lib/config.js +40 -0
  78. package/dist/lib/config.js.map +1 -1
  79. package/dist/queue/dead-letter.d.ts +26 -0
  80. package/dist/queue/dead-letter.d.ts.map +1 -0
  81. package/dist/queue/dead-letter.js +233 -0
  82. package/dist/queue/dead-letter.js.map +1 -0
  83. package/dist/queue/drain.d.ts +36 -0
  84. package/dist/queue/drain.d.ts.map +1 -0
  85. package/dist/queue/drain.js +170 -0
  86. package/dist/queue/drain.js.map +1 -0
  87. package/dist/queue/flush.d.ts +64 -0
  88. package/dist/queue/flush.d.ts.map +1 -0
  89. package/dist/queue/flush.js +119 -0
  90. package/dist/queue/flush.js.map +1 -0
  91. package/dist/queue/handlers/send-event.d.ts +23 -0
  92. package/dist/queue/handlers/send-event.d.ts.map +1 -0
  93. package/dist/queue/handlers/send-event.js +131 -0
  94. package/dist/queue/handlers/send-event.js.map +1 -0
  95. package/dist/queue/index.d.ts +30 -0
  96. package/dist/queue/index.d.ts.map +1 -0
  97. package/dist/queue/index.js +71 -0
  98. package/dist/queue/index.js.map +1 -0
  99. package/dist/queue/paths.d.ts +40 -0
  100. package/dist/queue/paths.d.ts.map +1 -0
  101. package/dist/queue/paths.js +107 -0
  102. package/dist/queue/paths.js.map +1 -0
  103. package/dist/queue/process-file.d.ts +22 -0
  104. package/dist/queue/process-file.d.ts.map +1 -0
  105. package/dist/queue/process-file.js +257 -0
  106. package/dist/queue/process-file.js.map +1 -0
  107. package/dist/queue/register-handlers.d.ts +26 -0
  108. package/dist/queue/register-handlers.d.ts.map +1 -0
  109. package/dist/queue/register-handlers.js +36 -0
  110. package/dist/queue/register-handlers.js.map +1 -0
  111. package/dist/queue/registry.d.ts +42 -0
  112. package/dist/queue/registry.d.ts.map +1 -0
  113. package/dist/queue/registry.js +36 -0
  114. package/dist/queue/registry.js.map +1 -0
  115. package/dist/queue/snapshot.d.ts +16 -0
  116. package/dist/queue/snapshot.d.ts.map +1 -0
  117. package/dist/queue/snapshot.js +39 -0
  118. package/dist/queue/snapshot.js.map +1 -0
  119. package/dist/queue/spawn.d.ts +15 -0
  120. package/dist/queue/spawn.d.ts.map +1 -0
  121. package/dist/queue/spawn.js +45 -0
  122. package/dist/queue/spawn.js.map +1 -0
  123. package/dist/queue/submit.d.ts +19 -0
  124. package/dist/queue/submit.d.ts.map +1 -0
  125. package/dist/queue/submit.js +94 -0
  126. package/dist/queue/submit.js.map +1 -0
  127. package/dist/queue/types.d.ts +77 -0
  128. package/dist/queue/types.d.ts.map +1 -0
  129. package/dist/queue/types.js +83 -0
  130. package/dist/queue/types.js.map +1 -0
  131. package/dist/queue/worker-log.d.ts +21 -0
  132. package/dist/queue/worker-log.d.ts.map +1 -0
  133. package/dist/queue/worker-log.js +140 -0
  134. package/dist/queue/worker-log.js.map +1 -0
  135. package/package.json +1 -1
@@ -2,12 +2,24 @@
2
2
  /**
3
3
  * IronBee CLI — Collector Client
4
4
  *
5
- * Sends events to the IronBee Collector service.
6
- * Non-blocking, fail-safe never throws, never blocks CLI for more than 3s.
5
+ * Shared HTTP transport for pushing events to the IronBee Collector
6
+ * (`POST {url}/v1/events`). Two callers use it today:
7
7
  *
8
- * Requires collector.url and collector.apiKey in config.
8
+ * - `sendToCollector(entry, …)` — fire-and-forget single-event send used
9
+ * by `appendAction` in the interactive path. Short timeout, resolves on
10
+ * ANY response (status ignored for backward-compat), rejects only on
11
+ * network / timeout errors.
12
+ *
13
+ * - `postEventsBatch(events, cc)` — low-level primitive returning
14
+ * `{ status, body }` so callers can classify the response. Used by the
15
+ * queue `send_event` handler for HTTP-status → TransientError /
16
+ * AuthError / BadRequestBatchError classification (spec §6).
17
+ *
18
+ * Both are no-ops when `IRONBEE_COLLECTOR=false` is set (jest harness).
9
19
  */
10
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.postEventsBatch = postEventsBatch;
22
+ exports.getCollectorTarget = getCollectorTarget;
11
23
  exports.sendToCollector = sendToCollector;
12
24
  const https_1 = require("https");
13
25
  const http_1 = require("http");
@@ -15,59 +27,119 @@ const config_1 = require("./config");
15
27
  const logger_1 = require("./logger");
16
28
  const SEND_TIMEOUT_MS = 3000;
17
29
  const EVENTS_PATH = "/v1/events";
18
- function getCollectorConfig(projectDir) {
19
- const config = (0, config_1.loadConfig)(projectDir);
20
- if (config.collector && config.collector.url && config.collector.apiKey) {
21
- return { url: config.collector.url, apiKey: config.collector.apiKey };
22
- }
23
- return null;
24
- }
25
- async function sendToCollector(entry, _sessionId, projectDir) {
26
- if (process.env.IRONBEE_COLLECTOR === "false") {
27
- return;
28
- }
30
+ /**
31
+ * Low-level transport: POST a JSON array of events to the collector and
32
+ * resolve with the HTTP status + response body. Rejects on network error,
33
+ * connect timeout, or socket timeout. Does NOT throw on non-2xx — callers
34
+ * decide what HTTP status means for their use case.
35
+ */
36
+ async function postEventsBatch(events, target, opts) {
37
+ const timeoutMs = opts?.timeoutMs ?? SEND_TIMEOUT_MS;
29
38
  return new Promise((resolve, reject) => {
30
39
  try {
31
- const collectorConfig = getCollectorConfig(projectDir);
32
- if (!collectorConfig) {
33
- resolve();
34
- return;
35
- }
36
- // entry is already enriched with id/session_id/project_name/timestamp by appendAction.
37
- const event = { ...entry };
38
- const body = JSON.stringify([event]);
39
- const url = new URL(EVENTS_PATH, collectorConfig.url);
40
+ const body = JSON.stringify(events);
41
+ const url = new URL(EVENTS_PATH, target.url);
40
42
  const isHttps = url.protocol === "https:";
41
43
  const doRequest = isHttps ? https_1.request : http_1.request;
42
- const timeout = setTimeout(() => {
43
- logger_1.logger.debug("collector: send timeout");
44
+ const timer = setTimeout(() => {
44
45
  reject(new Error("collector: send timeout"));
45
- }, SEND_TIMEOUT_MS);
46
+ }, timeoutMs);
46
47
  const req = doRequest({
47
48
  hostname: url.hostname,
48
49
  port: url.port || (isHttps ? 443 : 80),
49
- path: url.pathname,
50
+ path: url.pathname + url.search,
50
51
  method: "POST",
51
52
  headers: {
52
53
  "Content-Type": "application/json",
53
54
  "Content-Length": Buffer.byteLength(body),
54
- ...(collectorConfig.apiKey ? { "X-API-Key": collectorConfig.apiKey } : {}),
55
+ ...(target.apiKey ? { "X-API-Key": target.apiKey } : {}),
55
56
  },
56
- timeout: SEND_TIMEOUT_MS,
57
+ timeout: timeoutMs,
57
58
  }, (res) => {
58
- res.on("data", () => { });
59
- res.on("end", () => { clearTimeout(timeout); resolve(); });
60
- res.on("close", () => { clearTimeout(timeout); resolve(); });
59
+ let chunks = "";
60
+ res.setEncoding("utf-8");
61
+ res.on("data", (d) => { chunks += d; });
62
+ res.on("end", () => {
63
+ clearTimeout(timer);
64
+ resolve({ status: res.statusCode ?? 0, body: chunks });
65
+ });
66
+ res.on("close", () => {
67
+ clearTimeout(timer);
68
+ resolve({ status: res.statusCode ?? 0, body: chunks });
69
+ });
61
70
  });
62
- req.on("error", (err) => { clearTimeout(timeout); reject(err); });
63
- req.on("timeout", () => { clearTimeout(timeout); req.destroy(); reject(new Error("collector: request timeout")); });
71
+ req.on("error", (err) => { clearTimeout(timer); reject(err); });
72
+ req.on("timeout", () => { clearTimeout(timer); req.destroy(); reject(new Error("collector: request timeout")); });
64
73
  req.write(body);
65
74
  req.end();
66
75
  }
67
76
  catch (e) {
68
- logger_1.logger.debug(`collector: sendToCollector failed: ${e}`);
69
77
  reject(e instanceof Error ? e : new Error(String(e)));
70
78
  }
71
79
  });
72
80
  }
81
+ /**
82
+ * Resolve the collector target from config, or `null` if disabled.
83
+ *
84
+ * Disabled when ANY of:
85
+ * - `IRONBEE_COLLECTOR=false` env (jest harness escape hatch)
86
+ * - no `collector` config section
87
+ * - `collector.enable: false` explicitly set
88
+ * - `collector.url` missing or empty
89
+ *
90
+ * Otherwise the section is treated as enabled (presence is the opt-in,
91
+ * symmetric with `jobQueue`). `apiKey` is optional — when absent, the
92
+ * `X-API-Key` header is simply omitted, allowing use against an
93
+ * auth-disabled collector.
94
+ */
95
+ function getCollectorTarget(projectDir) {
96
+ if (process.env.IRONBEE_COLLECTOR === "false") {
97
+ return null;
98
+ }
99
+ const config = (0, config_1.loadConfig)(projectDir);
100
+ const section = config.collector;
101
+ if (!section) {
102
+ return null;
103
+ }
104
+ // explicit kill switch — keeps url/apiKey/batchSize in config so the user
105
+ // can flip back on without re-typing them
106
+ if (section.enable === false) {
107
+ return null;
108
+ }
109
+ if (typeof section.url !== "string" || section.url.length === 0) {
110
+ return null;
111
+ }
112
+ return {
113
+ url: section.url,
114
+ apiKey: section.apiKey,
115
+ batchSize: typeof section.batchSize === "number" ? section.batchSize : undefined,
116
+ };
117
+ }
118
+ /**
119
+ * Fire-and-forget single-event send. Resolves on any HTTP response (status is
120
+ * intentionally ignored so a 5xx from the collector does not propagate back
121
+ * into a hook that's writing to `actions.jsonl`). Rejects only on network
122
+ * / timeout errors.
123
+ *
124
+ * Emits a debug-level trace line per attempt to `session.log` (level filter
125
+ * does not gate file writes — see logger.ts) so operators can audit which
126
+ * lifecycle events made it to the collector. The line carries the event id
127
+ * and type to make grep'ing trivial; it does not include payload content.
128
+ */
129
+ async function sendToCollector(entry, _sessionId, projectDir) {
130
+ const target = getCollectorTarget(projectDir);
131
+ if (!target) {
132
+ return;
133
+ }
134
+ const startedAt = Date.now();
135
+ try {
136
+ // entry is already enriched with id/session_id/project_name/timestamp by appendAction.
137
+ await postEventsBatch([entry], target, { timeoutMs: SEND_TIMEOUT_MS });
138
+ logger_1.logger.debug(`collector: posted type=${entry.type} id=${entry.id ?? "?"} in ${Date.now() - startedAt}ms`);
139
+ }
140
+ catch (e) {
141
+ logger_1.logger.debug(`collector: sendToCollector failed type=${entry.type} id=${entry.id ?? "?"}: ${e}`);
142
+ throw e instanceof Error ? e : new Error(String(e));
143
+ }
144
+ }
73
145
  //# sourceMappingURL=collector.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/lib/collector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/lib/collector.ts"],"names":[],"mappings":"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"}
@@ -28,24 +28,68 @@ export interface IronBeeConfig {
28
28
  /** Maximum retry attempts before allowing completion despite failures. */
29
29
  maxRetries?: number;
30
30
  /**
31
- * IronBee Collector configuration for remote event ingestion.
32
- * When set, events are sent to the collector in addition to local storage.
31
+ * IronBee Collector configuration for remote event ingestion. When the
32
+ * section is present and `enable` is not explicitly `false`, events are
33
+ * sent to the collector in addition to local storage.
33
34
  */
34
35
  collector?: {
35
- /** Collector base URL (e.g. "https://service.ironbee.dev") */
36
- url: string;
36
+ /**
37
+ * Master switch. Defaults to `true` whenever this section is present,
38
+ * mirroring `jobQueue.enable`. Set explicitly to `false` to suspend
39
+ * the collector without removing `url` / `apiKey` / `batchSize` —
40
+ * useful for temporarily working offline while keeping the rest of
41
+ * the collector config around.
42
+ */
43
+ enable?: boolean;
44
+ /**
45
+ * Collector base URL (e.g. "https://service.ironbee.dev"). Required
46
+ * for `enable !== false`; the collector is treated as disabled when
47
+ * `url` is missing or empty.
48
+ */
49
+ url?: string;
37
50
  /** API key for authentication (X-API-Key header). Optional if auth is disabled on collector. */
38
51
  apiKey?: string;
52
+ /**
53
+ * Max events per POST in the queue's `send_event` handler. Jobs
54
+ * accumulated in a snapshot are chunked into batches of this size so
55
+ * the collector doesn't reject oversize bodies. Default 100.
56
+ * Set to a higher value if your collector tolerates big bodies.
57
+ */
58
+ batchSize?: number;
39
59
  };
40
60
  /**
41
- * Recording configuration.
42
- * When enabled, each verification cycle requires a browser recording
43
- * (start-recording before browser tools, stop-recording before verdict).
61
+ * Recording enforcement configuration. When enabled, each verification
62
+ * cycle requires a browser recording (start-recording before browser
63
+ * tools, stop-recording before verdict).
64
+ *
65
+ * The presence of this section IS the opt-in signal — `"recording": {}`
66
+ * (or any sub-key) turns enforcement on. Set `enable: false` explicitly
67
+ * to disable while keeping the section around. Section absent → off.
68
+ * Symmetric with `jobQueue` and `collector`.
44
69
  */
45
70
  recording?: {
46
- /** Enable recording enforcement. Default: false. */
47
71
  enable?: boolean;
48
72
  };
73
+ /**
74
+ * Job queue tuning. The presence of this section IS the opt-in signal —
75
+ * adding `"jobQueue": {}` (or any sub-key) enables the queue. To opt out
76
+ * after the section exists, set `enable: false` explicitly.
77
+ *
78
+ * `enable`: master switch. Defaults to `true` when this section is
79
+ * present, `false` when absent. Set explicitly to `false` to disable
80
+ * without removing the rest of the config (e.g. keep your custom
81
+ * `autoFlushSizeBytes` around for later).
82
+ *
83
+ * `autoFlushSizeBytes`: when the live `jobs.jsonl` size meets or exceeds
84
+ * this threshold after a submit, a detached worker is spawned in the
85
+ * background to snapshot and process it — providing mid-session flush
86
+ * without waiting for Stop / SessionEnd. Set to `0` (or a negative value)
87
+ * to disable size-based auto-flush. Default 32768 (32 KB).
88
+ */
89
+ jobQueue?: {
90
+ enable?: boolean;
91
+ autoFlushSizeBytes?: number;
92
+ };
49
93
  /** Allow additional config fields. */
50
94
  [key: string]: unknown;
51
95
  }
@@ -78,4 +122,24 @@ export interface BrowserDevToolsMCPConfig {
78
122
  */
79
123
  export declare function getMcpServerEntry(projectDir?: string): BrowserDevToolsMCPConfig;
80
124
  export declare function getMaxRetries(config: IronBeeConfig): number;
125
+ /**
126
+ * Returns true when the job queue layer is enabled for this project.
127
+ *
128
+ * Rule:
129
+ * - No `jobQueue` section in config → disabled (default-off).
130
+ * - `jobQueue` section present → enabled, unless `enable: false` is set
131
+ * explicitly. Adding any sub-key (e.g. `autoFlushSizeBytes`) implicitly
132
+ * opts in.
133
+ *
134
+ * Used as both a producer-side gate (track-action skips wire construction
135
+ * when off) and a defense-in-depth guard inside `submit()` itself.
136
+ */
137
+ export declare function isJobQueueEnabled(projectDir?: string): boolean;
138
+ /**
139
+ * Returns true when recording enforcement is enabled for this project.
140
+ * Same presence-as-opt-in semantics as `isJobQueueEnabled`: the `recording`
141
+ * section being present in config.json turns enforcement on; set
142
+ * `enable: false` explicitly to suspend without removing the section.
143
+ */
144
+ export declare function isRecordingEnabled(projectDir?: string): boolean;
81
145
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEjC,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,SAAS,CAAC,EAAE;QACR,8DAA8D;QAC9D,GAAG,EAAE,MAAM,CAAC;QACZ,gGAAgG;QAChG,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACR,oDAAoD;QACpD,MAAM,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;IAEF,sCAAsC;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AA6CD,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAiB7D;AAyCD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAarF;AAED,MAAM,WAAW,wBAAwB;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAcD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,wBAAwB,CAuC/E;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAI3D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEjC,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACR;;;;;;WAMG;QACH,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB;;;;WAIG;QACH,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,gGAAgG;QAChG,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;;;WAKG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;IAEF;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;KAC/B,CAAC;IAEF,sCAAsC;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AA6CD,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAiB7D;AAyCD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAarF;AAED,MAAM,WAAW,wBAAwB;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAcD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,wBAAwB,CAuC/E;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAI3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAG9D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAG/D"}
@@ -13,6 +13,8 @@ exports.loadConfig = loadConfig;
13
13
  exports.requiresVerification = requiresVerification;
14
14
  exports.getMcpServerEntry = getMcpServerEntry;
15
15
  exports.getMaxRetries = getMaxRetries;
16
+ exports.isJobQueueEnabled = isJobQueueEnabled;
17
+ exports.isRecordingEnabled = isRecordingEnabled;
16
18
  const fs_1 = require("fs");
17
19
  const path_1 = require("path");
18
20
  const os_1 = require("os");
@@ -191,4 +193,42 @@ function getMaxRetries(config) {
191
193
  ? config.maxRetries
192
194
  : DEFAULT_MAX_RETRIES;
193
195
  }
196
+ /**
197
+ * Returns true when the job queue layer is enabled for this project.
198
+ *
199
+ * Rule:
200
+ * - No `jobQueue` section in config → disabled (default-off).
201
+ * - `jobQueue` section present → enabled, unless `enable: false` is set
202
+ * explicitly. Adding any sub-key (e.g. `autoFlushSizeBytes`) implicitly
203
+ * opts in.
204
+ *
205
+ * Used as both a producer-side gate (track-action skips wire construction
206
+ * when off) and a defense-in-depth guard inside `submit()` itself.
207
+ */
208
+ function isJobQueueEnabled(projectDir) {
209
+ const config = loadConfig(projectDir);
210
+ return isPresenceEnabled(config.jobQueue);
211
+ }
212
+ /**
213
+ * Returns true when recording enforcement is enabled for this project.
214
+ * Same presence-as-opt-in semantics as `isJobQueueEnabled`: the `recording`
215
+ * section being present in config.json turns enforcement on; set
216
+ * `enable: false` explicitly to suspend without removing the section.
217
+ */
218
+ function isRecordingEnabled(projectDir) {
219
+ const config = loadConfig(projectDir);
220
+ return isPresenceEnabled(config.recording);
221
+ }
222
+ /**
223
+ * Shared "section present + not explicitly disabled" check used by the
224
+ * three master-switch helpers (`jobQueue`, `recording`, and inline by
225
+ * `getCollectorTarget`). Defensive against malformed config values
226
+ * (null / non-object / array) — those are treated as disabled.
227
+ */
228
+ function isPresenceEnabled(section) {
229
+ if (section === undefined || section === null || typeof section !== "object" || Array.isArray(section)) {
230
+ return false;
231
+ }
232
+ return section.enable !== false;
233
+ }
194
234
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * IronBee CLI — Dead Letter Writer + Rotation
3
+ *
4
+ * See docs/job-queue.md §6.1 (entry shape), §6.2 (rotation + retention).
5
+ */
6
+ import { DeadLetterEntry, Job } from "./types";
7
+ export interface DeadLetterInput {
8
+ projectDir: string;
9
+ sessionId: string;
10
+ sourceFile: string;
11
+ }
12
+ /**
13
+ * Append a parsed-job dead-letter entry. Enforces the 4 KB line ceiling via a
14
+ * cascade of three truncation fallbacks. The last fallback always fits — it
15
+ * replaces the entire entry with a minimal overflow marker — so the atomic
16
+ * append invariant (§6.1) always holds.
17
+ */
18
+ export declare function deadLetterParsed(input: DeadLetterInput, job: Job, category: string): void;
19
+ /**
20
+ * Append a parse-error dead-letter entry. The raw line is truncated to 512
21
+ * chars and ASCII control chars are escaped.
22
+ */
23
+ export declare function deadLetterParseError(input: DeadLetterInput, raw: string, category: string): void;
24
+ /** Exposed for tests and CLI tooling. */
25
+ export declare function readDeadLetterEntries(projectDir: string, sessionId: string): DeadLetterEntry[];
26
+ //# sourceMappingURL=dead-letter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-letter.d.ts","sourceRoot":"","sources":["../../src/queue/dead-letter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiBH,OAAO,EAIH,eAAe,EAGf,GAAG,EAEN,MAAM,SAAS,CAAC;AAGjB,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CA4DzF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYhG;AAyHD,yCAAyC;AACzC,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,CAoB9F"}
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ /**
3
+ * IronBee CLI — Dead Letter Writer + Rotation
4
+ *
5
+ * See docs/job-queue.md §6.1 (entry shape), §6.2 (rotation + retention).
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.deadLetterParsed = deadLetterParsed;
9
+ exports.deadLetterParseError = deadLetterParseError;
10
+ exports.readDeadLetterEntries = readDeadLetterEntries;
11
+ const fs_1 = require("fs");
12
+ const path_1 = require("path");
13
+ const crypto_1 = require("crypto");
14
+ const logger_1 = require("../lib/logger");
15
+ const types_1 = require("./types");
16
+ const paths_1 = require("./paths");
17
+ /**
18
+ * Append a parsed-job dead-letter entry. Enforces the 4 KB line ceiling via a
19
+ * cascade of three truncation fallbacks. The last fallback always fits — it
20
+ * replaces the entire entry with a minimal overflow marker — so the atomic
21
+ * append invariant (§6.1) always holds.
22
+ */
23
+ function deadLetterParsed(input, job, category) {
24
+ const filename = (0, path_1.basename)(input.sourceFile);
25
+ const receivedAt = new Date().toISOString();
26
+ const entryId = (0, crypto_1.randomUUID)();
27
+ // Fallback 0: the happy case — full entry.
28
+ let entry = {
29
+ id: entryId,
30
+ received_at: receivedAt,
31
+ source_file: filename,
32
+ category,
33
+ original: job,
34
+ };
35
+ let line = JSON.stringify(entry) + "\n";
36
+ if (Buffer.byteLength(line, "utf-8") > types_1.MAX_LINE_BYTES) {
37
+ // Fallback 1: drop `original.data`.
38
+ entry = {
39
+ ...entry,
40
+ original: {
41
+ id: job.id,
42
+ type: job.type,
43
+ created_at: job.created_at,
44
+ data: { __truncated__: true },
45
+ },
46
+ };
47
+ line = JSON.stringify(entry) + "\n";
48
+ }
49
+ if (Buffer.byteLength(line, "utf-8") > types_1.MAX_LINE_BYTES) {
50
+ // Fallback 2: also truncate the category string.
51
+ entry = {
52
+ ...entry,
53
+ category: truncateString(category, 256),
54
+ };
55
+ line = JSON.stringify(entry) + "\n";
56
+ }
57
+ if (Buffer.byteLength(line, "utf-8") > types_1.MAX_LINE_BYTES) {
58
+ // Fallback 3: minimal overflow marker. Preserves identity + triage
59
+ // pointer (job id, source_file) but drops everything else.
60
+ const minimal = {
61
+ id: entryId,
62
+ received_at: receivedAt,
63
+ source_file: truncateString(filename, 128),
64
+ category: "overflow",
65
+ original: { id: job.id, type: truncateString(job.type, 64) },
66
+ __truncated__: true,
67
+ };
68
+ line = JSON.stringify(minimal) + "\n";
69
+ // Absolute last resort — if even this exceeds 4 KB (which would
70
+ // require a pathologically long source_file name the OS likely
71
+ // rejected anyway), hard-truncate the byte array and append a "\n".
72
+ if (Buffer.byteLength(line, "utf-8") > types_1.MAX_LINE_BYTES) {
73
+ const raw = Buffer.from(line, "utf-8").subarray(0, types_1.MAX_LINE_BYTES - 1);
74
+ line = raw.toString("utf-8") + "\n";
75
+ }
76
+ }
77
+ writeDeadLetterLine(input.projectDir, input.sessionId, line);
78
+ }
79
+ /**
80
+ * Append a parse-error dead-letter entry. The raw line is truncated to 512
81
+ * chars and ASCII control chars are escaped.
82
+ */
83
+ function deadLetterParseError(input, raw, category) {
84
+ const filename = (0, path_1.basename)(input.sourceFile);
85
+ const sanitized = escapeControls(raw).slice(0, types_1.DEAD_LETTER_RAW_MAX);
86
+ const entry = {
87
+ id: (0, crypto_1.randomUUID)(),
88
+ received_at: new Date().toISOString(),
89
+ source_file: filename,
90
+ category,
91
+ raw: sanitized,
92
+ };
93
+ const line = JSON.stringify(entry) + "\n";
94
+ writeDeadLetterLine(input.projectDir, input.sessionId, line);
95
+ }
96
+ function writeDeadLetterLine(projectDir, sessionId, line) {
97
+ const dir = (0, paths_1.queueDir)(projectDir, sessionId);
98
+ (0, fs_1.mkdirSync)(dir, { recursive: true, mode: 0o700 });
99
+ const path = (0, paths_1.deadLetterFile)(projectDir, sessionId);
100
+ const flags = fs_1.constants.O_CREAT
101
+ | fs_1.constants.O_WRONLY
102
+ | fs_1.constants.O_APPEND
103
+ | (typeof fs_1.constants.O_NOFOLLOW === "number" ? fs_1.constants.O_NOFOLLOW : 0);
104
+ const fd = (0, fs_1.openSync)(path, flags, 0o600);
105
+ try {
106
+ const bytes = Buffer.from(line, "utf-8");
107
+ (0, fs_1.writeSync)(fd, bytes, 0, bytes.length);
108
+ }
109
+ finally {
110
+ try {
111
+ (0, fs_1.closeSync)(fd);
112
+ }
113
+ catch {
114
+ // ignore
115
+ }
116
+ }
117
+ rotateIfNeeded(projectDir, sessionId);
118
+ }
119
+ function rotateIfNeeded(projectDir, sessionId) {
120
+ // Size-only rotation — `stat()` is O(1), appends stay sub-ms even with a
121
+ // near-threshold file. A line-count check would require reading the whole
122
+ // file on every append, which defeats the purpose of append-only writes.
123
+ // Practical dead-letter entries are 400–1500 bytes, so 10 MB naturally
124
+ // bounds line count to ~7k–25k.
125
+ const path = (0, paths_1.deadLetterFile)(projectDir, sessionId);
126
+ let size;
127
+ try {
128
+ size = (0, fs_1.statSync)(path).size;
129
+ }
130
+ catch {
131
+ return;
132
+ }
133
+ if (size <= types_1.DEAD_LETTER_ROTATE_BYTES) {
134
+ return;
135
+ }
136
+ const dir = (0, paths_1.queueDir)(projectDir, sessionId);
137
+ const rotated = (0, path_1.join)(dir, `dead-letter-${(0, crypto_1.randomUUID)()}.jsonl`);
138
+ try {
139
+ (0, fs_1.renameSync)(path, rotated);
140
+ }
141
+ catch (e) {
142
+ const err = e;
143
+ if (err.code === "ENOENT") {
144
+ // another worker already rotated; nothing to do
145
+ return;
146
+ }
147
+ // Keep the writer robust — non-ENOENT failure (EACCES, EIO, EXDEV, …)
148
+ // means the dead-letter file keeps growing past the 10 MB target
149
+ // until the cause is fixed. Surface via debug so the operator has a
150
+ // trace to follow instead of a silent slow-grow.
151
+ logger_1.logger.debug(`dead-letter rotation failed on ${path}: ${err.code ?? err.message}`);
152
+ return;
153
+ }
154
+ enforceRetention(projectDir, sessionId);
155
+ }
156
+ function enforceRetention(projectDir, sessionId) {
157
+ const dir = (0, paths_1.queueDir)(projectDir, sessionId);
158
+ let entries;
159
+ try {
160
+ entries = (0, fs_1.readdirSync)(dir);
161
+ }
162
+ catch {
163
+ return;
164
+ }
165
+ const rotated = [];
166
+ for (const name of entries) {
167
+ if (!paths_1.DEAD_LETTER_ROTATED_REGEX.test(name)) {
168
+ continue;
169
+ }
170
+ const full = (0, path_1.join)(dir, name);
171
+ try {
172
+ const st = (0, fs_1.statSync)(full);
173
+ rotated.push({ path: full, mtimeMs: st.mtimeMs });
174
+ }
175
+ catch {
176
+ // ignore
177
+ }
178
+ }
179
+ if (rotated.length <= types_1.DEAD_LETTER_RETAIN_COUNT) {
180
+ return;
181
+ }
182
+ // sort newest first; unlink anything past the keep count
183
+ rotated.sort((a, b) => b.mtimeMs - a.mtimeMs);
184
+ for (let i = types_1.DEAD_LETTER_RETAIN_COUNT; i < rotated.length; i++) {
185
+ try {
186
+ (0, fs_1.unlinkSync)(rotated[i].path);
187
+ }
188
+ catch {
189
+ // ignore — best-effort
190
+ }
191
+ }
192
+ }
193
+ function escapeControls(s) {
194
+ let out = "";
195
+ for (let i = 0; i < s.length; i++) {
196
+ const code = s.charCodeAt(i);
197
+ if (code < 0x20 || code === 0x7f) {
198
+ out += `\\x${code.toString(16).padStart(2, "0")}`;
199
+ }
200
+ else {
201
+ out += s[i];
202
+ }
203
+ }
204
+ return out;
205
+ }
206
+ function truncateString(s, max) {
207
+ return s.length <= max ? s : s.slice(0, max) + "…";
208
+ }
209
+ /** Exposed for tests and CLI tooling. */
210
+ function readDeadLetterEntries(projectDir, sessionId) {
211
+ const path = (0, paths_1.deadLetterFile)(projectDir, sessionId);
212
+ let content;
213
+ try {
214
+ content = (0, fs_1.readFileSync)(path, "utf-8");
215
+ }
216
+ catch {
217
+ return [];
218
+ }
219
+ const out = [];
220
+ for (const line of content.split("\n")) {
221
+ if (line.length === 0) {
222
+ continue;
223
+ }
224
+ try {
225
+ out.push(JSON.parse(line));
226
+ }
227
+ catch {
228
+ // skip unparseable dead-letter lines — shouldn't happen in practice
229
+ }
230
+ }
231
+ return out;
232
+ }
233
+ //# sourceMappingURL=dead-letter.js.map