diff --git a/modules/home/pi.nix b/modules/home/pi.nix index fffae33..dc4ab6d 100644 --- a/modules/home/pi.nix +++ b/modules/home/pi.nix @@ -3,6 +3,7 @@ let cfg = config.dot.pi; piPath = "${config.dot.dotfilesPath}/modules/pi/agent"; + piWorkMode = config.dot.llm.pi.workMode or false; in { options.dot.pi = { @@ -12,14 +13,15 @@ in }; config = lib.mkIf cfg.enable { - # Out-of-store symlinks so the files stay editable without a nix rebuild. - # Only the managed files are linked; pi's runtime files (auth.json, - # sessions/, models-store.json) are left untouched in ~/.pi/agent. home.file = { ".pi/agent/settings.json".source = - config.lib.file.mkOutOfStoreSymlink "${piPath}/settings.json"; + config.lib.file.mkOutOfStoreSymlink + "${piPath}/${if piWorkMode then "settings.work" else "settings.home"}.json"; ".pi/agent/extensions".source = - config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions"; + config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions-common"; + } // lib.optionalAttrs piWorkMode { + ".pi/agent/extensions-work".source = + config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions-work"; }; }; } diff --git a/modules/pi/agent/extensions/plan-mode/README.md b/modules/pi/agent/extensions-common/plan-mode/README.md similarity index 100% rename from modules/pi/agent/extensions/plan-mode/README.md rename to modules/pi/agent/extensions-common/plan-mode/README.md diff --git a/modules/pi/agent/extensions/plan-mode/index.ts b/modules/pi/agent/extensions-common/plan-mode/index.ts similarity index 94% rename from modules/pi/agent/extensions/plan-mode/index.ts rename to modules/pi/agent/extensions-common/plan-mode/index.ts index e9ee73f..ca721d7 100644 --- a/modules/pi/agent/extensions/plan-mode/index.ts +++ b/modules/pi/agent/extensions-common/plan-mode/index.ts @@ -316,10 +316,9 @@ Do just this one step. Do NOT start any other step. Stop when this step is done. phase = undefined; return; } - const where = planFilePath ? `\nSaved to: ${planFilePath}` : ""; const choice = await ctx.ui.select( - `Plan "${plan.title}" — ${plan.steps.length} steps.${where}\nWhat next?`, - ["Execute step-by-step", "Stay in plan mode", "Refine the plan"], + `Plan "${plan.title}" — ${plan.steps.length} steps.\nWhat next?`, + ["Execute step-by-step", "Stay in plan mode", "Refine the plan", "Save plan to file"], ); if (choice?.startsWith("Execute")) { @@ -339,6 +338,14 @@ Do just this one step. Do NOT start any other step. Stop when this step is done. if (refinement?.trim()) { pi.sendUserMessage(refinement.trim(), { deliverAs: "followUp" }); } + } else if (choice === "Save plan to file") { + try { + planFilePath = await savePlanFile(ctx, plan); + ctx.ui.notify(`Plan saved to ${planFilePath}`, "info"); + persistState(); + } catch { + ctx.ui.notify("Failed to save plan.", "error"); + } } else { phase = "planning"; updateStatus(ctx); @@ -382,6 +389,23 @@ Do just this one step. Do NOT start any other step. Stop when this step is done. }, }); + pi.registerCommand("plan-save", { + description: "Save the current plan to a file in .pi/plans/", + handler: async (_args, ctx) => { + if (!plan) { + ctx.ui.notify("No plan to save. Submit a plan first.", "info"); + return; + } + try { + planFilePath = await savePlanFile(ctx, plan); + ctx.ui.notify(`Plan saved to ${planFilePath}`, "info"); + persistState(); + } catch { + ctx.ui.notify("Failed to save plan.", "error"); + } + }, + }); + pi.registerShortcut(Key.ctrlAlt("p"), { description: "Toggle plan mode", handler: async (ctx) => togglePlanMode(ctx), @@ -424,23 +448,17 @@ Do just this one step. Do NOT start any other step. Stop when this step is done. awaitingStep = false; phase = "awaiting-approval"; - try { - planFilePath = await savePlanFile(ctx, plan); - } catch { - planFilePath = undefined; - } persistState(); updateStatus(ctx); - const loc = planFilePath ? ` and saved to ${planFilePath}` : ""; return { content: [ { type: "text", - text: `Plan "${plan.title}" with ${plan.steps.length} step(s) submitted${loc}. Stop here and wait for the user to approve, refine, or execute.`, + text: `Plan "${plan.title}" with ${plan.steps.length} step(s) submitted. Stop here and wait for the user to approve, refine, or execute. Use /plan-save to save the plan to a file.`, }, ], - details: { title: plan.title, steps: plan.steps.length, path: planFilePath ?? null }, + details: { title: plan.title, steps: plan.steps.length }, terminate: true, }; }, diff --git a/modules/pi/agent/extensions/plan-mode/utils.ts b/modules/pi/agent/extensions-common/plan-mode/utils.ts similarity index 100% rename from modules/pi/agent/extensions/plan-mode/utils.ts rename to modules/pi/agent/extensions-common/plan-mode/utils.ts diff --git a/modules/pi/agent/extensions/langdock.ts b/modules/pi/agent/extensions-work/langdock.ts similarity index 99% rename from modules/pi/agent/extensions/langdock.ts rename to modules/pi/agent/extensions-work/langdock.ts index ca83594..479f334 100644 --- a/modules/pi/agent/extensions/langdock.ts +++ b/modules/pi/agent/extensions-work/langdock.ts @@ -141,13 +141,10 @@ export default function (pi: ExtensionAPI) { // ── Hide unwanted built-in providers ──────────────────────────────────── const keep = new Set([ - "anthropic", - "openai", - // "openrouter", + "openrouter", ]); const hide = [ - "openrouter", "ant-ling", "azure-openai", "azure-openai-responses", diff --git a/modules/pi/agent/settings.home.json b/modules/pi/agent/settings.home.json new file mode 100644 index 0000000..3c0e6a1 --- /dev/null +++ b/modules/pi/agent/settings.home.json @@ -0,0 +1,11 @@ +{ + "lastChangelogVersion": "0.81.1", + "theme": "light", + "defaultProvider": "openrouter", + "defaultModel": "deepseek/deepseek-v4-pro", + "defaultThinkingLevel": "high", + "hideThinkingBlock": false, + "enableInstallTelemetry": false, + "doubleEscapeAction": "tree", + "treeFilterMode": "all" +} diff --git a/modules/pi/agent/settings.json b/modules/pi/agent/settings.json index edd763d..183368c 100644 --- a/modules/pi/agent/settings.json +++ b/modules/pi/agent/settings.json @@ -1,8 +1,8 @@ { "lastChangelogVersion": "0.81.1", "theme": "light", - "defaultProvider": "anthropic", - "defaultModel": "claude-opus-4-8-default", + "defaultProvider": "openrouter", + "defaultModel": "deepseek/deepseek-v4-flash", "defaultThinkingLevel": "high", "hideThinkingBlock": false, "retry": { diff --git a/modules/pi/agent/settings.work.json b/modules/pi/agent/settings.work.json new file mode 100644 index 0000000..17cae73 --- /dev/null +++ b/modules/pi/agent/settings.work.json @@ -0,0 +1,19 @@ +{ + "lastChangelogVersion": "0.81.1", + "theme": "light", + "defaultProvider": "anthropic", + "defaultModel": "claude-opus-4-8-default", + "defaultThinkingLevel": "high", + "hideThinkingBlock": false, + "retry": { + "enabled": true, + "maxRetries": 4, + "baseDelayMs": 10000 + }, + "enableInstallTelemetry": false, + "doubleEscapeAction": "tree", + "treeFilterMode": "all", + "extensions": [ + "~/.pi/agent/extensions-work" + ] +} \ No newline at end of file