olakai-cli 0.1.12 → 0.1.14

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/dist/index.js CHANGED
@@ -668,6 +668,32 @@ async function getActivityKpis(options) {
668
668
  }
669
669
  return await response.json();
670
670
  }
671
+ async function listSessions(options) {
672
+ const token = getValidToken();
673
+ if (!token) {
674
+ throw new Error("Not logged in. Run 'olakai login' first.");
675
+ }
676
+ const params = new URLSearchParams();
677
+ params.set("agentId", options.agentId);
678
+ if (options.since) params.set("since", options.since);
679
+ if (options.until) params.set("until", options.until);
680
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
681
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
682
+ const url = `${getBaseUrl()}/api/activity/sessions?${params}`;
683
+ const response = await fetch(url, {
684
+ headers: {
685
+ Authorization: `Bearer ${token}`
686
+ }
687
+ });
688
+ if (!response.ok) {
689
+ if (response.status === 401) {
690
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
691
+ }
692
+ const error = await response.json();
693
+ throw new Error(error.error || "Failed to list sessions");
694
+ }
695
+ return await response.json();
696
+ }
671
697
  async function listCustomDataConfigs(agentId) {
672
698
  const token = getValidToken();
673
699
  if (!token) {
@@ -1902,15 +1928,15 @@ function formatActivityTable(data) {
1902
1928
  return;
1903
1929
  }
1904
1930
  const headers = ["ID", "AGENT", "APP", "MODEL", "TOKENS", "TIME(ms)", "RISK", "STATUS"];
1905
- const rows = data.prompts.map((prompt) => [
1906
- prompt.id.slice(0, 12) + "...",
1907
- prompt.agentName || (prompt.agentId ? prompt.agentId.slice(0, 12) + "..." : "-"),
1908
- prompt.app.slice(0, 12),
1909
- prompt.modelId?.slice(0, 15) || "-",
1910
- String(prompt.tokens),
1911
- String(prompt.requestTime),
1912
- prompt.isHighRisk ? "Yes" : "No",
1913
- prompt.decorationStatus.slice(0, 10)
1931
+ const rows = data.prompts.map((prompt2) => [
1932
+ prompt2.id.slice(0, 12) + "...",
1933
+ prompt2.agentName || (prompt2.agentId ? prompt2.agentId.slice(0, 12) + "..." : "-"),
1934
+ prompt2.app.slice(0, 12),
1935
+ prompt2.modelId?.slice(0, 15) || "-",
1936
+ String(prompt2.tokens),
1937
+ String(prompt2.requestTime),
1938
+ prompt2.isHighRisk ? "Yes" : "No",
1939
+ prompt2.decorationStatus.slice(0, 10)
1914
1940
  ]);
1915
1941
  const widths = headers.map(
1916
1942
  (h, i) => Math.max(h.length, ...rows.map((r) => r[i].length))
@@ -1926,51 +1952,51 @@ function formatActivityTable(data) {
1926
1952
  console.log(`Use --offset ${data.offset + data.limit} to see more results`);
1927
1953
  }
1928
1954
  }
1929
- function formatActivityDetail(prompt) {
1930
- console.log(`ID: ${prompt.id}`);
1931
- console.log(`Created: ${prompt.createdAt}`);
1932
- console.log(`Agent: ${prompt.agentName || "-"} (${prompt.agentId || "-"})`);
1933
- console.log(`Workflow: ${prompt.workflowName || "-"} (${prompt.workflowId || "-"})`);
1934
- if (prompt.taskExecutionId) {
1935
- console.log(`Task Exec ID: ${prompt.taskExecutionId}`);
1936
- }
1937
- console.log(`App: ${prompt.app}`);
1938
- console.log(`Model: ${prompt.modelId || "-"} (${prompt.modelType || "-"})`);
1939
- console.log(`Tokens: ${prompt.tokens}`);
1940
- console.log(`Request Time: ${prompt.requestTime}ms`);
1941
- console.log(`High Risk: ${prompt.isHighRisk ? "Yes" : "No"}`);
1942
- console.log(`Blocked: ${prompt.blocked ? "Yes" : "No"}`);
1943
- console.log(`Status: ${prompt.decorationStatus}`);
1944
- if (prompt.sensitivity && prompt.sensitivity.length > 0) {
1945
- console.log(`Sensitivity: ${prompt.sensitivity.join(", ")}`);
1946
- }
1947
- if (prompt.analytics) {
1955
+ function formatActivityDetail(prompt2) {
1956
+ console.log(`ID: ${prompt2.id}`);
1957
+ console.log(`Created: ${prompt2.createdAt}`);
1958
+ console.log(`Agent: ${prompt2.agentName || "-"} (${prompt2.agentId || "-"})`);
1959
+ console.log(`Workflow: ${prompt2.workflowName || "-"} (${prompt2.workflowId || "-"})`);
1960
+ if (prompt2.taskExecutionId) {
1961
+ console.log(`Task Exec ID: ${prompt2.taskExecutionId}`);
1962
+ }
1963
+ console.log(`App: ${prompt2.app}`);
1964
+ console.log(`Model: ${prompt2.modelId || "-"} (${prompt2.modelType || "-"})`);
1965
+ console.log(`Tokens: ${prompt2.tokens}`);
1966
+ console.log(`Request Time: ${prompt2.requestTime}ms`);
1967
+ console.log(`High Risk: ${prompt2.isHighRisk ? "Yes" : "No"}`);
1968
+ console.log(`Blocked: ${prompt2.blocked ? "Yes" : "No"}`);
1969
+ console.log(`Status: ${prompt2.decorationStatus}`);
1970
+ if (prompt2.sensitivity && prompt2.sensitivity.length > 0) {
1971
+ console.log(`Sensitivity: ${prompt2.sensitivity.join(", ")}`);
1972
+ }
1973
+ if (prompt2.analytics) {
1948
1974
  console.log("");
1949
1975
  console.log("Analytics:");
1950
- console.log(` Task: ${prompt.analytics.task || "-"}`);
1951
- console.log(` Subtask: ${prompt.analytics.subtask || "-"}`);
1952
- console.log(` Time Saved: ${prompt.analytics.timesaved_minutes ?? "-"} minutes`);
1953
- console.log(` Risk Score: ${prompt.analytics.riskassessment_dangerousity ?? "-"}`);
1976
+ console.log(` Task: ${prompt2.analytics.task || "-"}`);
1977
+ console.log(` Subtask: ${prompt2.analytics.subtask || "-"}`);
1978
+ console.log(` Time Saved: ${prompt2.analytics.timesaved_minutes ?? "-"} minutes`);
1979
+ console.log(` Risk Score: ${prompt2.analytics.riskassessment_dangerousity ?? "-"}`);
1954
1980
  }
1955
- if (prompt.kpiData && Object.keys(prompt.kpiData).length > 0) {
1981
+ if (prompt2.kpiData && Object.keys(prompt2.kpiData).length > 0) {
1956
1982
  console.log("");
1957
1983
  console.log("KPIs:");
1958
- for (const [key, value] of Object.entries(prompt.kpiData)) {
1984
+ for (const [key, value] of Object.entries(prompt2.kpiData)) {
1959
1985
  console.log(` ${key}: ${value}`);
1960
1986
  }
1961
1987
  }
1962
- if (prompt.prompt !== void 0) {
1988
+ if (prompt2.prompt !== void 0) {
1963
1989
  console.log("");
1964
1990
  console.log("Prompt:");
1965
1991
  console.log("---");
1966
- console.log(prompt.prompt.slice(0, 1e3) + (prompt.prompt.length > 1e3 ? "..." : ""));
1992
+ console.log(prompt2.prompt.slice(0, 1e3) + (prompt2.prompt.length > 1e3 ? "..." : ""));
1967
1993
  console.log("---");
1968
1994
  }
1969
- if (prompt.response !== void 0) {
1995
+ if (prompt2.response !== void 0) {
1970
1996
  console.log("");
1971
1997
  console.log("Response:");
1972
1998
  console.log("---");
1973
- console.log(prompt.response.slice(0, 1e3) + (prompt.response.length > 1e3 ? "..." : ""));
1999
+ console.log(prompt2.response.slice(0, 1e3) + (prompt2.response.length > 1e3 ? "..." : ""));
1974
2000
  console.log("---");
1975
2001
  }
1976
2002
  }
@@ -2046,11 +2072,11 @@ async function listCommand5(options) {
2046
2072
  }
2047
2073
  async function getCommand5(id, options) {
2048
2074
  try {
2049
- const prompt = await getActivity(id, options.includeContent);
2075
+ const prompt2 = await getActivity(id, options.includeContent);
2050
2076
  if (options.json) {
2051
- console.log(JSON.stringify(prompt, null, 2));
2077
+ console.log(JSON.stringify(prompt2, null, 2));
2052
2078
  } else {
2053
- formatActivityDetail(prompt);
2079
+ formatActivityDetail(prompt2);
2054
2080
  }
2055
2081
  } catch (error) {
2056
2082
  console.error(
@@ -2085,11 +2111,485 @@ async function kpisCommand(options) {
2085
2111
  process.exit(1);
2086
2112
  }
2087
2113
  }
2114
+ function formatSessionsTable(data) {
2115
+ console.log("Session Decoration Status");
2116
+ console.log("");
2117
+ console.log("Summary:");
2118
+ console.log(` Total Sessions: ${data.summary.sessionCount}`);
2119
+ const statuses = ["DECORATED", "NEW", "DECORATION_FAILED", "DECORATION_OUTDATED", "SKIPPED"];
2120
+ for (const status of statuses) {
2121
+ const count = data.summary.byStatus[status] || 0;
2122
+ const pct = data.summary.sessionCount > 0 ? (count / data.summary.sessionCount * 100).toFixed(1) : "0.0";
2123
+ const label = status.charAt(0) + status.slice(1).toLowerCase().replace(/_/g, " ");
2124
+ console.log(` ${label.padEnd(17)} ${String(count).padStart(4)} (${pct}%)`);
2125
+ }
2126
+ if (data.sessions.length === 0) {
2127
+ console.log("");
2128
+ console.log("No sessions found.");
2129
+ return;
2130
+ }
2131
+ console.log("");
2132
+ const headers = ["ID", "STATUS", "DATE", "CANDIDATE", "ERRORS", "KPI DATA", "VERSION"];
2133
+ const rows = data.sessions.map((s) => [
2134
+ s.id.slice(0, 15) + "...",
2135
+ s.decorationStatus,
2136
+ s.decorationDate || "-",
2137
+ s.decorationCandidate ? "Yes" : "No",
2138
+ String(s.decorationErrorStreak),
2139
+ s.hasKpiData ? "Yes" : "No",
2140
+ s.decoratorVersion || "-"
2141
+ ]);
2142
+ const widths = headers.map(
2143
+ (h, i) => Math.max(h.length, ...rows.map((r) => r[i].length))
2144
+ );
2145
+ console.log(headers.map((h, i) => h.padEnd(widths[i])).join(" "));
2146
+ console.log(widths.map((w) => "-".repeat(w)).join(" "));
2147
+ for (const row of rows) {
2148
+ console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(" "));
2149
+ }
2150
+ console.log("");
2151
+ console.log(`Showing ${data.sessions.length} of ${data.total} results (offset: ${data.offset})`);
2152
+ if (data.hasMore) {
2153
+ console.log(`Use --offset ${data.offset + data.limit} to see more results`);
2154
+ }
2155
+ }
2156
+ async function sessionsCommand(options) {
2157
+ try {
2158
+ const data = await listSessions({
2159
+ agentId: options.agentId,
2160
+ since: options.since,
2161
+ until: options.until,
2162
+ limit: options.limit ? parseInt(options.limit, 10) : void 0,
2163
+ offset: options.offset ? parseInt(options.offset, 10) : void 0
2164
+ });
2165
+ if (options.json) {
2166
+ console.log(JSON.stringify(data, null, 2));
2167
+ } else {
2168
+ formatSessionsTable(data);
2169
+ }
2170
+ } catch (error) {
2171
+ console.error(
2172
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
2173
+ );
2174
+ process.exit(1);
2175
+ }
2176
+ }
2088
2177
  function registerActivityCommand(program2) {
2089
2178
  const activity = program2.command("activity").description("Inspect AI activity and prompts");
2090
2179
  activity.command("list").description("List prompt requests with filters").option("--agent-id <id>", "Filter by agent ID").option("--workflow-id <id>", "Filter by workflow ID").option("--since <date>", "Start date (ISO format)").option("--until <date>", "End date (ISO format)").option("--limit <n>", "Results per page", "20").option("--offset <n>", "Skip first N results", "0").option("--include-content", "Include prompt/response content").option("--include-analytics", "Include advanced analytics").option("--json", "Output as JSON").action(listCommand5);
2091
2180
  activity.command("get <id>").description("Get prompt request details").option("--include-content", "Include prompt/response content").option("--json", "Output as JSON").action(getCommand5);
2092
2181
  activity.command("kpis").description("Get aggregated KPI values").option("--agent-id <id>", "Agent ID").option("--workflow-id <id>", "Workflow ID").option("--since <date>", "Period start (ISO format)").option("--until <date>", "Period end (ISO format)").option("--period <type>", "Aggregation period (hourly, daily, weekly)").option("--include-atoms", "Include per-prompt KPI data").option("--json", "Output as JSON").action(kpisCommand);
2182
+ activity.command("sessions").description("Inspect chat/session decoration status for troubleshooting").requiredOption("--agent-id <id>", "Agent ID (required)").option("--since <date>", "Start date (ISO format)").option("--until <date>", "End date (ISO format)").option("--limit <n>", "Results per page", "20").option("--offset <n>", "Skip first N results", "0").option("--json", "Output as JSON").action(sessionsCommand);
2183
+ }
2184
+
2185
+ // src/commands/monitor.ts
2186
+ import * as fs2 from "fs";
2187
+ import * as path2 from "path";
2188
+ import * as readline from "readline";
2189
+ var CLAUDE_DIR = ".claude";
2190
+ var SETTINGS_FILE = "settings.json";
2191
+ var MONITOR_CONFIG_FILE = "olakai-monitor.json";
2192
+ var OLAKAI_HOOK_MARKER = "olakai monitor hook";
2193
+ var HOOK_DEFINITIONS = {
2194
+ Stop: [
2195
+ {
2196
+ matcher: "",
2197
+ hooks: [
2198
+ {
2199
+ type: "command",
2200
+ command: "olakai monitor hook stop"
2201
+ }
2202
+ ]
2203
+ }
2204
+ ]
2205
+ };
2206
+ function prompt(question) {
2207
+ const rl = readline.createInterface({
2208
+ input: process.stdin,
2209
+ output: process.stdout
2210
+ });
2211
+ return new Promise((resolve) => {
2212
+ rl.question(question, (answer) => {
2213
+ rl.close();
2214
+ resolve(answer.trim());
2215
+ });
2216
+ });
2217
+ }
2218
+ function findProjectRoot(startDir) {
2219
+ let dir = startDir ?? process.cwd();
2220
+ while (true) {
2221
+ if (fs2.existsSync(path2.join(dir, CLAUDE_DIR))) {
2222
+ return dir;
2223
+ }
2224
+ const parent = path2.dirname(dir);
2225
+ if (parent === dir) break;
2226
+ dir = parent;
2227
+ }
2228
+ return startDir ?? process.cwd();
2229
+ }
2230
+ function getClaudeDir(projectRoot) {
2231
+ return path2.join(projectRoot, CLAUDE_DIR);
2232
+ }
2233
+ function getSettingsPath(projectRoot) {
2234
+ return path2.join(getClaudeDir(projectRoot), SETTINGS_FILE);
2235
+ }
2236
+ function getMonitorConfigPath(projectRoot) {
2237
+ return path2.join(getClaudeDir(projectRoot), MONITOR_CONFIG_FILE);
2238
+ }
2239
+ function readJsonFile(filePath) {
2240
+ try {
2241
+ if (!fs2.existsSync(filePath)) return null;
2242
+ const content = fs2.readFileSync(filePath, "utf-8");
2243
+ return JSON.parse(content);
2244
+ } catch {
2245
+ return null;
2246
+ }
2247
+ }
2248
+ function writeJsonFile(filePath, data) {
2249
+ const dir = path2.dirname(filePath);
2250
+ if (!fs2.existsSync(dir)) {
2251
+ fs2.mkdirSync(dir, { recursive: true });
2252
+ }
2253
+ fs2.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
2254
+ }
2255
+ function loadMonitorConfig(projectRoot) {
2256
+ const root = projectRoot ?? findProjectRoot();
2257
+ return readJsonFile(getMonitorConfigPath(root));
2258
+ }
2259
+ function readStdin(timeoutMs = 3e3) {
2260
+ return new Promise((resolve) => {
2261
+ if (process.stdin.isTTY) {
2262
+ resolve("");
2263
+ return;
2264
+ }
2265
+ let data = "";
2266
+ const timer = setTimeout(() => {
2267
+ process.stdin.removeAllListeners();
2268
+ process.stdin.destroy();
2269
+ resolve(data);
2270
+ }, timeoutMs);
2271
+ process.stdin.setEncoding("utf-8");
2272
+ process.stdin.on("data", (chunk) => {
2273
+ data += chunk;
2274
+ });
2275
+ process.stdin.on("end", () => {
2276
+ clearTimeout(timer);
2277
+ resolve(data);
2278
+ });
2279
+ process.stdin.on("error", () => {
2280
+ clearTimeout(timer);
2281
+ resolve(data);
2282
+ });
2283
+ });
2284
+ }
2285
+ async function initCommand() {
2286
+ const token = getValidToken();
2287
+ if (!token) {
2288
+ console.error("Not logged in. Run 'olakai login' first.");
2289
+ process.exit(1);
2290
+ }
2291
+ console.log("Setting up Claude Code monitoring for this workspace...\n");
2292
+ const projectRoot = process.cwd();
2293
+ const dirName = path2.basename(projectRoot);
2294
+ let agent;
2295
+ const choice = await prompt(
2296
+ "Create a new agent or use an existing one? (new/existing) [new]: "
2297
+ );
2298
+ if (choice.toLowerCase() === "existing" || choice.toLowerCase() === "e") {
2299
+ const agents = await listAgents();
2300
+ if (agents.length === 0) {
2301
+ console.log("No agents found. Creating a new one instead.\n");
2302
+ agent = await createNewAgent(dirName);
2303
+ } else {
2304
+ console.log("\nAvailable agents:");
2305
+ for (let i = 0; i < agents.length; i++) {
2306
+ console.log(` ${i + 1}. ${agents[i].name} (${agents[i].id.slice(0, 12)}...)`);
2307
+ }
2308
+ const selection = await prompt(`
2309
+ Select agent (1-${agents.length}): `);
2310
+ const idx = parseInt(selection, 10) - 1;
2311
+ if (isNaN(idx) || idx < 0 || idx >= agents.length) {
2312
+ console.error("Invalid selection.");
2313
+ process.exit(1);
2314
+ }
2315
+ agent = await getAgent(agents[idx].id);
2316
+ if (!agent.apiKey?.key && !agent.apiKey?.isActive) {
2317
+ console.log(
2318
+ "\nThis agent has no active API key. Please create a new agent instead,"
2319
+ );
2320
+ console.log("or generate an API key via the Olakai dashboard.\n");
2321
+ const createNew = await prompt("Create a new agent? (y/n) [y]: ");
2322
+ if (createNew.toLowerCase() !== "n") {
2323
+ agent = await createNewAgent(dirName);
2324
+ } else {
2325
+ process.exit(1);
2326
+ }
2327
+ }
2328
+ }
2329
+ } else {
2330
+ agent = await createNewAgent(dirName);
2331
+ }
2332
+ let apiKey = agent.apiKey?.key;
2333
+ if (!apiKey) {
2334
+ console.log(
2335
+ "\nThe API key for this agent is not available (it is only shown once at creation)."
2336
+ );
2337
+ apiKey = await prompt("Paste the API key for this agent: ");
2338
+ if (!apiKey) {
2339
+ console.error("API key is required for monitoring.");
2340
+ process.exit(1);
2341
+ }
2342
+ }
2343
+ const claudeDir = getClaudeDir(projectRoot);
2344
+ if (!fs2.existsSync(claudeDir)) {
2345
+ fs2.mkdirSync(claudeDir, { recursive: true });
2346
+ }
2347
+ const settingsPath = getSettingsPath(projectRoot);
2348
+ const existingSettings = readJsonFile(settingsPath) ?? {};
2349
+ const mergedHooks = {
2350
+ ...existingSettings.hooks ?? {}
2351
+ };
2352
+ for (const [event, entries] of Object.entries(HOOK_DEFINITIONS)) {
2353
+ const existing = mergedHooks[event] ?? [];
2354
+ const filtered = existing.filter(
2355
+ (e) => !e.hooks.some((h) => h.command.includes(OLAKAI_HOOK_MARKER))
2356
+ );
2357
+ mergedHooks[event] = [...filtered, ...entries];
2358
+ }
2359
+ const updatedSettings = {
2360
+ ...existingSettings,
2361
+ hooks: mergedHooks
2362
+ };
2363
+ writeJsonFile(settingsPath, updatedSettings);
2364
+ const monitoringEndpoint = `${getBaseUrl()}/api/monitoring/prompt`;
2365
+ const monitorConfig = {
2366
+ agentId: agent.id,
2367
+ apiKey,
2368
+ agentName: agent.name,
2369
+ source: "claude-code",
2370
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2371
+ monitoringEndpoint
2372
+ };
2373
+ const monitorConfigPath = getMonitorConfigPath(projectRoot);
2374
+ writeJsonFile(monitorConfigPath, monitorConfig);
2375
+ fs2.chmodSync(monitorConfigPath, 384);
2376
+ console.log("");
2377
+ console.log(`\u2713 Agent "${agent.name}" configured (ID: ${agent.id})`);
2378
+ if (agent.apiKey?.key) {
2379
+ console.log("\u2713 API key generated");
2380
+ }
2381
+ console.log(`\u2713 Claude Code hooks configured in ${CLAUDE_DIR}/${SETTINGS_FILE}`);
2382
+ console.log(`\u2713 Monitor config saved to ${CLAUDE_DIR}/${MONITOR_CONFIG_FILE}`);
2383
+ console.log("");
2384
+ console.log(
2385
+ "Monitoring is now active. Claude Code will report activity to Olakai"
2386
+ );
2387
+ console.log(
2388
+ `on each turn. View activity at: ${getBaseUrl()}/dashboard`
2389
+ );
2390
+ console.log("");
2391
+ console.log(
2392
+ `\u26A0 Ensure ${CLAUDE_DIR}/${MONITOR_CONFIG_FILE} is in your .gitignore (it contains your API key)`
2393
+ );
2394
+ console.log("");
2395
+ console.log("To check status: olakai monitor status");
2396
+ console.log("To disable: olakai monitor disable");
2397
+ }
2398
+ async function createNewAgent(defaultName) {
2399
+ const nameInput = await prompt(
2400
+ `Agent name [${defaultName}]: `
2401
+ );
2402
+ const agentName = nameInput || defaultName;
2403
+ const agent = await createAgent({
2404
+ name: agentName,
2405
+ description: `Claude Code local agent for ${agentName}`,
2406
+ role: "WORKER",
2407
+ createApiKey: true,
2408
+ category: "CODING",
2409
+ source: "CLAUDE_CODE"
2410
+ });
2411
+ return agent;
2412
+ }
2413
+ async function hookCommand(event) {
2414
+ try {
2415
+ const config = loadMonitorConfig();
2416
+ if (!config) {
2417
+ return;
2418
+ }
2419
+ const stdinData = await readStdin(3e3);
2420
+ let eventData = {};
2421
+ if (stdinData) {
2422
+ try {
2423
+ eventData = JSON.parse(stdinData);
2424
+ } catch {
2425
+ return;
2426
+ }
2427
+ }
2428
+ const payload = buildPayload(event, eventData, config);
2429
+ if (!payload) {
2430
+ return;
2431
+ }
2432
+ const controller = new AbortController();
2433
+ const timeoutId = setTimeout(() => controller.abort(), 5e3);
2434
+ try {
2435
+ await fetch(config.monitoringEndpoint, {
2436
+ method: "POST",
2437
+ headers: {
2438
+ "x-api-key": config.apiKey,
2439
+ "Content-Type": "application/json"
2440
+ },
2441
+ body: JSON.stringify([payload]),
2442
+ signal: controller.signal
2443
+ });
2444
+ } finally {
2445
+ clearTimeout(timeoutId);
2446
+ }
2447
+ } catch {
2448
+ }
2449
+ }
2450
+ function buildPayload(event, eventData, config) {
2451
+ const sessionId = eventData.session_id ?? `claude-code-${Date.now()}`;
2452
+ switch (event) {
2453
+ case "stop": {
2454
+ return {
2455
+ prompt: eventData.prompt ?? "",
2456
+ response: eventData.response ?? "",
2457
+ chatId: sessionId,
2458
+ source: config.source,
2459
+ modelName: eventData.model,
2460
+ tokens: eventData.total_tokens_in !== void 0 && eventData.total_tokens_out !== void 0 ? eventData.total_tokens_in + eventData.total_tokens_out : void 0,
2461
+ requestTime: eventData.duration_api_ms,
2462
+ customData: {
2463
+ hookEvent: "Stop",
2464
+ stopReason: eventData.stop_reason ?? "",
2465
+ totalTokensIn: eventData.total_tokens_in ?? 0,
2466
+ totalTokensOut: eventData.total_tokens_out ?? 0,
2467
+ totalCost: eventData.total_cost ?? 0,
2468
+ durationMs: eventData.duration_ms ?? 0,
2469
+ numTurns: eventData.num_turns ?? 0
2470
+ }
2471
+ };
2472
+ }
2473
+ default:
2474
+ return null;
2475
+ }
2476
+ }
2477
+ async function statusCommand(options) {
2478
+ const projectRoot = findProjectRoot();
2479
+ const config = loadMonitorConfig(projectRoot);
2480
+ if (!config) {
2481
+ console.log("Monitoring is not configured for this workspace.");
2482
+ console.log("Run 'olakai monitor init' to set up monitoring.");
2483
+ process.exit(1);
2484
+ }
2485
+ const settings = readJsonFile(getSettingsPath(projectRoot));
2486
+ const hooksPresent = settings?.hooks ? Object.values(settings.hooks).some(
2487
+ (entries) => entries.some(
2488
+ (e) => e.hooks.some((h) => h.command.includes(OLAKAI_HOOK_MARKER))
2489
+ )
2490
+ ) : false;
2491
+ if (options.json) {
2492
+ console.log(
2493
+ JSON.stringify(
2494
+ {
2495
+ ...config,
2496
+ apiKey: config.apiKey.slice(0, 12) + "...",
2497
+ hooksConfigured: hooksPresent
2498
+ },
2499
+ null,
2500
+ 2
2501
+ )
2502
+ );
2503
+ return;
2504
+ }
2505
+ console.log("Olakai Monitor Status");
2506
+ console.log("=====================");
2507
+ console.log(`Agent: ${config.agentName}`);
2508
+ console.log(`Agent ID: ${config.agentId}`);
2509
+ console.log(`API Key: ${config.apiKey.slice(0, 12)}...`);
2510
+ console.log(`Endpoint: ${config.monitoringEndpoint}`);
2511
+ console.log(`Source: ${config.source}`);
2512
+ console.log(`Configured: ${config.createdAt}`);
2513
+ console.log(`Hooks: ${hooksPresent ? "Active" : "Missing (run 'olakai monitor init' to restore)"}`);
2514
+ try {
2515
+ const token = getValidToken();
2516
+ if (token) {
2517
+ const params = new URLSearchParams({
2518
+ agentId: config.agentId,
2519
+ limit: "5"
2520
+ });
2521
+ const response = await fetch(
2522
+ `${getBaseUrl()}/api/activity/prompts?${params}`,
2523
+ {
2524
+ headers: { Authorization: `Bearer ${token}` }
2525
+ }
2526
+ );
2527
+ if (response.ok) {
2528
+ const data = await response.json();
2529
+ if (data.prompts && data.prompts.length > 0) {
2530
+ console.log("");
2531
+ console.log("Recent Activity:");
2532
+ for (const p of data.prompts) {
2533
+ console.log(` ${p.createdAt} ${p.id.slice(0, 12)}...`);
2534
+ }
2535
+ } else {
2536
+ console.log("");
2537
+ console.log("No activity recorded yet.");
2538
+ }
2539
+ }
2540
+ }
2541
+ } catch {
2542
+ }
2543
+ }
2544
+ async function disableCommand(options) {
2545
+ const projectRoot = findProjectRoot();
2546
+ const settingsPath = getSettingsPath(projectRoot);
2547
+ const settings = readJsonFile(settingsPath);
2548
+ if (settings?.hooks) {
2549
+ const cleanedHooks = {};
2550
+ for (const [event, entries] of Object.entries(settings.hooks)) {
2551
+ const filtered = entries.filter(
2552
+ (e) => !e.hooks.some((h) => h.command.includes(OLAKAI_HOOK_MARKER))
2553
+ );
2554
+ if (filtered.length > 0) {
2555
+ cleanedHooks[event] = filtered;
2556
+ }
2557
+ }
2558
+ if (Object.keys(cleanedHooks).length > 0) {
2559
+ settings.hooks = cleanedHooks;
2560
+ } else {
2561
+ delete settings.hooks;
2562
+ }
2563
+ writeJsonFile(settingsPath, settings);
2564
+ console.log(`\u2713 Olakai hooks removed from ${CLAUDE_DIR}/${SETTINGS_FILE}`);
2565
+ } else {
2566
+ console.log("No hooks found in settings.json.");
2567
+ }
2568
+ if (!options.keepConfig) {
2569
+ const configPath = getMonitorConfigPath(projectRoot);
2570
+ if (fs2.existsSync(configPath)) {
2571
+ fs2.unlinkSync(configPath);
2572
+ console.log(`\u2713 Monitor config removed (${CLAUDE_DIR}/${MONITOR_CONFIG_FILE})`);
2573
+ }
2574
+ } else {
2575
+ console.log(
2576
+ `Monitor config retained at ${CLAUDE_DIR}/${MONITOR_CONFIG_FILE}`
2577
+ );
2578
+ }
2579
+ console.log("");
2580
+ console.log("Monitoring disabled. Run 'olakai monitor init' to re-enable.");
2581
+ }
2582
+ function registerMonitorCommand(program2) {
2583
+ const monitor = program2.command("monitor").description("Monitor Claude Code sessions with Olakai");
2584
+ monitor.command("init").description(
2585
+ "Set up Olakai monitoring for this Claude Code workspace"
2586
+ ).action(initCommand);
2587
+ monitor.command("hook <event>").description("Hook handler called by Claude Code (internal use)").action(hookCommand);
2588
+ monitor.command("status").description("Show monitoring status for this workspace").option("--json", "Output as JSON").action(statusCommand);
2589
+ monitor.command("disable").description("Remove Olakai monitoring from this workspace").option(
2590
+ "--keep-config",
2591
+ "Keep the monitor config file (only remove hooks)"
2592
+ ).action(disableCommand);
2093
2593
  }
2094
2594
 
2095
2595
  // src/index.ts
@@ -2120,5 +2620,6 @@ registerWorkflowsCommand(program);
2120
2620
  registerKpisCommand(program);
2121
2621
  registerCustomDataCommand(program);
2122
2622
  registerActivityCommand(program);
2623
+ registerMonitorCommand(program);
2123
2624
  program.parse();
2124
2625
  //# sourceMappingURL=index.js.map