@pify/plan-mode 0.1.0 → 0.2.0

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.
@@ -26,7 +26,7 @@ import type {
26
26
  import { Type } from "typebox";
27
27
 
28
28
  import { classifyToolCall } from "../src/policy.ts";
29
- import { createPlanFile } from "../src/plans.ts";
29
+ import { createPlanFile, listPlanFiles } from "../src/plans.ts";
30
30
  import {
31
31
  ENTER_REMINDER,
32
32
  EXIT_REMINDER,
@@ -347,9 +347,20 @@ export default function planMode(pi: ExtensionAPI) {
347
347
  // ── Command & shortcut ───────────────────────────────────────────────
348
348
 
349
349
  pi.registerCommand("plan", {
350
- description: "Toggle read-only plan mode: /plan [off | <first planning prompt>]",
350
+ description: "Toggle read-only plan mode: /plan [off | list | <first planning prompt>]",
351
351
  handler: async (args, ctx) => {
352
352
  const text = (args ?? "").trim();
353
+ if (text.toLowerCase() === "list") {
354
+ const plans = listPlanFiles(ctx.cwd);
355
+ notify(
356
+ ctx,
357
+ plans.length > 0
358
+ ? `${plans.map((p) => `${p.file} (${p.size} chars)`).join("\n")}\nLocation: .pi/plans/`
359
+ : "No saved plans yet (.pi/plans/ is empty).",
360
+ "info",
361
+ );
362
+ return;
363
+ }
353
364
  if (text.toLowerCase() === "off") {
354
365
  if (!state.active) {
355
366
  notify(ctx, "Plan mode is not active.", "info");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pify/plan-mode",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Read-only planning mode for pi with an explicit approve-then-execute gate: enforced tool policy, plan files, approach options, fresh-session handoff",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -31,8 +31,12 @@
31
31
  "LICENSE"
32
32
  ],
33
33
  "pi": {
34
- "extensions": ["./extensions/plan-mode.ts"],
35
- "skills": ["./skills"]
34
+ "extensions": [
35
+ "./extensions/plan-mode.ts"
36
+ ],
37
+ "skills": [
38
+ "./skills"
39
+ ]
36
40
  },
37
41
  "scripts": {
38
42
  "typecheck": "tsc --noEmit",
@@ -44,8 +48,12 @@
44
48
  "typebox": "*"
45
49
  },
46
50
  "peerDependenciesMeta": {
47
- "@earendil-works/pi-coding-agent": { "optional": true },
48
- "typebox": { "optional": true }
51
+ "@earendil-works/pi-coding-agent": {
52
+ "optional": true
53
+ },
54
+ "typebox": {
55
+ "optional": true
56
+ }
49
57
  },
50
58
  "devDependencies": {
51
59
  "@earendil-works/pi-coding-agent": "^0.84.4",
package/src/plans.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { mkdirSync, writeFileSync, existsSync } from "node:fs";
1
+ import { mkdirSync, writeFileSync, existsSync, readdirSync, statSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
 
4
4
  /** Plan files live in .pi/plans/, reviewable and committable. */
@@ -25,6 +25,22 @@ export function localDateStr(d: Date = new Date()): string {
25
25
  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
26
26
  }
27
27
 
28
+ /** List saved plan files, newest first (v0.2: saved-plan library, minimal form). */
29
+ export function listPlanFiles(cwd: string): Array<{ file: string; size: number }> {
30
+ const dir = plansDir(cwd);
31
+ try {
32
+ return readdirSync(dir)
33
+ .filter((f) => f.endsWith(".md"))
34
+ .map((f) => {
35
+ const full = join(dir, f);
36
+ return { file: f, size: statSync(full).size };
37
+ })
38
+ .sort((a, b) => b.file.localeCompare(a.file));
39
+ } catch {
40
+ return [];
41
+ }
42
+ }
43
+
28
44
  /** Create the plan file, uniquified when the slug collides on the same day. */
29
45
  export function createPlanFile(cwd: string, title: string, content: string): string {
30
46
  const dir = plansDir(cwd);