feat(ai-tools): omp shared + OpenCode/omp sessions, tokens, subagents; Grok hooks; resume by id
- 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).
This commit is contained in:
+15
-7
@@ -295,16 +295,18 @@ function buildCodexArgv({
|
||||
|
||||
/**
|
||||
* Any catalog tool without a hand-written launcher: `[bin, ...args, ...resume?,
|
||||
* ...bypass?, ...prompt]` (`[flag, model]` right after the fixed args when the
|
||||
* ...bypass?, ...prompt]` (`...resumeById, <id>` in place of `resume` for a
|
||||
* named session; `[flag, model]` right after the fixed args when the
|
||||
* catalog declares a model flag). Every piece but the prompt and the
|
||||
* validated model comes from the catalog
|
||||
* file, and the prompt is one argv element — or, for `after-start`, nothing
|
||||
* here: spawnRun pastes it into the pane once the CLI is up.
|
||||
*/
|
||||
function buildCatalogArgv(entry, bin, { model, resumeLast, bypass, initialPrompt }) {
|
||||
function buildCatalogArgv(entry, bin, { model, resumeSessionId, resumeLast, bypass, initialPrompt }) {
|
||||
const argv = [bin, ...entry.args];
|
||||
if (model && entry.model) argv.push(entry.model.flag, model);
|
||||
if (resumeLast && entry.resume) argv.push(...entry.resume);
|
||||
if (resumeSessionId && entry.resumeById) argv.push(...entry.resumeById, resumeSessionId);
|
||||
else if (resumeLast && entry.resume) argv.push(...entry.resume);
|
||||
if (bypass && entry.bypass) argv.push(...entry.bypass);
|
||||
const p = entry.prompt;
|
||||
if (initialPrompt && p.mode === "flag") argv.push(p.flag, promptArg(initialPrompt));
|
||||
@@ -437,15 +439,21 @@ function spawnRun(args) {
|
||||
}
|
||||
if (
|
||||
resumeSessionId != null &&
|
||||
(typeof resumeSessionId !== "string" || !/^[A-Za-z0-9-]{8,}$/.test(resumeSessionId))
|
||||
(typeof resumeSessionId !== "string" || !/^[A-Za-z0-9_-]{8,}$/.test(resumeSessionId))
|
||||
) {
|
||||
throw makeErr("EBADSESSION", "resumeSessionId is not a valid session id");
|
||||
}
|
||||
// Only the hand-written launchers can resume a NAMED session; a catalog
|
||||
// tool would silently start fresh under a "resume".
|
||||
if (resumeSessionId && !entry.launcher) {
|
||||
// Only the hand-written launchers and a catalog tool that declares
|
||||
// `resumeById` can resume a NAMED session; any other would silently start
|
||||
// fresh under a "resume".
|
||||
if (resumeSessionId && !entry.launcher && !entry.resumeById) {
|
||||
throw makeErr("EUNSUPPORTED", `${tool} cannot resume a session by id`);
|
||||
}
|
||||
// A catalog tool takes the id as an argv element of its own: never one that
|
||||
// could read as a flag.
|
||||
if (resumeSessionId && !entry.launcher && !/^[A-Za-z0-9]/.test(resumeSessionId)) {
|
||||
throw makeErr("EBADSESSION", "resumeSessionId is not a valid session id");
|
||||
}
|
||||
if (worktree === true && entry.launcher !== "claude") {
|
||||
throw makeErr("EUNSUPPORTED", `${tool} cannot start a session in its own worktree`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user