feat: per-change-block hunk actions (#50), codex lanes without a pipeline, macOS LaunchAgent
- git (#50): stage-hunk/discard-hunk take an optional `block` — one run of consecutive +/- lines inside an @@ hunk. `onlyBlock` (server/lib/git-diff.js) cuts git's fresh hunk down to it, folding the other blocks into the side being checked; LaneDiffView hangs one review bar per block (unified + split) and its arrows walk blocks. - git exclude: entries AgentHub writes for a lane go to the COMMON git dir with the lane's path prefix (server/lib/git-exclude.js, used by router-apply and lane-mcp) — a linked worktree's own info/exclude is never read by git, and a subdir lane has no .git. MCP sync no longer fails with ENOTDIR on a worktree lane or creates a stray .git in a non-repo lane. - codex lanes carry no pipeline: codex-ingest mirrors only idle/running, codex-nudge is removed, agents install writes nothing for codex, the Workspace hides stage/pipeline/feature pickers/PipelineMap for them, and every server start clears leftover codex stage data and the old AGENTS.md stage block. - Changes panel: a whole file opens for reading and enters the editor on a click on its text (caret at the clicked line), not automatically. - macOS: LaunchAgent start-at-login (scripts/launchd-service.js, picked by scripts/service-manager.js). - Adds the AgentHub introduction slides and their image-embedding script.
This commit is contained in:
+5
-19
@@ -9,8 +9,8 @@
|
||||
* logins — a QA account only needs to log in once per machine).
|
||||
*
|
||||
* Deliberately does NOT write any permission or settings.local.json content
|
||||
* — see the F1 design spec's Scope section for why. Plain file I/O; no git
|
||||
* calls, unlike lane-sync.js (E2) or lane-agents.js (E3).
|
||||
* — see the F1 design spec's Scope section for why. Plain file I/O apart
|
||||
* from the one `git rev-parse` behind `excludeFromGit`.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,8 @@ const fs = require("node:fs");
|
||||
const os = require("node:os");
|
||||
const path = require("node:path");
|
||||
|
||||
const { excludeFromGit } = require("./git-exclude");
|
||||
|
||||
/** Read the source repo's mcpServers from ~/.claude.json. Throws
|
||||
* ENOMCPCONFIG if the file is missing or the project has none declared —
|
||||
* a lane with zero MCP servers synced would silently break Stage 3/6 much
|
||||
@@ -99,22 +101,6 @@ function seedProfiles(sourceRepo, laneDir) {
|
||||
return seeded;
|
||||
}
|
||||
|
||||
/** Idempotently append a line to <laneDir>/.git/info/exclude — same
|
||||
* read-existing-then-append-if-missing pattern E2/E3 already use for
|
||||
* .git/info/attributes and .git/info/exclude. .mcp.json sits at the lane
|
||||
* root (not inside .git), so this needs no --git-common-dir resolution —
|
||||
* the exclude file itself is always local to this lane's own working copy. */
|
||||
function excludeFromGit(laneDir, line) {
|
||||
const excludePath = path.join(laneDir, ".git", "info", "exclude");
|
||||
fs.mkdirSync(path.dirname(excludePath), { recursive: true });
|
||||
const existing = fs.existsSync(excludePath) ? fs.readFileSync(excludePath, "utf8") : "";
|
||||
const lines = existing.split("\n").filter(Boolean);
|
||||
if (!lines.includes(line)) {
|
||||
lines.push(line);
|
||||
fs.writeFileSync(excludePath, lines.join("\n") + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{cwd: string, source_repo: string}} lane
|
||||
* @returns {{servers: string[], profilesSeeded: string[]}}
|
||||
@@ -129,7 +115,7 @@ async function syncMcp(lane) {
|
||||
path.join(lane.cwd, ".mcp.json"),
|
||||
JSON.stringify({ mcpServers: relocated }, null, 2) + "\n"
|
||||
);
|
||||
excludeFromGit(lane.cwd, ".mcp.json");
|
||||
excludeFromGit(lane.cwd, [".mcp.json"]);
|
||||
|
||||
const profilesSeeded = seedProfiles(sourceRepo, lane.cwd);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user