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:
+33
-4
@@ -17,6 +17,7 @@ const { db } = require("../db");
|
||||
const lanesLib = require("../lib/lanes");
|
||||
const { sessionWorktree, removeSessionWorktree } = require("../lib/session-worktree");
|
||||
const { sourceFolder } = require("../lib/lane-sources");
|
||||
const { nestedRepos, repoFolder } = require("../lib/nested-repos");
|
||||
const { suggestCommitMessage } = require("../lib/commit-message");
|
||||
const aiTools = require("../lib/ai-tools");
|
||||
const {
|
||||
@@ -1315,6 +1316,23 @@ router.get("/:id/integrations/:name", (req, res) => {
|
||||
* POST and Express matches on method as well as path. Verified by moving this
|
||||
* registration after it: the suite stayed green.
|
||||
*/
|
||||
/**
|
||||
* The git repositories inside the workspace folder (`server/lib/nested-repos.js`):
|
||||
* a parent folder of several repos gets one Changes-panel section per repo,
|
||||
* each read and written through `?repo=<path>`. `root` says whether the
|
||||
* workspace folder is itself in a repo. Disk reads only, cached 30 s;
|
||||
* `?refresh=1` reads again. A missing folder is an empty list, not a fault.
|
||||
*/
|
||||
router.get("/:id/repos", async (req, res) => {
|
||||
const lane = laneOr404(req, res);
|
||||
if (!lane) return;
|
||||
try {
|
||||
res.json(await nestedRepos(lane.cwd, { refresh: req.query.refresh === "1" }));
|
||||
} catch {
|
||||
res.json({ root: false, items: [], truncated: false });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/:id/git", async (req, res) => {
|
||||
const t = await gitTargetOr404(req, res);
|
||||
if (!t) return;
|
||||
@@ -2426,14 +2444,25 @@ function gitErrorCode(err) {
|
||||
* `?session=<id>` — that session's worktree (`claude --worktree`), resolved by
|
||||
* `sessionWorktree` from the session ROW (owned by this workspace, registered
|
||||
* by `git worktree list`), or — with `?source=<id>` — one of the workspace's
|
||||
* extra folders, resolved by `sourceFolder` from its `lane_sources` ROW; never
|
||||
* from a path in the request. An unresolvable session (400) or source (404,
|
||||
* like another workspace's row) is never a silent fall back to the main
|
||||
* folder: a commit or a discard must never land in the wrong tree.
|
||||
* extra folders, resolved by `sourceFolder` from its `lane_sources` ROW, or —
|
||||
* with `?repo=<path>` — a repo inside the workspace folder, accepted only when
|
||||
* `repoFolder`'s own walk of that folder found it; never from a path in the
|
||||
* request. An unresolvable session (400), source or repo (404, like another
|
||||
* workspace's row) is never a silent fall back to the main folder: a commit
|
||||
* or a discard must never land in the wrong tree.
|
||||
*/
|
||||
async function gitTargetOr404(req, res) {
|
||||
const lane = laneOr404(req, res);
|
||||
if (!lane) return null;
|
||||
if (req.query.repo !== undefined) {
|
||||
try {
|
||||
const cwd = await repoFolder(lane.cwd, req.query.repo);
|
||||
return { lane, cwd, worktree: null, source: true };
|
||||
} catch (err) {
|
||||
res.status(404).json({ error: { code: err.code, message: err.message } });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (req.query.source !== undefined) {
|
||||
try {
|
||||
const cwd = sourceFolder(lane.id, req.query.source);
|
||||
|
||||
Reference in New Issue
Block a user