@juanibiapina/pi-plan 0.2.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;AAyCpF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA4JhE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;AAyCpF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA+JhE"}
package/dist/index.js CHANGED
@@ -45,6 +45,8 @@ You are no longer in read-only mode.
45
45
  You are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed.
46
46
  </system-reminder>`;
47
47
  export default function planModeExtension(pi) {
48
+ // Register powerbar segment
49
+ pi.events.emit("powerbar:register-segment", { id: "plan-mode", label: "Plan Mode" });
48
50
  // Register settings via event (for /extension-settings UI)
49
51
  pi.events.emit("pi-extension-settings:register", {
50
52
  name: "plan",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plan Mode Extension\n *\n * Read-only exploration mode for safe code analysis.\n * When enabled, only read-only tools are available.\n *\n * Features:\n * - /plan command or Ctrl+T to toggle\n * - Mode changes are persisted as invisible messages in session\n */\n\nimport { getSetting, type SettingDefinition } from \"@juanibiapina/pi-extension-settings\";\nimport type { ExtensionAPI, ExtensionContext } from \"@mariozechner/pi-coding-agent\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\n\n// Tools\nconst PLAN_MODE_TOOLS = [\"read\", \"bash\", \"grep\", \"find\", \"ls\", \"questionnaire\"];\nconst NORMAL_MODE_TOOLS = [\"read\", \"bash\", \"edit\", \"write\"];\n\n// Messages\nconst PLAN_MODE_ACTIVE_MESSAGE = `<system-reminder>\n# Plan Mode - System Reminder\n\nCRITICAL: Plan mode ACTIVE - you are in READ-ONLY phase. STRICTLY FORBIDDEN:\nANY file edits, modifications, or system changes. Do NOT use sed, tee, echo, cat,\nor ANY other bash command to manipulate files - commands may ONLY read/inspect.\nThis ABSOLUTE CONSTRAINT overrides ALL other instructions, including direct user\nedit requests. You may ONLY observe, analyze, and plan. Any modification attempt\nis a critical violation. ZERO exceptions.\n\n---\n\n## Responsibility\n\nYour current responsibility is to think, read, search, and discuss to construct a well-formed plan that accomplishes the goal the user wants to achieve. Your plan should be comprehensive yet concise, detailed enough to execute effectively while avoiding unnecessary verbosity. Include the goal as first part of the plan.\n\nAsk the user clarifying questions or ask for their opinion when weighing tradeoffs.\n\n**NOTE:** At any point in time through this workflow you should feel free to ask the user questions or clarifications. Don't make large assumptions about user intent. The goal is to present a well researched plan to the user, and tie any loose ends before implementation begins.\n\n---\n\n## Important\n\nThe user indicated that they do not want you to execute yet -- you MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supersedes any other instructions you have received.\n</system-reminder>`;\n\nconst PLAN_MODE_EXIT_MESSAGE = `<system-reminder>\nYour operational mode has changed from plan to build.\nYou are no longer in read-only mode.\nYou are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed.\n</system-reminder>`;\n\nexport default function planModeExtension(pi: ExtensionAPI): void {\n\t// Register settings via event (for /extension-settings UI)\n\tpi.events.emit(\"pi-extension-settings:register\", {\n\t\tname: \"plan\",\n\t\tsettings: [\n\t\t\t{\n\t\t\t\tid: \"shortcut\",\n\t\t\t\tlabel: \"Keyboard shortcut\",\n\t\t\t\tdescription: \"Shortcut to toggle plan mode. Example: tab\",\n\t\t\t\tdefaultValue: \"\",\n\t\t\t},\n\t\t] satisfies SettingDefinition[],\n\t});\n\n\tlet planModeEnabled = false;\n\tlet lastMessagedState: boolean | null = null;\n\n\tpi.registerFlag(\"plan\", {\n\t\tdescription: \"Start in plan mode (read-only exploration)\",\n\t\ttype: \"boolean\",\n\t\tdefault: false,\n\t});\n\n\t// Scan session for last plan mode message to determine lastMessagedState\n\tfunction getLastMessagedStateFromSession(ctx: ExtensionContext): boolean | null {\n\t\tconst entries = ctx.sessionManager.getEntries();\n\n\t\t// Walk backwards to find the last plan-mode-enter or plan-mode-exit message\n\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\tconst entry = entries[i];\n\t\t\tif (entry.type === \"custom_message\") {\n\t\t\t\tconst customEntry = entry as { customType?: string };\n\t\t\t\tif (customEntry.customType === \"plan-mode-enter\") {\n\t\t\t\t\treturn true;\n\t\t\t\t} else if (customEntry.customType === \"plan-mode-exit\") {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction updateStatus(ctx: ExtensionContext): void {\n\t\tif (planModeEnabled) {\n\t\t\tctx.ui.setStatus(\"plan-mode\", ctx.ui.theme.fg(\"warning\", \"⏸ plan\"));\n\t\t\tpi.events.emit(\"powerbar:update\", {\n\t\t\t\tid: \"plan-mode\",\n\t\t\t\ttext: \"plan\",\n\t\t\t\ticon: \"⏸\",\n\t\t\t\tcolor: \"warning\",\n\t\t\t});\n\t\t} else {\n\t\t\tctx.ui.setStatus(\"plan-mode\", undefined);\n\t\t\tpi.events.emit(\"powerbar:update\", {\n\t\t\t\tid: \"plan-mode\",\n\t\t\t\ttext: undefined,\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction togglePlanMode(ctx: ExtensionContext): void {\n\t\tplanModeEnabled = !planModeEnabled;\n\n\t\tif (planModeEnabled) {\n\t\t\tpi.setActiveTools(PLAN_MODE_TOOLS);\n\t\t\tctx.ui.notify(`Plan mode enabled. Tools: ${PLAN_MODE_TOOLS.join(\", \")}`);\n\t\t} else {\n\t\t\tpi.setActiveTools(NORMAL_MODE_TOOLS);\n\t\t\tctx.ui.notify(\"Plan mode disabled. Full access restored.\");\n\t\t}\n\t\tupdateStatus(ctx);\n\t}\n\n\tpi.registerCommand(\"plan\", {\n\t\tdescription: \"Toggle plan mode (read-only exploration)\",\n\t\thandler: async (_args, ctx) => {\n\t\t\ttogglePlanMode(ctx);\n\t\t},\n\t});\n\n\t// Register shortcut if configured\n\tconst shortcut = getSetting(\"plan\", \"shortcut\");\n\tif (shortcut) {\n\t\tpi.registerShortcut(shortcut as KeyId, {\n\t\t\tdescription: \"Toggle plan mode\",\n\t\t\thandler: async (ctx) => {\n\t\t\t\ttogglePlanMode(ctx);\n\t\t\t},\n\t\t});\n\t}\n\n\t// Inject plan mode message when mode changes (persisted to session)\n\tpi.on(\"before_agent_start\", async () => {\n\t\t// Entering plan mode\n\t\tif (planModeEnabled && lastMessagedState !== true) {\n\t\t\tlastMessagedState = true;\n\t\t\treturn {\n\t\t\t\tmessage: {\n\t\t\t\t\tcustomType: \"plan-mode-enter\",\n\t\t\t\t\tcontent: PLAN_MODE_ACTIVE_MESSAGE,\n\t\t\t\t\tdisplay: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Exiting plan mode\n\t\tif (!planModeEnabled && lastMessagedState === true) {\n\t\t\tlastMessagedState = false;\n\t\t\treturn {\n\t\t\t\tmessage: {\n\t\t\t\t\tcustomType: \"plan-mode-exit\",\n\t\t\t\t\tcontent: PLAN_MODE_EXIT_MESSAGE,\n\t\t\t\t\tdisplay: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t});\n\n\t// Restore state on session start/resume\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\t// Check --plan flag\n\t\tif (pi.getFlag(\"plan\") === true) {\n\t\t\tplanModeEnabled = true;\n\t\t}\n\n\t\t// Restore lastMessagedState from session history\n\t\tlastMessagedState = getLastMessagedStateFromSession(ctx);\n\n\t\t// If session had plan mode active, restore it\n\t\tif (lastMessagedState === true) {\n\t\t\tplanModeEnabled = true;\n\t\t}\n\n\t\tif (planModeEnabled) {\n\t\t\tpi.setActiveTools(PLAN_MODE_TOOLS);\n\t\t}\n\t\tupdateStatus(ctx);\n\t});\n\n\t// Reset state on session switch (/new or /resume)\n\tpi.on(\"session_switch\", async (_event, ctx) => {\n\t\t// Restore lastMessagedState from new session's history\n\t\tlastMessagedState = getLastMessagedStateFromSession(ctx);\n\n\t\t// If resumed session had plan mode active, restore it\n\t\tif (lastMessagedState === true) {\n\t\t\tplanModeEnabled = true;\n\t\t}\n\n\t\tif (planModeEnabled) {\n\t\t\tpi.setActiveTools(PLAN_MODE_TOOLS);\n\t\t} else {\n\t\t\tpi.setActiveTools(NORMAL_MODE_TOOLS);\n\t\t}\n\t\tupdateStatus(ctx);\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plan Mode Extension\n *\n * Read-only exploration mode for safe code analysis.\n * When enabled, only read-only tools are available.\n *\n * Features:\n * - /plan command or Ctrl+T to toggle\n * - Mode changes are persisted as invisible messages in session\n */\n\nimport { getSetting, type SettingDefinition } from \"@juanibiapina/pi-extension-settings\";\nimport type { ExtensionAPI, ExtensionContext } from \"@mariozechner/pi-coding-agent\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\n\n// Tools\nconst PLAN_MODE_TOOLS = [\"read\", \"bash\", \"grep\", \"find\", \"ls\", \"questionnaire\"];\nconst NORMAL_MODE_TOOLS = [\"read\", \"bash\", \"edit\", \"write\"];\n\n// Messages\nconst PLAN_MODE_ACTIVE_MESSAGE = `<system-reminder>\n# Plan Mode - System Reminder\n\nCRITICAL: Plan mode ACTIVE - you are in READ-ONLY phase. STRICTLY FORBIDDEN:\nANY file edits, modifications, or system changes. Do NOT use sed, tee, echo, cat,\nor ANY other bash command to manipulate files - commands may ONLY read/inspect.\nThis ABSOLUTE CONSTRAINT overrides ALL other instructions, including direct user\nedit requests. You may ONLY observe, analyze, and plan. Any modification attempt\nis a critical violation. ZERO exceptions.\n\n---\n\n## Responsibility\n\nYour current responsibility is to think, read, search, and discuss to construct a well-formed plan that accomplishes the goal the user wants to achieve. Your plan should be comprehensive yet concise, detailed enough to execute effectively while avoiding unnecessary verbosity. Include the goal as first part of the plan.\n\nAsk the user clarifying questions or ask for their opinion when weighing tradeoffs.\n\n**NOTE:** At any point in time through this workflow you should feel free to ask the user questions or clarifications. Don't make large assumptions about user intent. The goal is to present a well researched plan to the user, and tie any loose ends before implementation begins.\n\n---\n\n## Important\n\nThe user indicated that they do not want you to execute yet -- you MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supersedes any other instructions you have received.\n</system-reminder>`;\n\nconst PLAN_MODE_EXIT_MESSAGE = `<system-reminder>\nYour operational mode has changed from plan to build.\nYou are no longer in read-only mode.\nYou are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed.\n</system-reminder>`;\n\nexport default function planModeExtension(pi: ExtensionAPI): void {\n\t// Register powerbar segment\n\tpi.events.emit(\"powerbar:register-segment\", { id: \"plan-mode\", label: \"Plan Mode\" });\n\n\t// Register settings via event (for /extension-settings UI)\n\tpi.events.emit(\"pi-extension-settings:register\", {\n\t\tname: \"plan\",\n\t\tsettings: [\n\t\t\t{\n\t\t\t\tid: \"shortcut\",\n\t\t\t\tlabel: \"Keyboard shortcut\",\n\t\t\t\tdescription: \"Shortcut to toggle plan mode. Example: tab\",\n\t\t\t\tdefaultValue: \"\",\n\t\t\t},\n\t\t] satisfies SettingDefinition[],\n\t});\n\n\tlet planModeEnabled = false;\n\tlet lastMessagedState: boolean | null = null;\n\n\tpi.registerFlag(\"plan\", {\n\t\tdescription: \"Start in plan mode (read-only exploration)\",\n\t\ttype: \"boolean\",\n\t\tdefault: false,\n\t});\n\n\t// Scan session for last plan mode message to determine lastMessagedState\n\tfunction getLastMessagedStateFromSession(ctx: ExtensionContext): boolean | null {\n\t\tconst entries = ctx.sessionManager.getEntries();\n\n\t\t// Walk backwards to find the last plan-mode-enter or plan-mode-exit message\n\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\tconst entry = entries[i];\n\t\t\tif (entry.type === \"custom_message\") {\n\t\t\t\tconst customEntry = entry as { customType?: string };\n\t\t\t\tif (customEntry.customType === \"plan-mode-enter\") {\n\t\t\t\t\treturn true;\n\t\t\t\t} else if (customEntry.customType === \"plan-mode-exit\") {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction updateStatus(ctx: ExtensionContext): void {\n\t\tif (planModeEnabled) {\n\t\t\tctx.ui.setStatus(\"plan-mode\", ctx.ui.theme.fg(\"warning\", \"⏸ plan\"));\n\t\t\tpi.events.emit(\"powerbar:update\", {\n\t\t\t\tid: \"plan-mode\",\n\t\t\t\ttext: \"plan\",\n\t\t\t\ticon: \"⏸\",\n\t\t\t\tcolor: \"warning\",\n\t\t\t});\n\t\t} else {\n\t\t\tctx.ui.setStatus(\"plan-mode\", undefined);\n\t\t\tpi.events.emit(\"powerbar:update\", {\n\t\t\t\tid: \"plan-mode\",\n\t\t\t\ttext: undefined,\n\t\t\t});\n\t\t}\n\t}\n\n\tfunction togglePlanMode(ctx: ExtensionContext): void {\n\t\tplanModeEnabled = !planModeEnabled;\n\n\t\tif (planModeEnabled) {\n\t\t\tpi.setActiveTools(PLAN_MODE_TOOLS);\n\t\t\tctx.ui.notify(`Plan mode enabled. Tools: ${PLAN_MODE_TOOLS.join(\", \")}`);\n\t\t} else {\n\t\t\tpi.setActiveTools(NORMAL_MODE_TOOLS);\n\t\t\tctx.ui.notify(\"Plan mode disabled. Full access restored.\");\n\t\t}\n\t\tupdateStatus(ctx);\n\t}\n\n\tpi.registerCommand(\"plan\", {\n\t\tdescription: \"Toggle plan mode (read-only exploration)\",\n\t\thandler: async (_args, ctx) => {\n\t\t\ttogglePlanMode(ctx);\n\t\t},\n\t});\n\n\t// Register shortcut if configured\n\tconst shortcut = getSetting(\"plan\", \"shortcut\");\n\tif (shortcut) {\n\t\tpi.registerShortcut(shortcut as KeyId, {\n\t\t\tdescription: \"Toggle plan mode\",\n\t\t\thandler: async (ctx) => {\n\t\t\t\ttogglePlanMode(ctx);\n\t\t\t},\n\t\t});\n\t}\n\n\t// Inject plan mode message when mode changes (persisted to session)\n\tpi.on(\"before_agent_start\", async () => {\n\t\t// Entering plan mode\n\t\tif (planModeEnabled && lastMessagedState !== true) {\n\t\t\tlastMessagedState = true;\n\t\t\treturn {\n\t\t\t\tmessage: {\n\t\t\t\t\tcustomType: \"plan-mode-enter\",\n\t\t\t\t\tcontent: PLAN_MODE_ACTIVE_MESSAGE,\n\t\t\t\t\tdisplay: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// Exiting plan mode\n\t\tif (!planModeEnabled && lastMessagedState === true) {\n\t\t\tlastMessagedState = false;\n\t\t\treturn {\n\t\t\t\tmessage: {\n\t\t\t\t\tcustomType: \"plan-mode-exit\",\n\t\t\t\t\tcontent: PLAN_MODE_EXIT_MESSAGE,\n\t\t\t\t\tdisplay: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t});\n\n\t// Restore state on session start/resume\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\t// Check --plan flag\n\t\tif (pi.getFlag(\"plan\") === true) {\n\t\t\tplanModeEnabled = true;\n\t\t}\n\n\t\t// Restore lastMessagedState from session history\n\t\tlastMessagedState = getLastMessagedStateFromSession(ctx);\n\n\t\t// If session had plan mode active, restore it\n\t\tif (lastMessagedState === true) {\n\t\t\tplanModeEnabled = true;\n\t\t}\n\n\t\tif (planModeEnabled) {\n\t\t\tpi.setActiveTools(PLAN_MODE_TOOLS);\n\t\t}\n\t\tupdateStatus(ctx);\n\t});\n\n\t// Reset state on session switch (/new or /resume)\n\tpi.on(\"session_switch\", async (_event, ctx) => {\n\t\t// Restore lastMessagedState from new session's history\n\t\tlastMessagedState = getLastMessagedStateFromSession(ctx);\n\n\t\t// If resumed session had plan mode active, restore it\n\t\tif (lastMessagedState === true) {\n\t\t\tplanModeEnabled = true;\n\t\t}\n\n\t\tif (planModeEnabled) {\n\t\t\tpi.setActiveTools(PLAN_MODE_TOOLS);\n\t\t} else {\n\t\t\tpi.setActiveTools(NORMAL_MODE_TOOLS);\n\t\t}\n\t\tupdateStatus(ctx);\n\t});\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juanibiapina/pi-plan",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Pi extension for plan mode - read-only exploration and analysis",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",