feat(lanes): offer a create/update readme run when adding a lane

An optional checkbox in the Add-lane modal starts the new lane's terminal
run right after creation with `/sg-all:sg-md-writing` as its first message,
so the lane opens already writing or refreshing its CLAUDE.md/AGENTS.md set.
Claude lanes only — codex has no slash commands.
This commit is contained in:
2026-09-14 11:20:37 +07:00
parent b7e81af0b6
commit baa355bee4
5 changed files with 75 additions and 0 deletions
@@ -14,6 +14,8 @@
* the route answers before the actual `git worktree add` runs, so this
* component polls `GET /api/lanes/:id` until that finishes before running the
* auto-setup calls against a cwd that must actually exist on disk first.
* An optional "Create/update readme file" checkbox starts the lane's terminal
* run right after creation with `/sg-all:sg-md-writing` as its first message.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
@@ -94,6 +96,7 @@ export function AddLaneModal({
const [branches, setBranches] = useState<string[] | null>(null);
const [base, setBase] = useState("");
const [pipeline, setPipeline] = useState("default");
const [writeDocs, setWriteDocs] = useState(false);
const [pipelines, setPipelines] = useState<{ id: string; name: string; nodes: unknown[] }[]>([]);
const [branchesError, setBranchesError] = useState<string | null>(null);
const [tool, setTool] = useState<LaneTool>("claude");
@@ -114,6 +117,7 @@ export function AddLaneModal({
setBranches(null);
setBase("");
setPipeline("default");
setWriteDocs(false);
setTool("claude");
setBranchesError(null);
setError(null);
@@ -177,6 +181,14 @@ export function AddLaneModal({
return () => window.clearTimeout(timer);
}, [mode, sourceRepo, t]);
// The checkbox below runs the docs skill by opening the lane's own terminal
// run with the slash command as its first message — a skill only exists
// inside a CLI session, so there is nothing server-side to call instead.
// Claude-only: codex has no slash commands (same reason LaneConsolePane
// prefills prose for a codex lane).
const startDocsRun = (laneId: number, cwd: string) =>
api.run.start({ laneId, cwd, initialPrompt: "/sg-all:sg-md-writing" });
const submit = async () => {
const repo = sourceRepo.trim();
const name = title.trim();
@@ -192,6 +204,7 @@ export function AddLaneModal({
pipeline,
tool,
});
if (writeDocs && tool === "claude") await startDocsRun(result.lane.id, result.lane.cwd);
onAdded(result.lane);
reset();
onClose();
@@ -242,6 +255,10 @@ export function AddLaneModal({
mcp: mcpOutcome.status === "fulfilled" ? "ok" : "failed",
});
if (writeDocs && tool === "claude") {
await startDocsRun(result.lane.id, provisionedLane.cwd);
}
if (import.meta.env.DEV) {
console.info("[add-lane] auto-setup result:", {
profile:
@@ -390,6 +407,21 @@ export function AddLaneModal({
<p className="mt-1 text-[10px] text-fg-muted">{t("addLanePipelineHint")}</p>
</div>
{tool === "claude" && (
<div>
<label className="flex items-center gap-2 text-xs text-fg-secondary">
<input
type="checkbox"
checked={writeDocs}
onChange={(e) => setWriteDocs(e.target.checked)}
className="h-3.5 w-3.5 accent-accent"
/>
{t("addLaneWriteDocsLabel")}
</label>
<p className="mt-1 text-[10px] text-fg-muted">{t("addLaneWriteDocsHint")}</p>
</div>
)}
{mode === "worktree" && branches && (
<div>
<label className="mb-1 block text-xs text-fg-secondary" htmlFor="add-lane-base">