olakai-cli 0.1.13 → 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 +452 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1928,15 +1928,15 @@ function formatActivityTable(data) {
|
|
|
1928
1928
|
return;
|
|
1929
1929
|
}
|
|
1930
1930
|
const headers = ["ID", "AGENT", "APP", "MODEL", "TOKENS", "TIME(ms)", "RISK", "STATUS"];
|
|
1931
|
-
const rows = data.prompts.map((
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
String(
|
|
1937
|
-
String(
|
|
1938
|
-
|
|
1939
|
-
|
|
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)
|
|
1940
1940
|
]);
|
|
1941
1941
|
const widths = headers.map(
|
|
1942
1942
|
(h, i) => Math.max(h.length, ...rows.map((r) => r[i].length))
|
|
@@ -1952,51 +1952,51 @@ function formatActivityTable(data) {
|
|
|
1952
1952
|
console.log(`Use --offset ${data.offset + data.limit} to see more results`);
|
|
1953
1953
|
}
|
|
1954
1954
|
}
|
|
1955
|
-
function formatActivityDetail(
|
|
1956
|
-
console.log(`ID: ${
|
|
1957
|
-
console.log(`Created: ${
|
|
1958
|
-
console.log(`Agent: ${
|
|
1959
|
-
console.log(`Workflow: ${
|
|
1960
|
-
if (
|
|
1961
|
-
console.log(`Task Exec ID: ${
|
|
1962
|
-
}
|
|
1963
|
-
console.log(`App: ${
|
|
1964
|
-
console.log(`Model: ${
|
|
1965
|
-
console.log(`Tokens: ${
|
|
1966
|
-
console.log(`Request Time: ${
|
|
1967
|
-
console.log(`High Risk: ${
|
|
1968
|
-
console.log(`Blocked: ${
|
|
1969
|
-
console.log(`Status: ${
|
|
1970
|
-
if (
|
|
1971
|
-
console.log(`Sensitivity: ${
|
|
1972
|
-
}
|
|
1973
|
-
if (
|
|
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) {
|
|
1974
1974
|
console.log("");
|
|
1975
1975
|
console.log("Analytics:");
|
|
1976
|
-
console.log(` Task: ${
|
|
1977
|
-
console.log(` Subtask: ${
|
|
1978
|
-
console.log(` Time Saved: ${
|
|
1979
|
-
console.log(` Risk Score: ${
|
|
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 ?? "-"}`);
|
|
1980
1980
|
}
|
|
1981
|
-
if (
|
|
1981
|
+
if (prompt2.kpiData && Object.keys(prompt2.kpiData).length > 0) {
|
|
1982
1982
|
console.log("");
|
|
1983
1983
|
console.log("KPIs:");
|
|
1984
|
-
for (const [key, value] of Object.entries(
|
|
1984
|
+
for (const [key, value] of Object.entries(prompt2.kpiData)) {
|
|
1985
1985
|
console.log(` ${key}: ${value}`);
|
|
1986
1986
|
}
|
|
1987
1987
|
}
|
|
1988
|
-
if (
|
|
1988
|
+
if (prompt2.prompt !== void 0) {
|
|
1989
1989
|
console.log("");
|
|
1990
1990
|
console.log("Prompt:");
|
|
1991
1991
|
console.log("---");
|
|
1992
|
-
console.log(
|
|
1992
|
+
console.log(prompt2.prompt.slice(0, 1e3) + (prompt2.prompt.length > 1e3 ? "..." : ""));
|
|
1993
1993
|
console.log("---");
|
|
1994
1994
|
}
|
|
1995
|
-
if (
|
|
1995
|
+
if (prompt2.response !== void 0) {
|
|
1996
1996
|
console.log("");
|
|
1997
1997
|
console.log("Response:");
|
|
1998
1998
|
console.log("---");
|
|
1999
|
-
console.log(
|
|
1999
|
+
console.log(prompt2.response.slice(0, 1e3) + (prompt2.response.length > 1e3 ? "..." : ""));
|
|
2000
2000
|
console.log("---");
|
|
2001
2001
|
}
|
|
2002
2002
|
}
|
|
@@ -2072,11 +2072,11 @@ async function listCommand5(options) {
|
|
|
2072
2072
|
}
|
|
2073
2073
|
async function getCommand5(id, options) {
|
|
2074
2074
|
try {
|
|
2075
|
-
const
|
|
2075
|
+
const prompt2 = await getActivity(id, options.includeContent);
|
|
2076
2076
|
if (options.json) {
|
|
2077
|
-
console.log(JSON.stringify(
|
|
2077
|
+
console.log(JSON.stringify(prompt2, null, 2));
|
|
2078
2078
|
} else {
|
|
2079
|
-
formatActivityDetail(
|
|
2079
|
+
formatActivityDetail(prompt2);
|
|
2080
2080
|
}
|
|
2081
2081
|
} catch (error) {
|
|
2082
2082
|
console.error(
|
|
@@ -2182,6 +2182,416 @@ function registerActivityCommand(program2) {
|
|
|
2182
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
2183
|
}
|
|
2184
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);
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2185
2595
|
// src/index.ts
|
|
2186
2596
|
var require2 = createRequire(import.meta.url);
|
|
2187
2597
|
var packageJson = require2("../package.json");
|
|
@@ -2210,5 +2620,6 @@ registerWorkflowsCommand(program);
|
|
|
2210
2620
|
registerKpisCommand(program);
|
|
2211
2621
|
registerCustomDataCommand(program);
|
|
2212
2622
|
registerActivityCommand(program);
|
|
2623
|
+
registerMonitorCommand(program);
|
|
2213
2624
|
program.parse();
|
|
2214
2625
|
//# sourceMappingURL=index.js.map
|