@optimuslabs/runtime 0.3.3
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/LICENSE +21 -0
- package/README.md +198 -0
- package/dist/capture-prompt.d.ts +14 -0
- package/dist/capture-prompt.d.ts.map +1 -0
- package/dist/capture-prompt.js +173 -0
- package/dist/capture-prompt.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +203 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/client-event.d.ts +12 -0
- package/dist/lib/client-event.d.ts.map +1 -0
- package/dist/lib/client-event.js +140 -0
- package/dist/lib/client-event.js.map +1 -0
- package/dist/lib/endpoint-config.d.ts +2 -0
- package/dist/lib/endpoint-config.d.ts.map +1 -0
- package/dist/lib/endpoint-config.js +2 -0
- package/dist/lib/endpoint-config.js.map +1 -0
- package/dist/lib/hardware-uuid.d.ts +7 -0
- package/dist/lib/hardware-uuid.d.ts.map +1 -0
- package/dist/lib/hardware-uuid.js +52 -0
- package/dist/lib/hardware-uuid.js.map +1 -0
- package/dist/lib/machine-auth.d.ts +11 -0
- package/dist/lib/machine-auth.d.ts.map +1 -0
- package/dist/lib/machine-auth.js +46 -0
- package/dist/lib/machine-auth.js.map +1 -0
- package/dist/lib/pending-events.d.ts +49 -0
- package/dist/lib/pending-events.d.ts.map +1 -0
- package/dist/lib/pending-events.js +135 -0
- package/dist/lib/pending-events.js.map +1 -0
- package/dist/lib/startup-sync.d.ts +13 -0
- package/dist/lib/startup-sync.d.ts.map +1 -0
- package/dist/lib/startup-sync.js +164 -0
- package/dist/lib/startup-sync.js.map +1 -0
- package/dist/lib/streaming.d.ts +35 -0
- package/dist/lib/streaming.d.ts.map +1 -0
- package/dist/lib/streaming.js +326 -0
- package/dist/lib/streaming.js.map +1 -0
- package/dist/lib/telemetry/build-event.d.ts +10 -0
- package/dist/lib/telemetry/build-event.d.ts.map +1 -0
- package/dist/lib/telemetry/build-event.js +34 -0
- package/dist/lib/telemetry/build-event.js.map +1 -0
- package/dist/lib/telemetry/canonical.d.ts +26 -0
- package/dist/lib/telemetry/canonical.d.ts.map +1 -0
- package/dist/lib/telemetry/canonical.js +153 -0
- package/dist/lib/telemetry/canonical.js.map +1 -0
- package/dist/lib/telemetry/index.d.ts +9 -0
- package/dist/lib/telemetry/index.d.ts.map +1 -0
- package/dist/lib/telemetry/index.js +9 -0
- package/dist/lib/telemetry/index.js.map +1 -0
- package/dist/lib/telemetry/serialize.d.ts +3 -0
- package/dist/lib/telemetry/serialize.d.ts.map +1 -0
- package/dist/lib/telemetry/serialize.js +15 -0
- package/dist/lib/telemetry/serialize.js.map +1 -0
- package/dist/lib/telemetry/types.d.ts +35 -0
- package/dist/lib/telemetry/types.d.ts.map +1 -0
- package/dist/lib/telemetry/types.js +14 -0
- package/dist/lib/telemetry/types.js.map +1 -0
- package/dist/lib/telemetry/wire-metadata.d.ts +10 -0
- package/dist/lib/telemetry/wire-metadata.d.ts.map +1 -0
- package/dist/lib/telemetry/wire-metadata.js +28 -0
- package/dist/lib/telemetry/wire-metadata.js.map +1 -0
- package/dist/lib/telemetry.d.ts +2 -0
- package/dist/lib/telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry.js +2 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/tofu.d.ts +16 -0
- package/dist/lib/tofu.d.ts.map +1 -0
- package/dist/lib/tofu.js +44 -0
- package/dist/lib/tofu.js.map +1 -0
- package/dist/lib/user-profile.d.ts +17 -0
- package/dist/lib/user-profile.d.ts.map +1 -0
- package/dist/lib/user-profile.js +187 -0
- package/dist/lib/user-profile.js.map +1 -0
- package/dist/test/canonical.test.d.ts +2 -0
- package/dist/test/canonical.test.d.ts.map +1 -0
- package/dist/test/canonical.test.js +138 -0
- package/dist/test/canonical.test.js.map +1 -0
- package/dist/test/endpoint-config.test.d.ts +2 -0
- package/dist/test/endpoint-config.test.d.ts.map +1 -0
- package/dist/test/endpoint-config.test.js +73 -0
- package/dist/test/endpoint-config.test.js.map +1 -0
- package/dist/test/index.test.d.ts +2 -0
- package/dist/test/index.test.d.ts.map +1 -0
- package/dist/test/index.test.js +376 -0
- package/dist/test/index.test.js.map +1 -0
- package/dist/test/integration-canonical.test.d.ts +2 -0
- package/dist/test/integration-canonical.test.d.ts.map +1 -0
- package/dist/test/integration-canonical.test.js +176 -0
- package/dist/test/integration-canonical.test.js.map +1 -0
- package/dist/test/pending-events.test.d.ts +13 -0
- package/dist/test/pending-events.test.d.ts.map +1 -0
- package/dist/test/pending-events.test.js +265 -0
- package/dist/test/pending-events.test.js.map +1 -0
- package/dist/test/startup-sync.test.d.ts +2 -0
- package/dist/test/startup-sync.test.d.ts.map +1 -0
- package/dist/test/startup-sync.test.js +57 -0
- package/dist/test/startup-sync.test.js.map +1 -0
- package/dist/test/streaming-http.test.d.ts +11 -0
- package/dist/test/streaming-http.test.d.ts.map +1 -0
- package/dist/test/streaming-http.test.js +181 -0
- package/dist/test/streaming-http.test.js.map +1 -0
- package/dist/test/streaming.test.d.ts +2 -0
- package/dist/test/streaming.test.d.ts.map +1 -0
- package/dist/test/streaming.test.js +223 -0
- package/dist/test/streaming.test.js.map +1 -0
- package/dist/test/telemetry.test.d.ts +2 -0
- package/dist/test/telemetry.test.d.ts.map +1 -0
- package/dist/test/telemetry.test.js +201 -0
- package/dist/test/telemetry.test.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST `/endpoint_security/startup/` with `metadata.user_profile` so `EndpointMachine.user_profile`
|
|
3
|
+
* stays fresh even when `log_uuid` is throttled (e.g. customer hooks with existing auth_key.txt).
|
|
4
|
+
* Signs `payload` with the stored machine key when present (same as `log-llm-config` startup_sender)
|
|
5
|
+
* so the backend does not revoke keys on every unsigned sync.
|
|
6
|
+
*
|
|
7
|
+
* Throttled (default 30 min) on success to avoid an extra HTTP round-trip on every tool call.
|
|
8
|
+
* After failures (network, non-2xx, etc.), exponential backoff caps repeated work so hooks are
|
|
9
|
+
* not blocked on every batch. Override interval with `OPTIMUS_STARTUP_SYNC_INTERVAL_MS` (set to
|
|
10
|
+
* `0` to sync on every batch when healthy). Skip entirely with `OPTIMUS_SKIP_STARTUP_SYNC=1`.
|
|
11
|
+
*/
|
|
12
|
+
import { buildStartupEndpointUrl, createSignature, loadEndpointBase, persistAuthKey, readStoredAuthKey, } from "./tofu.js";
|
|
13
|
+
import { OPTIMUS_AUTH_KEY_RELATIVE_PATH, resetToolCallAuthCache } from "./machine-auth.js";
|
|
14
|
+
import { resolveUserProfile } from "./user-profile.js";
|
|
15
|
+
import fs from "node:fs";
|
|
16
|
+
import os from "node:os";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
const emptyUserProfile = () => ({
|
|
19
|
+
generateduuid: "",
|
|
20
|
+
machineuuid: "",
|
|
21
|
+
mac_username: "",
|
|
22
|
+
machine_name: "",
|
|
23
|
+
github_username: "",
|
|
24
|
+
claude_email: "",
|
|
25
|
+
cursor_email: "",
|
|
26
|
+
});
|
|
27
|
+
const DEFAULT_STARTUP_SYNC_INTERVAL_MS = 1800000;
|
|
28
|
+
const STARTUP_SYNC_FAILURE_BACKOFF_BASE_MS = 5000;
|
|
29
|
+
const STARTUP_SYNC_FAILURE_BACKOFF_CAP_MS = 300000;
|
|
30
|
+
let lastStartupAttemptEndedMs = 0;
|
|
31
|
+
/** After a failed attempt, false until the next completed successful sync. */
|
|
32
|
+
let lastStartupAttemptOk = true;
|
|
33
|
+
let startupSyncFailureStreak = 0;
|
|
34
|
+
function recordStartupSyncAttemptEnd(ok) {
|
|
35
|
+
lastStartupAttemptEndedMs = Date.now();
|
|
36
|
+
lastStartupAttemptOk = ok;
|
|
37
|
+
if (ok) {
|
|
38
|
+
startupSyncFailureStreak = 0;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
startupSyncFailureStreak += 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function shouldSkipStartupSyncDueToCooldown(now, intervalMs) {
|
|
45
|
+
if (lastStartupAttemptEndedMs <= 0)
|
|
46
|
+
return false;
|
|
47
|
+
const failureBackoffMs = !lastStartupAttemptOk
|
|
48
|
+
? Math.min(STARTUP_SYNC_FAILURE_BACKOFF_CAP_MS, STARTUP_SYNC_FAILURE_BACKOFF_BASE_MS *
|
|
49
|
+
2 ** Math.min(Math.max(0, startupSyncFailureStreak - 1), 6))
|
|
50
|
+
: 0;
|
|
51
|
+
const successIntervalMs = lastStartupAttemptOk && intervalMs > 0 ? intervalMs : 0;
|
|
52
|
+
const cooldownMs = Math.max(failureBackoffMs, successIntervalMs);
|
|
53
|
+
return cooldownMs > 0 && now - lastStartupAttemptEndedMs < cooldownMs;
|
|
54
|
+
}
|
|
55
|
+
function readOrganizationUuid() {
|
|
56
|
+
const envValue = (process.env.OPTIMUS_ORGANIZATION_UUID || "").trim();
|
|
57
|
+
if (envValue)
|
|
58
|
+
return envValue;
|
|
59
|
+
try {
|
|
60
|
+
const orgUuidFile = path.join(os.homedir(), ".optimuslabs", "management", "org", "organization-uuid.txt");
|
|
61
|
+
return fs.readFileSync(orgUuidFile, "utf8").trim();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return "";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export async function ensureStartupMetadataSynced(hardwareUuid) {
|
|
68
|
+
if (process.env.OPTIMUS_SKIP_STARTUP_SYNC === "1")
|
|
69
|
+
return;
|
|
70
|
+
const rawInterval = process.env.OPTIMUS_STARTUP_SYNC_INTERVAL_MS;
|
|
71
|
+
let intervalMs = DEFAULT_STARTUP_SYNC_INTERVAL_MS;
|
|
72
|
+
if (rawInterval !== undefined && rawInterval !== "") {
|
|
73
|
+
const parsed = parseInt(rawInterval, 10);
|
|
74
|
+
intervalMs =
|
|
75
|
+
Number.isNaN(parsed) || parsed < 0 ? DEFAULT_STARTUP_SYNC_INTERVAL_MS : parsed;
|
|
76
|
+
}
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
if (shouldSkipStartupSyncDueToCooldown(now, intervalMs)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const timestamp = new Date().toISOString();
|
|
82
|
+
const payloadSummary = {
|
|
83
|
+
timestamp,
|
|
84
|
+
directory: process.cwd(),
|
|
85
|
+
hardware_uuid: hardwareUuid,
|
|
86
|
+
};
|
|
87
|
+
let user_profile;
|
|
88
|
+
try {
|
|
89
|
+
user_profile = { ...resolveUserProfile() };
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
console.error(`[optimus-tool-call] resolveUserProfile failed; continuing startup sync with empty profile: ${err instanceof Error ? err.message : String(err)}`);
|
|
93
|
+
user_profile = emptyUserProfile();
|
|
94
|
+
}
|
|
95
|
+
const github_username = (typeof user_profile.github_username === "string" && user_profile.github_username.trim()) ||
|
|
96
|
+
process.env.GITHUB_USER ||
|
|
97
|
+
process.env.GH_USER ||
|
|
98
|
+
"";
|
|
99
|
+
const metadata = {
|
|
100
|
+
github_username,
|
|
101
|
+
org_identifier: process.env.GITHUB_ORG || "",
|
|
102
|
+
organization_uuid: readOrganizationUuid(),
|
|
103
|
+
repo_identifier: process.env.GITHUB_REPOSITORY || "",
|
|
104
|
+
branch: process.env.GITHUB_REF_NAME || process.env.BRANCH_NAME || "",
|
|
105
|
+
commit_sha: process.env.GITHUB_SHA || "",
|
|
106
|
+
agent_name: process.env.OPTIMUS_AGENT || "",
|
|
107
|
+
user_profile,
|
|
108
|
+
};
|
|
109
|
+
const body = {
|
|
110
|
+
hardware_uuid: hardwareUuid,
|
|
111
|
+
payload: payloadSummary,
|
|
112
|
+
metadata,
|
|
113
|
+
scan_timestamp: timestamp,
|
|
114
|
+
};
|
|
115
|
+
const storedKey = readStoredAuthKey({
|
|
116
|
+
authRelativePath: OPTIMUS_AUTH_KEY_RELATIVE_PATH,
|
|
117
|
+
});
|
|
118
|
+
if (storedKey?.key && storedKey.hardware_uuid === hardwareUuid) {
|
|
119
|
+
body.signature = createSignature(payloadSummary, storedKey.key);
|
|
120
|
+
if (storedKey.key_id)
|
|
121
|
+
body.key_id = storedKey.key_id;
|
|
122
|
+
}
|
|
123
|
+
const url = buildStartupEndpointUrl(loadEndpointBase());
|
|
124
|
+
try {
|
|
125
|
+
const controller = new AbortController();
|
|
126
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
127
|
+
let res;
|
|
128
|
+
try {
|
|
129
|
+
res = await fetch(url, {
|
|
130
|
+
method: "POST",
|
|
131
|
+
headers: { "Content-Type": "application/json" },
|
|
132
|
+
body: JSON.stringify(body),
|
|
133
|
+
signal: controller.signal,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
clearTimeout(timeoutId);
|
|
138
|
+
}
|
|
139
|
+
const text = await res.text();
|
|
140
|
+
if (!res.ok) {
|
|
141
|
+
console.error(`[optimus-tool-call] startup metadata sync failed ${res.status}: ${text ? text.slice(0, 240) : res.statusText}`);
|
|
142
|
+
recordStartupSyncAttemptEnd(false);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
let parsed = {};
|
|
146
|
+
try {
|
|
147
|
+
parsed = JSON.parse(text);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
recordStartupSyncAttemptEnd(false);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (parsed.status === "key_issued" && typeof parsed.key === "string") {
|
|
154
|
+
persistAuthKey(parsed.key, typeof parsed.key_id === "string" ? parsed.key_id : null, hardwareUuid, { authRelativePath: OPTIMUS_AUTH_KEY_RELATIVE_PATH });
|
|
155
|
+
resetToolCallAuthCache();
|
|
156
|
+
}
|
|
157
|
+
recordStartupSyncAttemptEnd(true);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error(`[optimus-tool-call] startup metadata sync error: ${err instanceof Error ? err.message : String(err)}`);
|
|
161
|
+
recordStartupSyncAttemptEnd(false);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=startup-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-sync.js","sourceRoot":"","sources":["../../src/lib/startup-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry streaming — batch and send events to Optimus backend.
|
|
3
|
+
*/
|
|
4
|
+
import { TelemetryEvent } from "./telemetry.js";
|
|
5
|
+
/** Thrown by sendBatch when the server rejects the request with a 4xx status. Not retryable. */
|
|
6
|
+
export declare class ClientError extends Error {
|
|
7
|
+
readonly httpStatus: number;
|
|
8
|
+
constructor(status: number, message: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Route a send failure to the right local buffer.
|
|
12
|
+
* 4xx → client_errors.jsonl (logged, never retried)
|
|
13
|
+
* anything else → pending_events.jsonl (retried on next hook invocation)
|
|
14
|
+
* Exported for unit testing without needing to mock the HTTP stack.
|
|
15
|
+
*/
|
|
16
|
+
export declare function routeFailure(events: TelemetryEvent[], err: unknown): void;
|
|
17
|
+
/**
|
|
18
|
+
* Resolved batch size from OPTIMUS_BATCH_SIZE (read at call time so tests can set env after import).
|
|
19
|
+
* Invalid or non-positive values fall back to 1 so `length >= batchSize` stays meaningful.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getBatchSize(): number;
|
|
22
|
+
/**
|
|
23
|
+
* Add an event to the queue and flush if needed.
|
|
24
|
+
*/
|
|
25
|
+
export declare function queueEvent(event: TelemetryEvent): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Flush all queued events to backend.
|
|
28
|
+
*/
|
|
29
|
+
export declare function flushEvents(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Ensure all events are flushed on process exit.
|
|
32
|
+
* Uses beforeExit to allow async flush before process terminates.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ensureShutdown(): void;
|
|
35
|
+
//# sourceMappingURL=streaming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/lib/streaming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMhD,gGAAgG;AAChG,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAChB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI5C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAMzE;AA+BD;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAMrC;AAoBD;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBrE;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA6BjD;AAwLD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CA0BrC"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry streaming — batch and send events to Optimus backend.
|
|
3
|
+
*/
|
|
4
|
+
import { createSignature } from "./tofu.js";
|
|
5
|
+
import { ensureToolCallAuth } from "./machine-auth.js";
|
|
6
|
+
import { ensureStartupMetadataSynced } from "./startup-sync.js";
|
|
7
|
+
import { cloneToolCallMetadataForWire } from "./telemetry/wire-metadata.js";
|
|
8
|
+
import { loadEndpointBase } from "./endpoint-config.js";
|
|
9
|
+
import { tryResolveHardwareUuid } from "./hardware-uuid.js";
|
|
10
|
+
import { appendPendingEvents, appendClientErrors, drainPendingEvents } from "./pending-events.js";
|
|
11
|
+
/** Thrown by sendBatch when the server rejects the request with a 4xx status. Not retryable. */
|
|
12
|
+
export class ClientError extends Error {
|
|
13
|
+
constructor(status, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.httpStatus = status;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Route a send failure to the right local buffer.
|
|
20
|
+
* 4xx → client_errors.jsonl (logged, never retried)
|
|
21
|
+
* anything else → pending_events.jsonl (retried on next hook invocation)
|
|
22
|
+
* Exported for unit testing without needing to mock the HTTP stack.
|
|
23
|
+
*/
|
|
24
|
+
export function routeFailure(events, err) {
|
|
25
|
+
if (err instanceof ClientError) {
|
|
26
|
+
appendClientErrors(events, err.httpStatus);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
appendPendingEvents(events);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const DEBUG = !!process.env.OPTIMUS_DEBUG;
|
|
33
|
+
const dbg = (...args) => { if (DEBUG)
|
|
34
|
+
console.error(...args); };
|
|
35
|
+
function toolCallAuditLogEnabled() {
|
|
36
|
+
const v = (process.env.OPTIMUS_TOOL_CALL_LOG || "").trim().toLowerCase();
|
|
37
|
+
return v === "1" || v === "true" || v === "yes";
|
|
38
|
+
}
|
|
39
|
+
/** One-line stderr audit when OPTIMUS_TOOL_CALL_LOG is set (hooks append stderr to hook-errors.log). */
|
|
40
|
+
function logBatchSent(endpoint, httpStatus, eventCount) {
|
|
41
|
+
if (!toolCallAuditLogEnabled()) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const u = new URL(endpoint);
|
|
46
|
+
console.error(`[optimus-tool-call] telemetry: POST ${u.pathname} -> ${httpStatus} (${eventCount} event(s), host=${u.host})`);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
console.error(`[optimus-tool-call] telemetry: POST batch -> ${httpStatus} (${eventCount} event(s))`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Backend configuration
|
|
53
|
+
const OPTIMUS_API_BASE = loadEndpointBase();
|
|
54
|
+
const BATCH_TIMEOUT_MS = 5000; // 5 seconds
|
|
55
|
+
/**
|
|
56
|
+
* Resolved batch size from OPTIMUS_BATCH_SIZE (read at call time so tests can set env after import).
|
|
57
|
+
* Invalid or non-positive values fall back to 1 so `length >= batchSize` stays meaningful.
|
|
58
|
+
*/
|
|
59
|
+
export function getBatchSize() {
|
|
60
|
+
const n = parseInt(process.env.OPTIMUS_BATCH_SIZE || "1", 10);
|
|
61
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
62
|
+
return 1;
|
|
63
|
+
}
|
|
64
|
+
return Math.floor(n);
|
|
65
|
+
}
|
|
66
|
+
// In-memory event queue
|
|
67
|
+
let eventQueue = [];
|
|
68
|
+
let batchTimer = null;
|
|
69
|
+
// Drain the pending file once per process lifetime, before the first send.
|
|
70
|
+
let pendingDrained = false;
|
|
71
|
+
async function sendPendingIfAny() {
|
|
72
|
+
const pending = drainPendingEvents();
|
|
73
|
+
if (pending.length === 0)
|
|
74
|
+
return;
|
|
75
|
+
dbg(`[optimus-tool-call] Retrying ${pending.length} pending event(s) from disk`);
|
|
76
|
+
try {
|
|
77
|
+
await sendBatch(pending);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
routeFailure(pending, err);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Add an event to the queue and flush if needed.
|
|
85
|
+
*/
|
|
86
|
+
export async function queueEvent(event) {
|
|
87
|
+
if (!event) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!pendingDrained) {
|
|
91
|
+
await sendPendingIfAny();
|
|
92
|
+
pendingDrained = true;
|
|
93
|
+
}
|
|
94
|
+
eventQueue.push(event);
|
|
95
|
+
// Flush immediately if batch size reached
|
|
96
|
+
if (eventQueue.length >= getBatchSize()) {
|
|
97
|
+
await flushEvents();
|
|
98
|
+
}
|
|
99
|
+
else if (!batchTimer) {
|
|
100
|
+
// Set timer for delayed flush if not already set
|
|
101
|
+
batchTimer = setTimeout(() => {
|
|
102
|
+
flushEvents().catch((err) => {
|
|
103
|
+
// Log but don't block
|
|
104
|
+
console.error("[optimus-tool-call] Failed to flush events:", err);
|
|
105
|
+
});
|
|
106
|
+
batchTimer = null;
|
|
107
|
+
}, BATCH_TIMEOUT_MS);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Flush all queued events to backend.
|
|
112
|
+
*/
|
|
113
|
+
export async function flushEvents() {
|
|
114
|
+
if (eventQueue.length === 0) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// Clear timer
|
|
118
|
+
if (batchTimer) {
|
|
119
|
+
clearTimeout(batchTimer);
|
|
120
|
+
batchTimer = null;
|
|
121
|
+
}
|
|
122
|
+
const eventsToSend = eventQueue.splice(0, eventQueue.length);
|
|
123
|
+
try {
|
|
124
|
+
await sendBatch(eventsToSend);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
if (err instanceof ClientError) {
|
|
128
|
+
console.error(`[optimus-tool-call] HTTP ${err.httpStatus} for ${eventsToSend.length} event(s), logging to disk (will not retry):`, err.message);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.error(`[optimus-tool-call] Failed to send ${eventsToSend.length} event(s), buffering for retry:`, err instanceof Error ? err.message : String(err));
|
|
132
|
+
}
|
|
133
|
+
routeFailure(eventsToSend, err);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Clone events for HTTP: drop metadata keys the backend recomputes (classification,
|
|
138
|
+
* MCP split, identity) so the client cannot spoof them.
|
|
139
|
+
*/
|
|
140
|
+
function eventsWireFromTelemetry(events) {
|
|
141
|
+
return events.map((e) => {
|
|
142
|
+
const raw = JSON.parse(JSON.stringify(e));
|
|
143
|
+
const meta = raw.tool_call_metadata;
|
|
144
|
+
const cleaned = cloneToolCallMetadataForWire(meta);
|
|
145
|
+
if (cleaned !== undefined) {
|
|
146
|
+
raw.tool_call_metadata = cleaned;
|
|
147
|
+
}
|
|
148
|
+
return raw;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Send batch of events to Django backend.
|
|
153
|
+
*/
|
|
154
|
+
async function sendBatch(events) {
|
|
155
|
+
if (events.length === 0) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
dbg(`[optimus-tool-call] Sending ${events.length} events to backend...`);
|
|
159
|
+
dbg(`[optimus-tool-call] Event agents:`, events.map(e => e.agent_identity).join(", "));
|
|
160
|
+
const hardwareUuid = tryResolveHardwareUuid();
|
|
161
|
+
if (!hardwareUuid) {
|
|
162
|
+
const err = "Cannot send tool-call telemetry: set OPTIMUS_HARDWARE_UUID or run on a host with a hardware UUID.";
|
|
163
|
+
console.error(`[optimus-tool-call] ERROR: ${err}`);
|
|
164
|
+
throw new Error(err);
|
|
165
|
+
}
|
|
166
|
+
dbg(`[optimus-tool-call] Hardware UUID: ${hardwareUuid}`);
|
|
167
|
+
try {
|
|
168
|
+
await ensureStartupMetadataSynced(hardwareUuid);
|
|
169
|
+
dbg(`[optimus-tool-call] Startup metadata synced`);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
console.error(`[optimus-tool-call] ERROR syncing startup metadata:`, err);
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
const eventsWire = eventsWireFromTelemetry(events);
|
|
176
|
+
dbg(`[optimus-tool-call] Events wire:`, JSON.stringify(eventsWire, null, 2).slice(0, 500));
|
|
177
|
+
const signingPayload = {
|
|
178
|
+
hardware_uuid: hardwareUuid,
|
|
179
|
+
events: eventsWire,
|
|
180
|
+
};
|
|
181
|
+
dbg(`[optimus-tool-call] Payload ready, signing...`);
|
|
182
|
+
const auth = await ensureToolCallAuth(hardwareUuid);
|
|
183
|
+
dbg(`[optimus-tool-call] Auth obtained, key_id: ${auth.key_id}`);
|
|
184
|
+
const signature = createSignature(signingPayload, auth.key);
|
|
185
|
+
const payload = {
|
|
186
|
+
...signingPayload,
|
|
187
|
+
signature,
|
|
188
|
+
key_id: auth.key_id || "",
|
|
189
|
+
};
|
|
190
|
+
const endpoint = new URL("api/tool-calls/events/batch_create/", OPTIMUS_API_BASE).toString();
|
|
191
|
+
dbg(`[optimus-tool-call] Endpoint: ${endpoint}`);
|
|
192
|
+
dbg(`[optimus-tool-call] Payload size: ${JSON.stringify(payload).length} bytes`);
|
|
193
|
+
const headers = {
|
|
194
|
+
"Content-Type": "application/json",
|
|
195
|
+
};
|
|
196
|
+
try {
|
|
197
|
+
// Use fetch if available (Node 18+), fall back to node:http
|
|
198
|
+
if (typeof fetch !== "undefined") {
|
|
199
|
+
dbg(`[optimus-tool-call] Using fetch to send...`);
|
|
200
|
+
const controller = new AbortController();
|
|
201
|
+
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
202
|
+
try {
|
|
203
|
+
const response = await fetch(endpoint, {
|
|
204
|
+
method: "POST",
|
|
205
|
+
headers,
|
|
206
|
+
body: JSON.stringify(payload),
|
|
207
|
+
signal: controller.signal,
|
|
208
|
+
});
|
|
209
|
+
dbg(`[optimus-tool-call] Response status: ${response.status} ${response.statusText}`);
|
|
210
|
+
if (!response.ok) {
|
|
211
|
+
const responseText = await response.text();
|
|
212
|
+
dbg(`[optimus-tool-call] Response body: ${responseText}`);
|
|
213
|
+
const msg = `HTTP ${response.status}: ${response.statusText} - ${responseText}`;
|
|
214
|
+
if (response.status >= 400 && response.status < 500) {
|
|
215
|
+
throw new ClientError(response.status, msg);
|
|
216
|
+
}
|
|
217
|
+
throw new Error(msg);
|
|
218
|
+
}
|
|
219
|
+
logBatchSent(endpoint, response.status, events.length);
|
|
220
|
+
dbg(`[optimus-tool-call] ✅ Successfully sent ${events.length} events`);
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
clearTimeout(timeoutId);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
// Fallback for older Node versions
|
|
228
|
+
dbg(`[optimus-tool-call] Using http fallback...`);
|
|
229
|
+
await sendViaHttp(endpoint, headers, payload, events.length);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
if (err instanceof ClientError) {
|
|
234
|
+
console.error(`[optimus-tool-call] ❌ ${err.message}`);
|
|
235
|
+
throw err;
|
|
236
|
+
}
|
|
237
|
+
const errorMsg = `Failed to send events to ${endpoint}: ${err instanceof Error ? err.message : String(err)}`;
|
|
238
|
+
console.error(`[optimus-tool-call] ❌ ${errorMsg}`);
|
|
239
|
+
throw new Error(errorMsg);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Fallback HTTP POST using node:http for older Node versions.
|
|
244
|
+
*/
|
|
245
|
+
function sendViaHttp(endpoint, headers, payload, eventCount) {
|
|
246
|
+
return new Promise((resolve, reject) => {
|
|
247
|
+
try {
|
|
248
|
+
const url = new URL(endpoint);
|
|
249
|
+
const protocol = url.protocol === "https:" ? require("https") : require("http");
|
|
250
|
+
const options = {
|
|
251
|
+
hostname: url.hostname,
|
|
252
|
+
port: url.port,
|
|
253
|
+
path: url.pathname + url.search,
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: {
|
|
256
|
+
...headers,
|
|
257
|
+
"Content-Length": Buffer.byteLength(JSON.stringify(payload)),
|
|
258
|
+
},
|
|
259
|
+
timeout: 5000,
|
|
260
|
+
};
|
|
261
|
+
const req = protocol.request(options, (res) => {
|
|
262
|
+
let data = "";
|
|
263
|
+
res.on("data", (chunk) => {
|
|
264
|
+
data += chunk;
|
|
265
|
+
});
|
|
266
|
+
res.on("end", () => {
|
|
267
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
268
|
+
logBatchSent(endpoint, res.statusCode, eventCount);
|
|
269
|
+
resolve();
|
|
270
|
+
}
|
|
271
|
+
else if (res.statusCode && res.statusCode >= 400 && res.statusCode < 500) {
|
|
272
|
+
reject(new ClientError(res.statusCode, `HTTP ${res.statusCode}: ${data || res.statusMessage || "Client error"}`));
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage || "Unknown error"}`));
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
req.on("error", (err) => {
|
|
280
|
+
reject(err);
|
|
281
|
+
});
|
|
282
|
+
req.on("timeout", () => {
|
|
283
|
+
req.destroy();
|
|
284
|
+
reject(new Error("Request timeout"));
|
|
285
|
+
});
|
|
286
|
+
req.write(JSON.stringify(payload));
|
|
287
|
+
req.end();
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
reject(err);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Ensure all events are flushed on process exit.
|
|
296
|
+
* Uses beforeExit to allow async flush before process terminates.
|
|
297
|
+
*/
|
|
298
|
+
export function ensureShutdown() {
|
|
299
|
+
// beforeExit allows async operations, unlike exit
|
|
300
|
+
process.on("beforeExit", async () => {
|
|
301
|
+
if (eventQueue.length > 0) {
|
|
302
|
+
try {
|
|
303
|
+
await flushEvents();
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
console.error("[optimus-tool-call] Failed to flush events on shutdown:", err);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
// Also handle explicit termination signals
|
|
311
|
+
const signals = ["SIGTERM", "SIGINT"];
|
|
312
|
+
signals.forEach((sig) => {
|
|
313
|
+
process.on(sig, async () => {
|
|
314
|
+
if (eventQueue.length > 0) {
|
|
315
|
+
try {
|
|
316
|
+
await flushEvents();
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
console.error(`[optimus-tool-call] Failed to flush events on ${sig}:`, err);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
process.exit(0);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=streaming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming.js","sourceRoot":"","sources":["../../src/lib/streaming.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TelemetryEvent, ToolInvocation } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Build a telemetry event from a tool invocation.
|
|
4
|
+
*
|
|
5
|
+
* Sends raw hook fields only. Classification (`action_type`, `command_components`,
|
|
6
|
+
* paths, patterns, MCP split) is performed server-side in Django
|
|
7
|
+
* (`tool_call_audit.classification.enrich`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildTelemetryEvent(inv: ToolInvocation | null | undefined, agentIdentity?: string, sessionId?: string | null): TelemetryEvent | null;
|
|
10
|
+
//# sourceMappingURL=build-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-event.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/build-event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACtC,aAAa,GAAE,MAAkB,EACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,cAAc,GAAG,IAAI,CA6BvB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a telemetry event from a tool invocation.
|
|
3
|
+
*
|
|
4
|
+
* Sends raw hook fields only. Classification (`action_type`, `command_components`,
|
|
5
|
+
* paths, patterns, MCP split) is performed server-side in Django
|
|
6
|
+
* (`tool_call_audit.classification.enrich`).
|
|
7
|
+
*/
|
|
8
|
+
export function buildTelemetryEvent(inv, agentIdentity = "unknown", sessionId) {
|
|
9
|
+
if (!inv) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const toolName = inv.tool_name;
|
|
13
|
+
const toolNameNorm = typeof toolName === "string" ? toolName.trim() : "";
|
|
14
|
+
const normalizedToolInput = inv.tool_input || {};
|
|
15
|
+
const hookHash = (process.env.OPTIMUS_HOOK_HASH || "").trim() || null;
|
|
16
|
+
const meta = {
|
|
17
|
+
tool_name: toolNameNorm || toolName,
|
|
18
|
+
tool_input: normalizedToolInput,
|
|
19
|
+
...(inv.user_prompt ? { user_prompt: inv.user_prompt } : {}),
|
|
20
|
+
...(inv.raw_event ? { raw_event: inv.raw_event } : {}),
|
|
21
|
+
...(hookHash ? { hook_hash: hookHash } : {}),
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
timestamp: new Date().toISOString(),
|
|
25
|
+
agent_identity: agentIdentity,
|
|
26
|
+
event_type: "tool_call",
|
|
27
|
+
session_id: sessionId,
|
|
28
|
+
tool_use_id: inv.tool_use_id || null,
|
|
29
|
+
hook_event_name: inv.hook_event_name || null,
|
|
30
|
+
working_directory: inv.cwd || null,
|
|
31
|
+
tool_call_metadata: meta,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=build-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-event.js","sourceRoot":"","sources":["../../../src/lib/telemetry/build-event.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAsC,EACtC,gBAAwB,SAAS,EACjC,SAAyB;IAEzB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC;IAC/B,MAAM,YAAY,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,MAAM,mBAAmB,GAA4B,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;IAE1E,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;IAEtE,MAAM,IAAI,GAAyC;QACjD,SAAS,EAAE,YAAY,IAAI,QAAQ;QACnC,UAAU,EAAE,mBAAmB;QAC/B,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,cAAc,EAAE,aAAa;QAC7B,UAAU,EAAE,WAAW;QACvB,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,IAAI;QACpC,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,IAAI;QAC5C,iBAAiB,EAAE,GAAG,CAAC,GAAG,IAAI,IAAI;QAClC,kBAAkB,EAAE,IAAI;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical event schema — minimal field extraction from Claude and Cursor hook payloads.
|
|
3
|
+
*
|
|
4
|
+
* No normalization happens here. Raw tool_name, tool_input, and the full raw_event
|
|
5
|
+
* are forwarded to the backend, which owns all agent-specific canonicalization and
|
|
6
|
+
* rule evaluation (see tool_call_audit/classification/enrich.py).
|
|
7
|
+
*
|
|
8
|
+
* The only client-side work is:
|
|
9
|
+
* - agent detection (to set agent_identity)
|
|
10
|
+
* - session_id / tool_use_id extraction (needed for auth and dedup)
|
|
11
|
+
* - user_prompt extraction (requires reading local files the backend cannot access)
|
|
12
|
+
*/
|
|
13
|
+
export interface CanonicalHookInput {
|
|
14
|
+
agent: "claude" | "cursor" | "unknown";
|
|
15
|
+
hook_event_name: string;
|
|
16
|
+
tool_name: string;
|
|
17
|
+
tool_input: Record<string, unknown>;
|
|
18
|
+
tool_use_id?: string | null;
|
|
19
|
+
session_id?: string | null;
|
|
20
|
+
cwd?: string | null;
|
|
21
|
+
model?: string | null;
|
|
22
|
+
user_prompt?: string | null;
|
|
23
|
+
raw_event: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
export declare function normalizeToCanonical(raw: Record<string, unknown>): CanonicalHookInput;
|
|
26
|
+
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAmBrF"}
|