dashboard: tasks move to <project>/todo.txt at root, auto-gitignore in git repos
This commit is contained in:
@@ -51,15 +51,46 @@ const AUTO_ZELLIJ_NAME = /^[a-z]+-[a-z]+$/;
|
|||||||
// pi-subagents names subagent sessions "<Base>#<8-hex>" (e.g. "Explore#fb073d02")
|
// pi-subagents names subagent sessions "<Base>#<8-hex>" (e.g. "Explore#fb073d02")
|
||||||
const SUBAGENT_NAME = /^.+?#[0-9a-f]{8}$/i;
|
const SUBAGENT_NAME = /^.+?#[0-9a-f]{8}$/i;
|
||||||
|
|
||||||
// Project-local task file: lives in the pi project's .pi/ directory
|
// Project task file: lives at the root of the pi project's working directory
|
||||||
// Mirrors how pi sessions are organized by working directory
|
// so it is visible and discoverable. In git repos it is automatically added to
|
||||||
function projectTasksDir(): string {
|
// .gitignore so task churn never pollutes commits or Hunk reviews.
|
||||||
const dir = join(process.cwd(), ".pi", "dashboard", "tasks");
|
function gitRoot(dir: string): string | null {
|
||||||
ensureDir(dir);
|
let cur = dir;
|
||||||
return dir;
|
for (;;) {
|
||||||
|
if (existsSync(join(cur, ".git"))) return cur;
|
||||||
|
const parent = join(cur, "..");
|
||||||
|
if (parent === cur) return null;
|
||||||
|
cur = parent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureTodoGitignored() {
|
||||||
|
const root = gitRoot(cwd());
|
||||||
|
if (!root) return; // not a git repo — nothing to ignore
|
||||||
|
const gi = join(root, ".gitignore");
|
||||||
|
let content = "";
|
||||||
|
if (existsSync(gi)) {
|
||||||
|
try {
|
||||||
|
content = readFileSync(gi, "utf-8");
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const lines = content.split("\n");
|
||||||
|
if (lines.some((l) => l.trim() === "todo.txt" || l.trim() === "/todo.txt")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const line = content === "" || content.endsWith("\n") ? "todo.txt\n" : "\ntodo.txt\n";
|
||||||
|
try {
|
||||||
|
writeFileSync(gi, content + line, "utf-8");
|
||||||
|
} catch {
|
||||||
|
// read-only repo — ignore; tasks still work, they just may show in git
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function projectTodotxt(): string {
|
function projectTodotxt(): string {
|
||||||
return join(projectTasksDir(), "todo.txt");
|
ensureTodoGitignored();
|
||||||
|
return join(cwd(), "todo.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Types ─────────────────────────────────────────────────────────
|
// ── Types ─────────────────────────────────────────────────────────
|
||||||
@@ -168,7 +199,6 @@ function appendToTodo(
|
|||||||
priority?: string,
|
priority?: string,
|
||||||
agent?: string
|
agent?: string
|
||||||
) {
|
) {
|
||||||
ensureDir(projectTasksDir());
|
|
||||||
const pri = priority ? `(${priority.toUpperCase()}) ` : "";
|
const pri = priority ? `(${priority.toUpperCase()}) ` : "";
|
||||||
const proj = project ? ` +project:${project}` : "";
|
const proj = project ? ` +project:${project}` : "";
|
||||||
const agentTag = agent ? ` +agent:${agent}` : "";
|
const agentTag = agent ? ` +agent:${agent}` : "";
|
||||||
@@ -208,7 +238,6 @@ function readTodoList() {
|
|||||||
|
|
||||||
export default function (pi: ExtensionAPI) {
|
export default function (pi: ExtensionAPI) {
|
||||||
ensureDir(DASHBOARD_DIR);
|
ensureDir(DASHBOARD_DIR);
|
||||||
ensureDir(projectTasksDir());
|
|
||||||
|
|
||||||
const machine = hostname();
|
const machine = hostname();
|
||||||
const inTmux = !!process.env.TMUX;
|
const inTmux = !!process.env.TMUX;
|
||||||
|
|||||||
Reference in New Issue
Block a user