@ironbee-ai/cli 0.13.0 → 0.14.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.
- package/CHANGELOG.md +6 -0
- package/README.md +9 -0
- package/dist/clients/claude/hooks/activity-start.d.ts.map +1 -1
- package/dist/clients/claude/hooks/activity-start.js +4 -0
- package/dist/clients/claude/hooks/activity-start.js.map +1 -1
- package/dist/clients/claude/hooks/session-start.d.ts.map +1 -1
- package/dist/clients/claude/hooks/session-start.js +4 -0
- package/dist/clients/claude/hooks/session-start.js.map +1 -1
- package/dist/clients/claude/index.d.ts +10 -0
- package/dist/clients/claude/index.d.ts.map +1 -1
- package/dist/clients/claude/index.js +105 -0
- package/dist/clients/claude/index.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +1 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/otel.d.ts +20 -0
- package/dist/commands/otel.d.ts.map +1 -0
- package/dist/commands/otel.js +132 -0
- package/dist/commands/otel.js.map +1 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +47 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +57 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/event.d.ts +112 -0
- package/dist/lib/event.d.ts.map +1 -1
- package/dist/lib/event.js +1 -0
- package/dist/lib/event.js.map +1 -1
- package/dist/lib/gitignore.d.ts.map +1 -1
- package/dist/lib/gitignore.js +6 -0
- package/dist/lib/gitignore.js.map +1 -1
- package/dist/lib/version.d.ts +5 -0
- package/dist/lib/version.d.ts.map +1 -1
- package/dist/lib/version.js +5 -0
- package/dist/lib/version.js.map +1 -1
- package/dist/otel/collector.d.ts +66 -0
- package/dist/otel/collector.d.ts.map +1 -0
- package/dist/otel/collector.js +317 -0
- package/dist/otel/collector.js.map +1 -0
- package/dist/otel/context/build.d.ts +37 -0
- package/dist/otel/context/build.d.ts.map +1 -0
- package/dist/otel/context/build.js +103 -0
- package/dist/otel/context/build.js.map +1 -0
- package/dist/otel/context/classify.d.ts +40 -0
- package/dist/otel/context/classify.d.ts.map +1 -0
- package/dist/otel/context/classify.js +228 -0
- package/dist/otel/context/classify.js.map +1 -0
- package/dist/otel/context/extract.d.ts +39 -0
- package/dist/otel/context/extract.d.ts.map +1 -0
- package/dist/otel/context/extract.js +76 -0
- package/dist/otel/context/extract.js.map +1 -0
- package/dist/otel/context/markers.d.ts +37 -0
- package/dist/otel/context/markers.d.ts.map +1 -0
- package/dist/otel/context/markers.js +179 -0
- package/dist/otel/context/markers.js.map +1 -0
- package/dist/otel/context/util.d.ts +15 -0
- package/dist/otel/context/util.d.ts.map +1 -0
- package/dist/otel/context/util.js +33 -0
- package/dist/otel/context/util.js.map +1 -0
- package/dist/otel/daemon/ensure.d.ts +52 -0
- package/dist/otel/daemon/ensure.d.ts.map +1 -0
- package/dist/otel/daemon/ensure.js +226 -0
- package/dist/otel/daemon/ensure.js.map +1 -0
- package/dist/otel/daemon/forward.d.ts +47 -0
- package/dist/otel/daemon/forward.d.ts.map +1 -0
- package/dist/otel/daemon/forward.js +0 -0
- package/dist/otel/daemon/forward.js.map +1 -0
- package/dist/otel/daemon/paths.d.ts +24 -0
- package/dist/otel/daemon/paths.d.ts.map +1 -0
- package/dist/otel/daemon/paths.js +47 -0
- package/dist/otel/daemon/paths.js.map +1 -0
- package/dist/otel/daemon/process.d.ts +21 -0
- package/dist/otel/daemon/process.d.ts.map +1 -0
- package/dist/otel/daemon/process.js +149 -0
- package/dist/otel/daemon/process.js.map +1 -0
- package/dist/otel/daemon/reprocess.d.ts +27 -0
- package/dist/otel/daemon/reprocess.d.ts.map +1 -0
- package/dist/otel/daemon/reprocess.js +112 -0
- package/dist/otel/daemon/reprocess.js.map +1 -0
- package/dist/otel/log-handler.d.ts +37 -0
- package/dist/otel/log-handler.d.ts.map +1 -0
- package/dist/otel/log-handler.js +332 -0
- package/dist/otel/log-handler.js.map +1 -0
- package/dist/otel/metric-handler.d.ts +12 -0
- package/dist/otel/metric-handler.d.ts.map +1 -0
- package/dist/otel/metric-handler.js +18 -0
- package/dist/otel/metric-handler.js.map +1 -0
- package/dist/otel/trace-handler.d.ts +12 -0
- package/dist/otel/trace-handler.d.ts.map +1 -0
- package/dist/otel/trace-handler.js +18 -0
- package/dist/otel/trace-handler.js.map +1 -0
- package/dist/otel/types.d.ts +105 -0
- package/dist/otel/types.d.ts.map +1 -0
- package/dist/otel/types.js +15 -0
- package/dist/otel/types.js.map +1 -0
- package/dist/tui/config/schema.d.ts.map +1 -1
- package/dist/tui/config/schema.js +44 -0
- package/dist/tui/config/schema.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IronBee — OTEL context classifier byte helpers.
|
|
3
|
+
*
|
|
4
|
+
* Byte counts are the trustworthy unit of the `session_context` breakdown
|
|
5
|
+
* (token density varies by content type). UTF-8 byte length, computed
|
|
6
|
+
* defensively so a malformed node never throws (returns 0 instead).
|
|
7
|
+
*/
|
|
8
|
+
/** UTF-8 byte length of a string. */
|
|
9
|
+
export declare function byteLen(s: string): number;
|
|
10
|
+
/**
|
|
11
|
+
* UTF-8 byte length of `JSON.stringify(node)`. `undefined` / unserializable
|
|
12
|
+
* nodes (functions, symbols) count as 0 rather than throwing.
|
|
13
|
+
*/
|
|
14
|
+
export declare function jsonBytes(node: unknown): number;
|
|
15
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/otel/context/util.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,qCAAqC;AACrC,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAW/C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* IronBee — OTEL context classifier byte helpers.
|
|
4
|
+
*
|
|
5
|
+
* Byte counts are the trustworthy unit of the `session_context` breakdown
|
|
6
|
+
* (token density varies by content type). UTF-8 byte length, computed
|
|
7
|
+
* defensively so a malformed node never throws (returns 0 instead).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.byteLen = byteLen;
|
|
11
|
+
exports.jsonBytes = jsonBytes;
|
|
12
|
+
/** UTF-8 byte length of a string. */
|
|
13
|
+
function byteLen(s) {
|
|
14
|
+
return Buffer.byteLength(s, "utf8");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* UTF-8 byte length of `JSON.stringify(node)`. `undefined` / unserializable
|
|
18
|
+
* nodes (functions, symbols) count as 0 rather than throwing.
|
|
19
|
+
*/
|
|
20
|
+
function jsonBytes(node) {
|
|
21
|
+
if (node === undefined) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
let s;
|
|
25
|
+
try {
|
|
26
|
+
s = JSON.stringify(node);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
return typeof s === "string" ? byteLen(s) : 0;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/otel/context/util.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAGH,0BAEC;AAMD,8BAWC;AApBD,qCAAqC;AACrC,SAAgB,OAAO,CAAC,CAAS;IAC7B,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,SAAgB,SAAS,CAAC,IAAa;IACnC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACrB,OAAO,CAAC,CAAC;IACb,CAAC;IACD,IAAI,CAAqB,CAAC;IAC1B,IAAI,CAAC;QACD,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,CAAC,CAAC;IACb,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IronBee — OTEL collector daemon liveness `ensure` (+ version self-replace)
|
|
3
|
+
*
|
|
4
|
+
* `ensureOTELCollector` is the fire-and-forget helper hooks call to make sure a
|
|
5
|
+
* current daemon is running. It probes `/health`, then either uses the running
|
|
6
|
+
* daemon, spawns one, or replaces a stale-version one. It must never block the
|
|
7
|
+
* host hook's critical path and never throw.
|
|
8
|
+
*
|
|
9
|
+
* Singleton arbitration is the OS port bind (see `collector.ts`); this module
|
|
10
|
+
* only decides whether to *attempt* a spawn. The version-compare decision is
|
|
11
|
+
* isolated in {@link decideEnsureAction} for unit testing.
|
|
12
|
+
*/
|
|
13
|
+
import { OTELHealth } from "../types";
|
|
14
|
+
/** Result of probing the daemon's `/health`. */
|
|
15
|
+
export type HealthProbe = {
|
|
16
|
+
kind: "ok";
|
|
17
|
+
health: OTELHealth;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "unreachable";
|
|
20
|
+
} | {
|
|
21
|
+
kind: "foreign";
|
|
22
|
+
};
|
|
23
|
+
/** What `ensure` should do after probing. */
|
|
24
|
+
export type EnsureDecision = "disabled" | "use-existing" | "spawn" | "replace" | "foreign";
|
|
25
|
+
/**
|
|
26
|
+
* Pure decision: given whether the feature is enabled, the health probe, and
|
|
27
|
+
* our own CLI version, decide the action. Isolated for unit testing.
|
|
28
|
+
*
|
|
29
|
+
* - feature off → `disabled`
|
|
30
|
+
* - nothing on the port → `spawn`
|
|
31
|
+
* - a foreign listener → `foreign` (warn + stand down)
|
|
32
|
+
* - running version < mine → `replace` (newest build wins)
|
|
33
|
+
* - running version >= mine → `use-existing`
|
|
34
|
+
*/
|
|
35
|
+
export declare function decideEnsureAction(opts: {
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
probe: HealthProbe;
|
|
38
|
+
myVersion: string;
|
|
39
|
+
}): EnsureDecision;
|
|
40
|
+
/** GET `/health` and classify the response. Never throws / never rejects. */
|
|
41
|
+
export declare function fetchHealth(port: number, host?: string, timeoutMs?: number): Promise<HealthProbe>;
|
|
42
|
+
/** POST `/admin/shutdown` (best-effort; resolves regardless of outcome). */
|
|
43
|
+
export declare function requestShutdown(port: number, host?: string, timeoutMs?: number): Promise<void>;
|
|
44
|
+
/** POST `/admin/reprocess` (best-effort; resolves regardless of outcome). */
|
|
45
|
+
export declare function requestReprocess(port: number, host?: string, timeoutMs?: number): Promise<void>;
|
|
46
|
+
export declare function spawnDaemon(port: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* Ensure a current OTEL collector daemon is running for this machine.
|
|
49
|
+
* Fire-and-forget, non-blocking, never throws — safe on a hook's hot path.
|
|
50
|
+
*/
|
|
51
|
+
export declare function ensureOTELCollector(projectDir?: string): Promise<void>;
|
|
52
|
+
//# sourceMappingURL=ensure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure.d.ts","sourceRoot":"","sources":["../../../src/otel/daemon/ensure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,OAAO,EAAE,UAAU,EAAqB,MAAM,UAAU,CAAC;AAQzD,gDAAgD;AAChD,MAAM,MAAM,WAAW,GACjB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAE1B,6CAA6C;AAC7C,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAE3F;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACrB,GAAG,cAAc,CAWjB;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CACvB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAqB,EAC3B,SAAS,GAAE,MAAyB,GACrC,OAAO,CAAC,WAAW,CAAC,CAoCtB;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAqB,EAC3B,SAAS,GAAE,MAAyB,GACrC,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAqB,EAC3B,SAAS,GAAE,MAAyB,GACrC,OAAO,CAAC,IAAI,CAAC,CAoBf;AA2CD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiB9C;AAMD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiC5E"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* IronBee — OTEL collector daemon liveness `ensure` (+ version self-replace)
|
|
4
|
+
*
|
|
5
|
+
* `ensureOTELCollector` is the fire-and-forget helper hooks call to make sure a
|
|
6
|
+
* current daemon is running. It probes `/health`, then either uses the running
|
|
7
|
+
* daemon, spawns one, or replaces a stale-version one. It must never block the
|
|
8
|
+
* host hook's critical path and never throw.
|
|
9
|
+
*
|
|
10
|
+
* Singleton arbitration is the OS port bind (see `collector.ts`); this module
|
|
11
|
+
* only decides whether to *attempt* a spawn. The version-compare decision is
|
|
12
|
+
* isolated in {@link decideEnsureAction} for unit testing.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.decideEnsureAction = decideEnsureAction;
|
|
16
|
+
exports.fetchHealth = fetchHealth;
|
|
17
|
+
exports.requestShutdown = requestShutdown;
|
|
18
|
+
exports.requestReprocess = requestReprocess;
|
|
19
|
+
exports.spawnDaemon = spawnDaemon;
|
|
20
|
+
exports.ensureOTELCollector = ensureOTELCollector;
|
|
21
|
+
const http_1 = require("http");
|
|
22
|
+
const child_process_1 = require("child_process");
|
|
23
|
+
const fs_1 = require("fs");
|
|
24
|
+
const os_1 = require("os");
|
|
25
|
+
const path_1 = require("path");
|
|
26
|
+
const config_1 = require("../../lib/config");
|
|
27
|
+
const version_1 = require("../../lib/version");
|
|
28
|
+
const logger_1 = require("../../lib/logger");
|
|
29
|
+
const types_1 = require("../types");
|
|
30
|
+
const DEFAULT_HOST = "127.0.0.1";
|
|
31
|
+
/** Health-probe timeout — tiny so a hook never blocks on it. */
|
|
32
|
+
const PROBE_TIMEOUT_MS = 300;
|
|
33
|
+
/** Brief wait after a stale daemon's shutdown before spawning its replacement. */
|
|
34
|
+
const REPLACE_PORT_RELEASE_MS = 400;
|
|
35
|
+
/**
|
|
36
|
+
* Pure decision: given whether the feature is enabled, the health probe, and
|
|
37
|
+
* our own CLI version, decide the action. Isolated for unit testing.
|
|
38
|
+
*
|
|
39
|
+
* - feature off → `disabled`
|
|
40
|
+
* - nothing on the port → `spawn`
|
|
41
|
+
* - a foreign listener → `foreign` (warn + stand down)
|
|
42
|
+
* - running version < mine → `replace` (newest build wins)
|
|
43
|
+
* - running version >= mine → `use-existing`
|
|
44
|
+
*/
|
|
45
|
+
function decideEnsureAction(opts) {
|
|
46
|
+
if (!opts.enabled) {
|
|
47
|
+
return "disabled";
|
|
48
|
+
}
|
|
49
|
+
if (opts.probe.kind === "unreachable") {
|
|
50
|
+
return "spawn";
|
|
51
|
+
}
|
|
52
|
+
if (opts.probe.kind === "foreign") {
|
|
53
|
+
return "foreign";
|
|
54
|
+
}
|
|
55
|
+
return (0, version_1.compareVersions)(opts.probe.health.version, opts.myVersion) < 0 ? "replace" : "use-existing";
|
|
56
|
+
}
|
|
57
|
+
/** GET `/health` and classify the response. Never throws / never rejects. */
|
|
58
|
+
function fetchHealth(port, host = DEFAULT_HOST, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
let settled = false;
|
|
61
|
+
const done = (p) => {
|
|
62
|
+
if (settled) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
settled = true;
|
|
66
|
+
resolve(p);
|
|
67
|
+
};
|
|
68
|
+
const req = (0, http_1.request)({ host, port, path: "/health", method: "GET", timeout: timeoutMs }, (res) => {
|
|
69
|
+
let body = "";
|
|
70
|
+
res.setEncoding("utf-8");
|
|
71
|
+
res.on("data", (d) => { body += d; });
|
|
72
|
+
res.on("end", () => {
|
|
73
|
+
try {
|
|
74
|
+
const parsed = JSON.parse(body);
|
|
75
|
+
if (parsed !== null && typeof parsed === "object"
|
|
76
|
+
&& parsed.service === types_1.OTEL_SERVICE_NAME
|
|
77
|
+
&& typeof parsed.version === "string") {
|
|
78
|
+
done({ kind: "ok", health: parsed });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// fall through — not our JSON shape
|
|
84
|
+
}
|
|
85
|
+
done({ kind: "foreign" });
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
req.on("error", () => { done({ kind: "unreachable" }); });
|
|
89
|
+
req.on("timeout", () => { req.destroy(); done({ kind: "unreachable" }); });
|
|
90
|
+
req.end();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/** POST `/admin/shutdown` (best-effort; resolves regardless of outcome). */
|
|
94
|
+
function requestShutdown(port, host = DEFAULT_HOST, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
let settled = false;
|
|
97
|
+
const done = () => {
|
|
98
|
+
if (!settled) {
|
|
99
|
+
settled = true;
|
|
100
|
+
resolve();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const req = (0, http_1.request)({ host, port, path: "/admin/shutdown", method: "POST", timeout: timeoutMs }, (res) => {
|
|
104
|
+
res.on("data", () => { });
|
|
105
|
+
res.on("end", done);
|
|
106
|
+
});
|
|
107
|
+
req.on("error", done);
|
|
108
|
+
req.on("timeout", () => { req.destroy(); done(); });
|
|
109
|
+
req.end();
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** POST `/admin/reprocess` (best-effort; resolves regardless of outcome). */
|
|
113
|
+
function requestReprocess(port, host = DEFAULT_HOST, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
let settled = false;
|
|
116
|
+
const done = () => {
|
|
117
|
+
if (!settled) {
|
|
118
|
+
settled = true;
|
|
119
|
+
resolve();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const req = (0, http_1.request)({ host, port, path: "/admin/reprocess", method: "POST", timeout: timeoutMs }, (res) => {
|
|
123
|
+
res.on("data", () => { });
|
|
124
|
+
res.on("end", done);
|
|
125
|
+
});
|
|
126
|
+
req.on("error", done);
|
|
127
|
+
req.on("timeout", () => { req.destroy(); done(); });
|
|
128
|
+
req.end();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/** Resolve how to re-invoke the CLI for a detached child (mirrors queue/spawn). */
|
|
132
|
+
function resolveInvocation() {
|
|
133
|
+
const override = process.env.IRONBEE_BIN;
|
|
134
|
+
if (override) {
|
|
135
|
+
return { command: override, args: [] };
|
|
136
|
+
}
|
|
137
|
+
const argv0 = process.argv[0];
|
|
138
|
+
const argv1 = process.argv[1] ?? "";
|
|
139
|
+
if (argv1.endsWith("index.js") || argv1.endsWith("index.ts")) {
|
|
140
|
+
return { command: argv0, args: [argv1] };
|
|
141
|
+
}
|
|
142
|
+
return { command: "ironbee", args: [] };
|
|
143
|
+
}
|
|
144
|
+
/** Spawn a detached `ironbee otel run --port <port>`. Returns immediately. */
|
|
145
|
+
/** Cap on the daemon log before a startup truncate (single-generation rotation). */
|
|
146
|
+
const DAEMON_LOG_MAX_BYTES = 5 * 1024 * 1024;
|
|
147
|
+
/**
|
|
148
|
+
* Open `~/.ironbee/otel/daemon.log` for the detached daemon's stdout/stderr, so
|
|
149
|
+
* the otherwise-invisible daemon (forward results, collector rejections, errors)
|
|
150
|
+
* is observable. Truncates past {@link DAEMON_LOG_MAX_BYTES}. Returns `"ignore"`
|
|
151
|
+
* (discard) when the log can't be opened — never blocks the spawn.
|
|
152
|
+
*/
|
|
153
|
+
function openDaemonLogTarget() {
|
|
154
|
+
try {
|
|
155
|
+
const dir = (0, path_1.join)((0, os_1.homedir)(), ".ironbee", "otel");
|
|
156
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
157
|
+
const logPath = (0, path_1.join)(dir, "daemon.log");
|
|
158
|
+
let truncate = false;
|
|
159
|
+
try {
|
|
160
|
+
truncate = (0, fs_1.statSync)(logPath).size > DAEMON_LOG_MAX_BYTES;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// no existing log — append-open creates it
|
|
164
|
+
}
|
|
165
|
+
return (0, fs_1.openSync)(logPath, truncate ? "w" : "a");
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return "ignore";
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function spawnDaemon(port) {
|
|
172
|
+
const inv = resolveInvocation();
|
|
173
|
+
const logTarget = openDaemonLogTarget();
|
|
174
|
+
const child = (0, child_process_1.spawn)(inv.command, [...inv.args, "otel", "run", "--port", String(port)], { detached: true, stdio: ["ignore", logTarget, logTarget], env: process.env });
|
|
175
|
+
child.unref();
|
|
176
|
+
if (typeof logTarget === "number") {
|
|
177
|
+
// The child holds its own dup'd fd; release the parent's copy.
|
|
178
|
+
try {
|
|
179
|
+
(0, fs_1.closeSync)(logTarget);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// already closed / race — fine
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function delay(ms) {
|
|
187
|
+
return new Promise((resolve) => { setTimeout(resolve, ms); });
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Ensure a current OTEL collector daemon is running for this machine.
|
|
191
|
+
* Fire-and-forget, non-blocking, never throws — safe on a hook's hot path.
|
|
192
|
+
*/
|
|
193
|
+
async function ensureOTELCollector(projectDir) {
|
|
194
|
+
try {
|
|
195
|
+
const config = (0, config_1.loadConfig)(projectDir);
|
|
196
|
+
if (!(0, config_1.isOTELEnabled)(config)) {
|
|
197
|
+
return; // disabled short-circuit — no probe, no spawn
|
|
198
|
+
}
|
|
199
|
+
const port = (0, config_1.getOTELPort)(config);
|
|
200
|
+
const probe = await fetchHealth(port);
|
|
201
|
+
const decision = decideEnsureAction({
|
|
202
|
+
enabled: true,
|
|
203
|
+
probe,
|
|
204
|
+
myVersion: (0, version_1.getLocalVersion)(),
|
|
205
|
+
});
|
|
206
|
+
switch (decision) {
|
|
207
|
+
case "spawn":
|
|
208
|
+
spawnDaemon(port);
|
|
209
|
+
break;
|
|
210
|
+
case "replace":
|
|
211
|
+
await requestShutdown(port);
|
|
212
|
+
await delay(REPLACE_PORT_RELEASE_MS);
|
|
213
|
+
spawnDaemon(port);
|
|
214
|
+
break;
|
|
215
|
+
case "foreign":
|
|
216
|
+
logger_1.logger.warn(`otel: a non-ironbee service is listening on ${DEFAULT_HOST}:${port}; OTEL collector not started`);
|
|
217
|
+
break;
|
|
218
|
+
default:
|
|
219
|
+
break; // use-existing / disabled → nothing
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
logger_1.logger.debug(`otel: ensureOTELCollector failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=ensure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure.js","sourceRoot":"","sources":["../../../src/otel/daemon/ensure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IronBee — OTEL forward pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Turns submitted body files into `session_context` events and ships them to
|
|
5
|
+
* the IronBee Collector, grouped per **collector target** (events for different
|
|
6
|
+
* projects/targets can't share a POST). Delivery is **delete-after-confirm**:
|
|
7
|
+
* a request file is unlinked only on a 2xx (or a permanent 4xx); a transient
|
|
8
|
+
* failure keeps it for catch-up retry. Spec: `docs/otel-session-context.md`
|
|
9
|
+
* §7.1 / §9.
|
|
10
|
+
*/
|
|
11
|
+
import { OTELHealthCounters } from "../types";
|
|
12
|
+
import { ApiRequestBodyMeta } from "../context/extract";
|
|
13
|
+
export declare class ForwardPipeline {
|
|
14
|
+
private pending;
|
|
15
|
+
private failed;
|
|
16
|
+
private dropped;
|
|
17
|
+
private reprocessing;
|
|
18
|
+
private flushTimer;
|
|
19
|
+
private readonly buffers;
|
|
20
|
+
/** Per-session last-admitted epoch ms — drives the `emitMinIntervalSeconds` throttle. */
|
|
21
|
+
private readonly lastEmitMs;
|
|
22
|
+
private readonly flushMs;
|
|
23
|
+
constructor(flushMs?: number);
|
|
24
|
+
/** Observability counters for `/health`. */
|
|
25
|
+
counters(): OTELHealthCounters;
|
|
26
|
+
/** Submit a body file for async processing + forwarding (fire-and-forget). */
|
|
27
|
+
submit(meta: ApiRequestBodyMeta): void;
|
|
28
|
+
private process;
|
|
29
|
+
/**
|
|
30
|
+
* Leading-edge per-session throttle for `otel.emitMinIntervalSeconds`.
|
|
31
|
+
* Returns `true` when this request should be coalesced away (dropped). The
|
|
32
|
+
* interval is read live per project (config can change between requests);
|
|
33
|
+
* `0` (the default) disables the throttle entirely.
|
|
34
|
+
*/
|
|
35
|
+
private shouldThrottle;
|
|
36
|
+
private scheduleFlush;
|
|
37
|
+
/**
|
|
38
|
+
* Flush every per-target buffer. All-or-nothing per batch:
|
|
39
|
+
* - 2xx → unlink all contributing request files (delivered)
|
|
40
|
+
* - permanent 4xx → unlink (retry won't help) + log
|
|
41
|
+
* - 429 / 5xx / net → keep the files (catch-up / `otel retry` re-sends)
|
|
42
|
+
*/
|
|
43
|
+
flushAll(): Promise<void>;
|
|
44
|
+
/** Re-scan registry otel dirs and resubmit orphans. Non-reentrant. */
|
|
45
|
+
reprocess(): void;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=forward.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../../../src/otel/daemon/forward.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAkCxD,qBAAa,eAAe;IACxB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,yFAAyF;IACzF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,GAAE,MAAyB;IAI9C,4CAA4C;IAC5C,QAAQ,IAAI,kBAAkB;IAS9B,8EAA8E;IAC9E,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;YAWxB,OAAO;IA8BrB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,aAAa;IAWrB;;;;;OAKG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC/B,sEAAsE;IACtE,SAAS,IAAI,IAAI;CAapB"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.js","sourceRoot":"","sources":["../../../src/otel/daemon/forward.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IronBee — OTEL body-ref path helpers (pure, path-aware, cross-platform).
|
|
3
|
+
*
|
|
4
|
+
* A raw body file lives at `<project_dir>/.ironbee/otel/<uuid>.request.json`.
|
|
5
|
+
* The daemon derives the project dir from that path (no registry walk), and the
|
|
6
|
+
* same check is the security gate: the daemon only reads / unlinks files that
|
|
7
|
+
* actually sit inside a `.ironbee/otel` directory (a loopback POST must not make
|
|
8
|
+
* it touch arbitrary paths).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Derive `<project_dir>` from a `body_ref` of the shape
|
|
12
|
+
* `<project_dir>/.ironbee/otel/<file>`. Returns `null` when the path is not
|
|
13
|
+
* inside a `.ironbee/otel` directory — which doubles as the security gate
|
|
14
|
+
* (reject anything outside). Path-aware: never splits on a hardcoded `/`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function projectDirFromBodyRef(bodyRef: string): string | null;
|
|
17
|
+
/** True when `body_ref` is inside a `.ironbee/otel` dir (the security gate). */
|
|
18
|
+
export declare function isInsideOTELDir(bodyRef: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* The request/response uuid from a body-ref filename:
|
|
21
|
+
* `<uuid>.request.json` → `<uuid>`, `<request_id>.response.json` → `<request_id>`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function requestUuidFromBodyRef(bodyRef: string): string;
|
|
24
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/otel/daemon/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAapE;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* IronBee — OTEL body-ref path helpers (pure, path-aware, cross-platform).
|
|
4
|
+
*
|
|
5
|
+
* A raw body file lives at `<project_dir>/.ironbee/otel/<uuid>.request.json`.
|
|
6
|
+
* The daemon derives the project dir from that path (no registry walk), and the
|
|
7
|
+
* same check is the security gate: the daemon only reads / unlinks files that
|
|
8
|
+
* actually sit inside a `.ironbee/otel` directory (a loopback POST must not make
|
|
9
|
+
* it touch arbitrary paths).
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.projectDirFromBodyRef = projectDirFromBodyRef;
|
|
13
|
+
exports.isInsideOTELDir = isInsideOTELDir;
|
|
14
|
+
exports.requestUuidFromBodyRef = requestUuidFromBodyRef;
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
const OTEL_DIRNAME = "otel";
|
|
17
|
+
const IRONBEE_DIRNAME = ".ironbee";
|
|
18
|
+
/**
|
|
19
|
+
* Derive `<project_dir>` from a `body_ref` of the shape
|
|
20
|
+
* `<project_dir>/.ironbee/otel/<file>`. Returns `null` when the path is not
|
|
21
|
+
* inside a `.ironbee/otel` directory — which doubles as the security gate
|
|
22
|
+
* (reject anything outside). Path-aware: never splits on a hardcoded `/`.
|
|
23
|
+
*/
|
|
24
|
+
function projectDirFromBodyRef(bodyRef) {
|
|
25
|
+
const otelDir = (0, path_1.dirname)(bodyRef);
|
|
26
|
+
const ironbeeDir = (0, path_1.dirname)(otelDir);
|
|
27
|
+
const projectDir = (0, path_1.dirname)(ironbeeDir);
|
|
28
|
+
if ((0, path_1.basename)(otelDir) === OTEL_DIRNAME
|
|
29
|
+
&& (0, path_1.basename)(ironbeeDir) === IRONBEE_DIRNAME
|
|
30
|
+
&& projectDir.length > 0
|
|
31
|
+
&& projectDir !== ironbeeDir) {
|
|
32
|
+
return projectDir;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/** True when `body_ref` is inside a `.ironbee/otel` dir (the security gate). */
|
|
37
|
+
function isInsideOTELDir(bodyRef) {
|
|
38
|
+
return projectDirFromBodyRef(bodyRef) !== null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The request/response uuid from a body-ref filename:
|
|
42
|
+
* `<uuid>.request.json` → `<uuid>`, `<request_id>.response.json` → `<request_id>`.
|
|
43
|
+
*/
|
|
44
|
+
function requestUuidFromBodyRef(bodyRef) {
|
|
45
|
+
return (0, path_1.basename)(bodyRef).replace(/\.(request|response)\.json$/i, "");
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/otel/daemon/paths.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAaH,sDAaC;AAGD,0CAEC;AAMD,wDAEC;AArCD,+BAAyC;AAEzC,MAAM,YAAY,GAAW,MAAM,CAAC;AACpC,MAAM,eAAe,GAAW,UAAU,CAAC;AAE3C;;;;;GAKG;AACH,SAAgB,qBAAqB,CAAC,OAAe;IACjD,MAAM,OAAO,GAAW,IAAA,cAAO,EAAC,OAAO,CAAC,CAAC;IACzC,MAAM,UAAU,GAAW,IAAA,cAAO,EAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAW,IAAA,cAAO,EAAC,UAAU,CAAC,CAAC;IAC/C,IACI,IAAA,eAAQ,EAAC,OAAO,CAAC,KAAK,YAAY;WAC/B,IAAA,eAAQ,EAAC,UAAU,CAAC,KAAK,eAAe;WACxC,UAAU,CAAC,MAAM,GAAG,CAAC;WACrB,UAAU,KAAK,UAAU,EAC9B,CAAC;QACC,OAAO,UAAU,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,gFAAgF;AAChF,SAAgB,eAAe,CAAC,OAAe;IAC3C,OAAO,qBAAqB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,SAAgB,sBAAsB,CAAC,OAAe;IAClD,OAAO,IAAA,eAAQ,EAAC,OAAO,CAAC,CAAC,OAAO,CAAC,8BAA8B,EAAE,EAAE,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IronBee — read a raw `*.request.json` body file and build its
|
|
3
|
+
* `session_context` event. Handles the security gate (path must be inside
|
|
4
|
+
* `.ironbee/otel`), the partial-write guard (size vs `body_length`), and
|
|
5
|
+
* identity resolution (session_id / project_name / model / base fields). Returns
|
|
6
|
+
* the built event + the owning project dir, or `null` to skip.
|
|
7
|
+
*/
|
|
8
|
+
import { SessionContextEvent } from "../../lib/event";
|
|
9
|
+
import { ApiRequestBodyMeta } from "../context/extract";
|
|
10
|
+
export interface ProcessedBody {
|
|
11
|
+
event: SessionContextEvent;
|
|
12
|
+
projectDir: string;
|
|
13
|
+
bodyRef: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read + build. Returns `null` (skip) on: a path outside `.ironbee/otel`
|
|
17
|
+
* (security gate), a missing / unreadable file, unparseable JSON, or no
|
|
18
|
+
* resolvable session_id.
|
|
19
|
+
*/
|
|
20
|
+
export declare function processBodyFile(meta: ApiRequestBodyMeta): Promise<ProcessedBody | null>;
|
|
21
|
+
//# sourceMappingURL=process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../../src/otel/daemon/process.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,EAAE,mBAAmB,EAAa,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAMxD,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,mBAAmB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACnB;AAmFD;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CA0D7F"}
|