f8d07dab61
- omp-usage.js / opencode-usage.js: poll each CLI's own session store into sessions (tool omp/opencode), token_usage per model and subagent agents; transcript routes read them (omp journals, OpenCode's opencode.db). - Grok runs the Claude hooks in ~/.claude/settings.json: its hooks are now recognised (hookEventName + workspaceRoot), tagged tool=grok, and their transcript_path dropped instead of being parsed as a Claude transcript. - Catalog `resumeById`: omp/Grok/Cursor `--resume <id>`, OpenCode `--session <id>`; session ids may carry `_`. The client offers Resume for any tool that resumes by id. - Kimi Code and GitHub Copilot leave the catalog (their session stores could not be verified).
89 lines
3.3 KiB
JavaScript
89 lines
3.3 KiB
JavaScript
/**
|
|
* @file Tests POST /api/hooks/event for a hook Grok Build fired through the
|
|
* Claude hooks in `~/.claude/settings.json` (Grok's Claude compatibility): it
|
|
* arrives with no `tool`, is told apart by the camelCase keys only Grok sends
|
|
* (`hookEventName`, `workspaceRoot`), and lands as a `tool = 'grok'` session
|
|
* on the grok workspace — never the claude one sharing the directory — with
|
|
* its `transcript_path` dropped. A Claude hook is left Claude's. The DB lives
|
|
* in a temp dir.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
const { describe, it, before, after } = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const path = require("node:path");
|
|
const os = require("node:os");
|
|
const fs = require("node:fs");
|
|
|
|
const ROOT = fs.mkdtempSync(path.join(os.tmpdir(), "agenthub-grok-hook-route-"));
|
|
process.env.DASHBOARD_DB_PATH = path.join(ROOT, "dashboard.db");
|
|
process.env.CLAUDE_HOME = path.join(ROOT, "claude");
|
|
process.env.DASHBOARD_LIVENESS_PROBE = "0";
|
|
|
|
const { createApp, startServer } = require("../index");
|
|
const { db } = require("../db");
|
|
const lanes = require("../lib/lanes");
|
|
|
|
let server;
|
|
let BASE;
|
|
const CWD = path.join(fs.realpathSync(ROOT), "repo");
|
|
fs.mkdirSync(CWD, { recursive: true });
|
|
|
|
before(async () => {
|
|
server = await startServer(createApp(), 0);
|
|
BASE = `http://127.0.0.1:${server.address().port}`;
|
|
});
|
|
after(() => {
|
|
server.close();
|
|
fs.rmSync(ROOT, { recursive: true, force: true });
|
|
});
|
|
|
|
const post = (body) =>
|
|
fetch(`${BASE}/api/hooks/event`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(body),
|
|
}).then((r) => r.json());
|
|
|
|
const grokData = (id, extra = {}) => ({
|
|
hookEventName: "session_start",
|
|
hook_event_name: "SessionStart",
|
|
sessionId: id,
|
|
session_id: id,
|
|
cwd: CWD,
|
|
workspaceRoot: CWD,
|
|
transcript_path: path.join(ROOT, "grok", "sessions", id, "chat_history.jsonl"),
|
|
permissionMode: "default",
|
|
...extra,
|
|
});
|
|
|
|
describe("Grok hooks through the Claude settings", () => {
|
|
it("records a grok session, on the grok workspace, with no transcript path", async () => {
|
|
const claudeLane = lanes.createLane({ title: "c", cwd: CWD, tool: "claude" });
|
|
const grokLane = lanes.createLane({ title: "g", cwd: CWD, tool: "grok" });
|
|
const id = "0199f0aa-1111-7222-8333-444455556666";
|
|
await post({ hook_type: "SessionStart", data: grokData(id) });
|
|
await post({
|
|
hook_type: "UserPromptSubmit",
|
|
data: grokData(id, { hookEventName: "user_prompt_submit", prompt: "fix the bug" }),
|
|
});
|
|
const s = db.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
assert.equal(s.tool, "grok");
|
|
assert.equal(s.transcript_path, null);
|
|
const events = db.prepare("SELECT data FROM events WHERE session_id = ?").all(id);
|
|
assert.ok(events.length >= 1);
|
|
for (const e of events) assert.equal(JSON.parse(e.data).transcript_path, undefined);
|
|
assert.equal(lanes.getLane(claudeLane.id).session_id, null);
|
|
assert.equal(lanes.getLane(grokLane.id).session_id, id);
|
|
});
|
|
|
|
it("leaves a Claude hook Claude's", async () => {
|
|
const id = "0199f0aa-1111-7222-8333-777788889999";
|
|
await post({
|
|
hook_type: "SessionStart",
|
|
data: { hook_event_name: "SessionStart", session_id: id, cwd: CWD },
|
|
});
|
|
assert.equal(db.prepare("SELECT tool FROM sessions WHERE id = ?").get(id).tool, "claude");
|
|
});
|
|
});
|