feat: AI commit messages, change tree, router behavesAs, sidebar times (v2.2.0)

- Changes panel: Files and Changes merged into one panel; the overview's
  groups drawn as a folder tree (compacted chains, file counts, fold,
  stage/unstage a whole folder)
- AI-suggested commit message for what is staged
  (POST /api/lanes/:id/git/commit-message, claude -p --safe-mode, haiku)
- AI Router: optional "Behaves as" Claude model id, written as
  modelPicker options into the router's --settings file (issue #56)
- Sidebar: session rows show last activity, live rows their start time;
  a closed Terminal row can be removed (DELETE /api/run/history/:id)
- Every pane's CLI starts only once a client is attached; claude panes
  no longer forced inline; tmux scrollbar one column wide
- Update notifier: "Check for updates" reopens a closed notice
This commit is contained in:
2026-10-06 12:36:06 +07:00
parent 6c605849d8
commit f0500dc592
41 changed files with 1201 additions and 249 deletions
+31
View File
@@ -674,6 +674,37 @@ const paths = {
},
},
},
"/api/lanes/{id}/git/commit-message": {
post: {
tags: ["Lanes"],
summary: "Suggest a commit message for the staged changes",
description:
"Runs the user's `claude` CLI (`-p --safe-mode --no-session-persistence --tools \"\" --model haiku`) on the STAGED diff of the lane's cwd (or `?session=` worktree), sent on stdin with the last ten commit subjects; a `settings.local.json` is never included. Reads only — nothing is staged or committed, no tool runs and no session is saved. Same-origin, since each call spends the user's Claude quota. 400 ENOSTAGED when nothing is staged, 400 ENOTOOL when `claude` is not on PATH, 502 EAI when the CLI fails, answers empty or runs past 120 s.",
operationId: "suggestLaneCommitMessage",
parameters: [
{ name: "id", in: "path", required: true, schema: { type: "integer" } },
{ name: "session", in: "query", required: false, schema: { type: "string" } },
],
responses: {
200: {
description: "The suggested message",
content: {
"application/json": {
schema: {
type: "object",
properties: { message: { type: "string" } },
required: ["message"],
},
},
},
},
400: { description: "ENOSTAGED / ENOTOOL / ENOWORKTREE" },
403: { description: "Cross-origin request refused" },
404: { description: "No such workspace" },
502: { description: "EAI — the claude CLI failed" },
},
},
},
"/api/lanes/{id}/git/{action}": {
post: {
tags: ["Lanes"],
+39
View File
@@ -857,6 +857,45 @@ const paths = {
},
},
"/api/run/history/{id}": {
delete: {
tags: ["Run"],
summary: "Forget a closed Terminal tab",
description:
"Deletes one `dashboard_runs` row whose tool is `shell` — a closed Terminal tab, which has no session — so it leaves the sidebar's recently-closed list. Rows of any other tool are never deleted (404). The loopback same-origin guard applies.",
operationId: "runHistoryForget",
parameters: [
{
name: "id",
in: "path",
required: true,
schema: { type: "string" },
description: "The history row's id (RunHistoryItem.id).",
example: "agenthub-lane-5-2@2026-10-06T08:00:00.000Z",
},
],
responses: {
200: {
description: "Removed",
content: { "application/json": { example: { removed: "agenthub-lane-5-2" } } },
},
403: ebadOrigin403,
404: {
description: "No closed Terminal tab with that id (ENOTFOUND)",
content: {
"application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } },
},
},
409: {
description: "That terminal is still open (ERUNLIVE)",
content: {
"application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } },
},
},
},
},
},
"/api/run/cwds": {
get: {
tags: ["Run"],