pi-task-tracker 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/index.ts +16 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -16,7 +16,7 @@ Task workflow tracking for the [pi coding agent](https://www.npmjs.com/package/@
16
16
  - **Nested-repo aware** — changes inside a sub-repository (a `.git` below your session root) are committed *there* — the innermost repo wins — and never pollute the outer repo. The outer task commit records anchors (`Nested: <repo>@<sha>`), so `/rollback` restores nested repos to their exact matching commit.
17
17
  - **Pre-existing double tracking respected** — if a file is already tracked by both an outer repo and a nested repo, changes go to the nested repo (innermost wins), pi never untracks the outer copy, and `/rollback` never lets the outer repo restore its stale copy over the inner worktree.
18
18
  - **Subdirectory start** — start pi in a subdirectory of an existing repo and no fresh `.git` is created there: all session changes (including TODO.md / README.md) are recorded in the enclosing repository, and `/rollback` restores the enclosing repo scoped to the session subtree.
19
- - **Scope guard** — the writable scope equals the trackable scope: out-of-session writes are blocked by default (`taskTracker.externalWrite`), so nothing can be changed that `/rollback` could not restore. Git rules are inherited from `pi-permission-system`.
19
+ - **Scope guard** — the writable scope equals the trackable scope: out-of-session writes follow `taskTracker.externalWrite` (default `"ask"`: confirm; `"warn"`: allow + yellow notice; `"block"`: hard deny), so nothing changes that `/rollback` could not restore. Git history protection is built in.
20
20
  - **Subagent-safe** — `.pi-subagents/` session artifacts are never recorded, listed, or committed.
21
21
 
22
22
  ## Lightweight by design (measured, not claimed)
@@ -76,7 +76,7 @@ Optional `taskTracker` key in `~/.pi/agent/settings.json` (all default to `true`
76
76
  - `readme` — maintain the `README.md` project-structure section
77
77
  - `autoCommit` — per-task commits; these are the `/rollback` checkpoints, so disabling this also disables rollback targets
78
78
  - `guard` — master switch for the built-in permission layer (default `true`). Set `false` to defer permission decisions entirely to another extension (e.g. `pi-permission-system`): no external-write checks, no git-ask prompts, no cd sandbox.
79
- - `externalWrite` — policy for tool calls that would create/modify files OUTSIDE the session directory: `"block"` (default, hard deny — external changes cannot be tracked or rolled back), `"ask"` (per-attempt confirmation), `"off"` (no enforcement; `pi-permission-system` rules still apply). Reads stay free. Copying files FROM outside INTO the session is allowed (`cp` checks only its destination); moving/deleting external paths is blocked. Everything INSIDE the session directory passes by default — the only sandbox-internal intervention is the `cd` disable. Git history protection is **inherited**: history-rewriting git (rebase/reset/amend/force-push/clean/...) prompts for confirmation right here, so `pi-permission-system` can be uninstalled without losing that layer; routine git passes untouched, an external `git init`/`clone` is allowed with a heads-up that the new repo is not tracked. Git-Bash/MSYS paths (`/c/Users/...`, `/cygdrive/c/...`) are normalized before evaluation, so drive-absolute forms do not false-positive as external; `/tmp` and other non-drive names stay external (they resolve outside the session on Windows). Shell commands are analyzed statically (redirects, `rm/mv/cp/touch/...`, `cd` tracking, PowerShell equivalents); git protection is inherited from `pi-permission-system` — routine git passes untouched and history-rewriting git still prompts there; only redirect targets and `-C` destinations on git segments are checked. **`cd` is free inside the session directory; a `cd` that would move the working directory outside it is blocked** (that is the one operation that changes pi's effective scope). No cd-tracking is performed — resolution baseline stays the session root, so a deep in-session `cd` followed by enough `../` levels to escape may over-block, which is the fail-safe direction.
79
+ - `externalWrite` — policy for tool calls that would create/modify files OUTSIDE the session directory: `"ask"` (default, per-attempt confirmation), `"warn"` (allow + yellow UI notice, no prompt), `"block"` (hard deny — external changes cannot be tracked or rolled back), `"off"` (no enforcement; defer permission decisions to another extension). Reads stay free. Copying files FROM outside INTO the session is allowed (`cp` checks only its destination); moving/deleting external paths is checked. Everything INSIDE the session directory passes by default. Git history protection is built in: history-rewriting git (rebase/reset/amend/force-push/clean/...) prompts for confirmation, routine git passes untouched, and an external `git init`/`clone` is allowed with a heads-up that the new repo is not tracked. Git-Bash/MSYS paths (`/c/Users/...`, `/cygdrive/c/...`) are normalized before evaluation, so drive-absolute forms do not false-positive as external; `/tmp` and other non-drive names stay external (they resolve outside the session on Windows). Shell commands are analyzed statically (redirects, `rm/mv/cp/touch/...`, PowerShell equivalents; redirect targets and `-C` destinations on git segments). **`cd` is free inside the session directory; a `cd` that would move the working directory outside it follows the same policy** (ask/warn/block). No cd-tracking is performed — resolution baseline stays the session root, so a deep in-session `cd` followed by enough `../` levels to escape may over-block, which is the fail-safe direction.
80
80
 
81
81
  ## Requirements
82
82
 
package/index.ts CHANGED
@@ -290,7 +290,7 @@ const GUARD_ASK_PROMPT = "pi-task-tracker external-write guard";
290
290
  async function guardExternalWriteHit(
291
291
  event: { toolName: string; input?: unknown },
292
292
  sessionCwd: string,
293
- mode: "block" | "ask",
293
+ mode: "block" | "ask" | "warn",
294
294
  ctx?: { hasUI?: boolean; ui?: { confirm: (t: string, m: string) => Promise<boolean>; notify: (m: string, kind?: string) => void } }
295
295
  ): Promise<string | null> {
296
296
  if (!sessionCwd) return null;
@@ -313,6 +313,12 @@ async function guardExternalWriteHit(
313
313
  }
314
314
  if (hit.block) {
315
315
  const why = "External changes cannot be tracked or rolled back by pi-task-tracker.";
316
+ if (mode === "warn") {
317
+ if (ctx?.hasUI && ctx.ui) {
318
+ ctx.ui.notify(`pi-task-tracker: command writes to '${hit.block}' outside the session directory. ${why}`, "warning");
319
+ }
320
+ return null;
321
+ }
316
322
  if (mode === "ask") {
317
323
  if (!ctx?.hasUI || !ctx.ui) return `pi-task-tracker scope guard: '${hit.block}' is outside the session directory and no UI is available. ${why}`;
318
324
  const ok = await ctx.ui.confirm(
@@ -335,6 +341,12 @@ async function guardExternalWriteHit(
335
341
  if (!isWriteish && (GUARD_READ_TOOLS.has(toolName) || coveredByGuardHeuristics(toolName))) return null;
336
342
  if (!isExternalAbs2(sessionCwd, p)) return null;
337
343
  const why = "External changes cannot be tracked or rolled back by pi-task-tracker.";
344
+ if (mode === "warn") {
345
+ if (ctx?.hasUI && ctx.ui) {
346
+ ctx.ui.notify(`pi-task-tracker: '${toolName}' targets '${p}' outside the session directory. ${why}`, "warning");
347
+ }
348
+ return null;
349
+ }
338
350
  if (mode === "ask") {
339
351
  if (!ctx?.hasUI || !ctx.ui) return `pi-task-tracker scope guard: '${p}' is outside the session directory and no UI is available to approve external writes. ${why}`;
340
352
  const ok = await ctx.ui.confirm(
@@ -599,8 +611,8 @@ interface TrackerConfig {
599
611
  /** master switch for the built-in permission layer (external-write guard,
600
612
  * git-ask inheritance, cd disable). false = defer entirely to other extensions */
601
613
  guard: boolean;
602
- /** Writes outside the session directory: "block" (default) | "ask" | "off" */
603
- externalWrite: "block" | "ask" | "off";
614
+ /** Writes outside the session directory: "ask" (default) | "warn" (allow + yellow notice) | "block" | "off" */
615
+ externalWrite: "block" | "ask" | "warn" | "off";
604
616
  }
605
617
 
606
618
  function readConfig(): TrackerConfig {
@@ -615,7 +627,7 @@ function readConfig(): TrackerConfig {
615
627
  readme: t.readme !== false,
616
628
  autoCommit: t.autoCommit !== false,
617
629
  guard: t.guard !== false,
618
- externalWrite: t.externalWrite === "block" || t.externalWrite === "off" ? t.externalWrite : "ask",
630
+ externalWrite: t.externalWrite === "block" || t.externalWrite === "off" || t.externalWrite === "warn" ? t.externalWrite : "ask",
619
631
  };
620
632
  } catch {
621
633
  return fallback;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-task-tracker",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Task workflow tracking for the pi coding agent: TODO/README maintenance, per-task git auto-commits as checkpoints, and an interactive /rollback. Hashline-aware, nested-repo aware, subagent-artifact-safe.",
5
5
  "keywords": [
6
6
  "pi-package",