chore: v2.8.23 — workspace groups, inner repos in Changes (opt-in), sub-agent tokens counted
Workspace groups: named, foldable, ordered sidebar sections kept per account (agenthub.workspace.groups); a workspace joins one from its menu, a drop on the header, a drag under a row, or Alt+Up/Down past a group's edge; headers drag to reorder; a folded header shows its most urgent state; New workspace in this group; fold/unfold all. Inner repos: GET /api/lanes/:id/repos + ?repo= on git/fs routes; the Changes panel shows a parent folder's repos only when Settings -> Git -> Changes panel turns it on (agenthub.changes.innerRepos, off by default). Cost: the hook writer adds a session's sub-agent transcripts to its tokens and hours (server/lib/subagent-usage.js) — a sub-agent on the session's own model was never counted live (~8% of a week here); an imported session is re-raised on every pass, so a claude -p run first seen with an empty transcript no longer stays at $0 (~10%). A one-time raise-only catch-up (user_version 5) re-reads ~/.claude/projects. Also: omp install script may redirect to its exact install.redirect URL (#85, repo-links test exempts it), native paste in the terminal.
This commit is contained in:
+15
-5
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file Express router for handling incoming hook events from Claude CLI — and from Codex (`tool: "codex"`, sent through server/lib/codex-hooks.js: such a session is created as a Codex one, its rollout is never parsed as a Claude transcript, a PermissionRequest becomes the permission Notification, and a sub-agent thread's hooks land on the root session). It processes various hook types (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, Notification), updates session and agent states accordingly in the database, extracts token usage from transcripts, detects compaction events, and broadcasts updates to connected clients via WebSocket. `POST /ingest-batch` takes the same hooks pushed from another machine behind a bearer token (server/lib/push-token.js), tagged with that machine as the session source; a hook from a folder the user ignores is dropped whole (server/lib/privacy.js).
|
||||
* @file Express router for handling incoming hook events from Claude CLI — and from Codex (`tool: "codex"`, sent through server/lib/codex-hooks.js: such a session is created as a Codex one, its rollout is never parsed as a Claude transcript, a PermissionRequest becomes the permission Notification, and a sub-agent thread's hooks land on the root session). It processes various hook types (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, Notification), updates session and agent states accordingly in the database, extracts token usage from transcripts (the session's sub-agent transcripts included, server/lib/subagent-usage.js), detects compaction events, and broadcasts updates to connected clients via WebSocket. `POST /ingest-batch` takes the same hooks pushed from another machine behind a bearer token (server/lib/push-token.js), tagged with that machine as the session source; a hook from a folder the user ignores is dropped whole (server/lib/privacy.js).
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,7 @@ function broadcast(type, data) {
|
||||
}
|
||||
const TranscriptCache = require("../lib/transcript-cache");
|
||||
const { writeHourly } = require("../lib/hourly-usage");
|
||||
const { subagentUsage, addTokens, sameParts } = require("../lib/subagent-usage");
|
||||
const { longArgs } = require("../lib/token-usage");
|
||||
const { scanAndImportSubagents } = require("../../scripts/import-history");
|
||||
const { evaluateEvent } = require("../lib/alerts");
|
||||
@@ -987,7 +988,11 @@ const processEventTx = db.transaction((hookType, data, tool = "claude", peer = n
|
||||
// Already handled (see transcriptMarks): the same result skips the
|
||||
// idempotent writes below, a grown one handles only its new entries.
|
||||
const mark = transcriptMarkFor(sessionId, transcriptPath, session.started_at);
|
||||
const unchanged = !!mark && mark.result === result;
|
||||
// The session's sub-agents spend too: their transcripts' usage joins the
|
||||
// main one's (`lib/subagent-usage.js`), and a sub-agent that grew is a
|
||||
// change even when the main transcript is not.
|
||||
const subs = subagentUsage(transcriptPath);
|
||||
const unchanged = !!mark && mark.result === result && sameParts(mark.subParts, subs?.parts);
|
||||
const lastOf = (arr) => (arr && arr.length ? arr[arr.length - 1] : null);
|
||||
|
||||
// Keep session.model in sync with the user's *current* model — the
|
||||
@@ -1074,10 +1079,11 @@ const processEventTx = db.transaction((hookType, data, tool = "claude", peer = n
|
||||
}
|
||||
}
|
||||
|
||||
if (tokensByModel && !unchanged) {
|
||||
if ((tokensByModel || subs) && !unchanged) {
|
||||
// Each bucket carries its pricing dimensions (model/speed/geo/tier) plus
|
||||
// the 1h cache-write split and server-tool request counts.
|
||||
for (const tokens of Object.values(tokensByModel)) {
|
||||
const allTokens = subs ? addTokens(tokensByModel, subs.tokensByModel) : tokensByModel;
|
||||
for (const tokens of Object.values(allTokens)) {
|
||||
stmts.replaceTokenUsage.run(
|
||||
sessionId,
|
||||
tokens.model,
|
||||
@@ -1105,7 +1111,10 @@ const processEventTx = db.transaction((hookType, data, tool = "claude", peer = n
|
||||
);
|
||||
}
|
||||
}
|
||||
writeHourly(sessionId, result.tokensByHour);
|
||||
writeHourly(
|
||||
sessionId,
|
||||
subs ? addTokens(result.tokensByHour, subs.tokensByHour) : result.tokensByHour
|
||||
);
|
||||
}
|
||||
|
||||
// Register API errors from transcript (quota limits, rate limits, overloaded, etc.)
|
||||
@@ -1229,6 +1238,7 @@ const processEventTx = db.transaction((hookType, data, tool = "claude", peer = n
|
||||
|
||||
queueTranscriptMark(sessionId, transcriptPath, {
|
||||
result,
|
||||
subParts: subs?.parts ?? null,
|
||||
startedAt: session.started_at,
|
||||
compactionUuid: lastOf(compaction?.entries)?.uuid ?? null,
|
||||
lastError: lastOf(result.errors),
|
||||
|
||||
Reference in New Issue
Block a user