Full Code of elianiva/dotfiles for AI

master 40499271695e cached
307 files
917.2 KB
255.4k tokens
261 symbols
1 requests
Download .txt
Showing preview only (1,002K chars total). Download the full file or copy to clipboard to get everything.
Repository: elianiva/dotfiles
Branch: master
Commit: 40499271695e
Files: 307
Total size: 917.2 KB

Directory structure:
gitextract_76rbdv8a/

├── .gitignore
├── .gitmodules
├── Makefile
├── README.md
├── agents/
│   ├── AGENTS.md
│   ├── opencode/
│   │   └── opencode.json
│   ├── pi/
│   │   ├── extensions/
│   │   │   ├── agent-profiles.ts
│   │   │   ├── ask.ts
│   │   │   ├── composed-editor/
│   │   │   │   ├── index.ts
│   │   │   │   └── package.json
│   │   │   ├── custom-formatting.ts
│   │   │   ├── exit-command.ts
│   │   │   ├── handoff.ts
│   │   │   ├── lsp/
│   │   │   │   ├── index.ts
│   │   │   │   └── lsp-config.ts
│   │   │   ├── notify.ts
│   │   │   ├── pi-codemode/
│   │   │   │   ├── README.md
│   │   │   │   ├── executor.jsonc
│   │   │   │   ├── index.ts
│   │   │   │   ├── package.json
│   │   │   │   ├── src/
│   │   │   │   │   ├── builtins.ts
│   │   │   │   │   ├── codemode.ts
│   │   │   │   │   ├── executor-cache.ts
│   │   │   │   │   ├── fff-plugin.ts
│   │   │   │   │   ├── fff.ts
│   │   │   │   │   ├── jj-plugin.ts
│   │   │   │   │   ├── npm-plugin.ts
│   │   │   │   │   ├── pi-plugin.ts
│   │   │   │   │   ├── read.ts
│   │   │   │   │   ├── render.ts
│   │   │   │   │   ├── runtime.ts
│   │   │   │   │   ├── sandbox-cache.ts
│   │   │   │   │   ├── source-config.ts
│   │   │   │   │   ├── source-hydrate.ts
│   │   │   │   │   ├── trace.ts
│   │   │   │   │   ├── turndown.d.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   ├── util.ts
│   │   │   │   │   └── webfetch.ts
│   │   │   │   └── tsconfig.json
│   │   │   ├── prompt-timer.ts
│   │   │   ├── session-breakdown.ts
│   │   │   ├── webfetch.ts
│   │   │   └── whimsical-timer.ts
│   │   ├── mcp.json
│   │   ├── models.json
│   │   ├── package.json
│   │   ├── settings.json
│   │   ├── themes/
│   │   │   └── rose-pine-dawn.json
│   │   └── treesitter.ts
│   └── skills/
│       ├── build-feature/
│       │   └── SKILL.md
│       ├── code-review/
│       │   └── SKILL.md
│       ├── debugging/
│       │   └── SKILL.md
│       ├── deslop/
│       │   └── SKILL.md
│       ├── effect-best-practices/
│       │   ├── SKILL.md
│       │   └── references/
│       │       ├── anti-patterns.md
│       │       ├── effect-atom-patterns.md
│       │       ├── error-patterns.md
│       │       ├── layer-patterns.md
│       │       ├── observability-patterns.md
│       │       ├── rpc-cluster-patterns.md
│       │       ├── schema-patterns.md
│       │       └── service-patterns.md
│       ├── emil-design-eng/
│       │   └── SKILL.md
│       ├── frontend-design/
│       │   ├── LICENSE.txt
│       │   └── SKILL.md
│       ├── grill-me/
│       │   └── SKILL.md
│       ├── initz/
│       │   └── SKILL.md
│       ├── jj/
│       │   └── SKILL.md
│       ├── pi-improvements/
│       │   └── SKILL.md
│       ├── react-best-practices/
│       │   ├── AGENTS.md
│       │   ├── README.md
│       │   ├── SKILL.md
│       │   ├── metadata.json
│       │   └── rules/
│       │       ├── _sections.md
│       │       ├── _template.md
│       │       ├── advanced-event-handler-refs.md
│       │       ├── advanced-use-latest.md
│       │       ├── async-api-routes.md
│       │       ├── async-defer-await.md
│       │       ├── async-dependencies.md
│       │       ├── async-parallel.md
│       │       ├── async-suspense-boundaries.md
│       │       ├── bundle-barrel-imports.md
│       │       ├── bundle-conditional.md
│       │       ├── bundle-defer-third-party.md
│       │       ├── bundle-dynamic-imports.md
│       │       ├── bundle-preload.md
│       │       ├── client-event-listeners.md
│       │       ├── client-localstorage-schema.md
│       │       ├── client-passive-event-listeners.md
│       │       ├── client-swr-dedup.md
│       │       ├── js-batch-dom-css.md
│       │       ├── js-cache-function-results.md
│       │       ├── js-cache-property-access.md
│       │       ├── js-cache-storage.md
│       │       ├── js-combine-iterations.md
│       │       ├── js-early-exit.md
│       │       ├── js-hoist-regexp.md
│       │       ├── js-index-maps.md
│       │       ├── js-length-check-first.md
│       │       ├── js-min-max-loop.md
│       │       ├── js-set-map-lookups.md
│       │       ├── js-tosorted-immutable.md
│       │       ├── rendering-activity.md
│       │       ├── rendering-animate-svg-wrapper.md
│       │       ├── rendering-conditional-render.md
│       │       ├── rendering-content-visibility.md
│       │       ├── rendering-hoist-jsx.md
│       │       ├── rendering-hydration-no-flicker.md
│       │       ├── rendering-svg-precision.md
│       │       ├── rendering-usetransition-loading.md
│       │       ├── rerender-defer-reads.md
│       │       ├── rerender-dependencies.md
│       │       ├── rerender-derived-state.md
│       │       ├── rerender-functional-setstate.md
│       │       ├── rerender-lazy-state-init.md
│       │       ├── rerender-memo-with-default-value.md
│       │       ├── rerender-memo.md
│       │       ├── rerender-simple-expression-in-memo.md
│       │       ├── rerender-transitions.md
│       │       ├── server-after-nonblocking.md
│       │       ├── server-auth-actions.md
│       │       ├── server-cache-lru.md
│       │       ├── server-cache-react.md
│       │       ├── server-dedup-props.md
│       │       ├── server-parallel-fetching.md
│       │       └── server-serialization.md
│       ├── root-cause-tracing/
│       │   └── SKILL.md
│       ├── session-retrospective/
│       │   └── SKILL.md
│       ├── web-design-guidelines/
│       │   └── SKILL.md
│       └── wydt/
│           └── SKILL.md
├── direnv/
│   └── direnvrc
├── fish/
│   ├── conf.d/
│   │   ├── abbr.fish
│   │   ├── alias.fish
│   │   ├── colour.fish
│   │   ├── foreign.fish
│   │   ├── manpage.fish
│   │   └── vi-mode.fish
│   ├── config.fish
│   ├── fish_plugins
│   ├── fish_variables
│   └── functions/
│       ├── fenv.apply.fish
│       ├── fenv.fish
│       ├── fenv.main.fish
│       ├── fenv.parse.after.fish
│       ├── fenv.parse.before.fish
│       ├── fenv.parse.diff.fish
│       └── fenv.parse.divider.fish
├── flake.nix
├── ghostty/
│   └── config
├── gitconfig/
│   └── .gitconfig
├── helix/
│   ├── config.toml
│   ├── languages.toml
│   ├── runtime/
│   │   └── queries/
│   │       └── typst/
│   │           └── highlights.scm
│   └── themes/
│       └── my_rose_pine.toml
├── improvement.md
├── jjui/
│   ├── config.toml
│   └── themes/
│       └── rose-pine-dawn.toml
├── kitty/
│   ├── kitty.conf
│   ├── launch.conf
│   ├── rose-pine-dawn.conf
│   └── rose-pine.conf
├── legacy/
│   ├── awesome/
│   │   └── .config/
│   │       └── awesome/
│   │           ├── keybinds/
│   │           │   ├── bindtotags.lua
│   │           │   ├── clientbuttons.lua
│   │           │   ├── clientkeys.lua
│   │           │   ├── globalkeys.lua
│   │           │   └── mediakeys.lua
│   │           ├── main/
│   │           │   ├── autostart.lua
│   │           │   ├── error-handling.lua
│   │           │   ├── exitscreen.lua
│   │           │   ├── helpers.lua
│   │           │   ├── json.lua
│   │           │   ├── layouts.lua
│   │           │   ├── menu.lua
│   │           │   ├── rules.lua
│   │           │   ├── signals.lua
│   │           │   ├── tags.lua
│   │           │   ├── titlebar.lua
│   │           │   ├── variables.lua
│   │           │   └── volume-widget/
│   │           │       └── init.lua
│   │           ├── rc.lua
│   │           ├── statusbar/
│   │           │   ├── init.lua
│   │           │   └── modules/
│   │           │       ├── battery/
│   │           │       │   └── init.lua
│   │           │       ├── clock/
│   │           │       │   └── init.lua
│   │           │       ├── cpu/
│   │           │       │   └── init.lua
│   │           │       ├── launcher.lua
│   │           │       ├── memory/
│   │           │       │   └── init.lua
│   │           │       ├── netspeed/
│   │           │       │   └── init.lua
│   │           │       ├── systray.lua
│   │           │       ├── taglist.lua
│   │           │       ├── temp/
│   │           │       │   └── init.lua
│   │           │       ├── todo/
│   │           │       │   └── init.lua
│   │           │       └── volume/
│   │           │           └── init.lua
│   │           └── themes/
│   │               └── main/
│   │                   ├── colours.lua
│   │                   ├── elements.lua
│   │                   ├── naughty.lua
│   │                   └── theme.lua
│   ├── fcitx5/
│   │   └── .config/
│   │       └── fcitx5/
│   │           ├── conf/
│   │           │   ├── cached_layouts
│   │           │   ├── classicui.conf
│   │           │   ├── clipboard.conf
│   │           │   ├── imselector.conf
│   │           │   ├── keyboard-longpress.conf
│   │           │   ├── keyboard.conf
│   │           │   ├── mozc.conf
│   │           │   ├── notifications.conf
│   │           │   ├── xcb.conf
│   │           │   └── xim.conf
│   │           ├── config
│   │           ├── profile
│   │           └── profile_KrsNBN
│   ├── flameshot/
│   │   └── .config/
│   │       └── flameshot/
│   │           └── flameshot.ini
│   ├── kitty/
│   │   └── .config/
│   │       └── kitty/
│   │           ├── gitgud-dark.conf
│   │           ├── gruvy.conf
│   │           ├── icy.conf
│   │           ├── kitty.conf
│   │           └── visual-studio-dark.conf
│   ├── lf/
│   │   └── .config/
│   │       └── lf/
│   │           ├── lfrc
│   │           └── preview
│   ├── pages/
│   │   ├── chrome-page/
│   │   │   ├── index.html
│   │   │   ├── main.js
│   │   │   ├── manifest.json
│   │   │   └── style.css
│   │   ├── ryuko/
│   │   │   └── slim.theme
│   │   ├── startpage/
│   │   │   ├── index.html
│   │   │   ├── main.js
│   │   │   ├── manifest.json
│   │   │   └── style.css
│   │   └── startpage-v2/
│   │       ├── index.html
│   │       ├── main.js
│   │       ├── manifest.json
│   │       ├── startpage.xpi
│   │       ├── style.css
│   │       └── test.vue
│   ├── scripts/
│   │   └── .scripts/
│   │       ├── extract
│   │       ├── launcher
│   │       └── lf
│   ├── tmux/
│   │   └── .tmux.conf
│   └── vscode/
│       └── .config/
│           └── Code/
│               └── User/
│                   ├── keybindings.json
│                   └── settings.json
├── misc/
│   ├── .bashrc
│   └── .profile
├── modules/
│   ├── brews.nix
│   ├── casks.nix
│   ├── darwin-config.nix
│   ├── darwin-home.nix
│   ├── darwin-packages.nix
│   ├── git.nix
│   ├── gpg.nix
│   ├── home-common.nix
│   ├── linux-home.nix
│   ├── linux-packages.nix
│   ├── linux-terminals.nix
│   └── packages.nix
├── nushell/
│   ├── ai.nu
│   ├── alias.nu
│   ├── bash-env.nu
│   ├── config.nu
│   ├── rose-pine-dawn.nu
│   ├── rose-pine-moon.nu
│   ├── vendor/
│   │   └── autoload/
│   │       └── starship.nu
│   └── zoxide.nu
├── nvim/
│   ├── init.lua
│   ├── lazy-lock.json
│   ├── lua/
│   │   ├── config/
│   │   │   ├── autocmds.lua
│   │   │   ├── lazy.lua
│   │   │   ├── lsp.lua
│   │   │   ├── mappings.lua
│   │   │   ├── options.lua
│   │   │   └── utils.lua
│   │   └── plugins/
│   │       ├── align.lua
│   │       ├── cmp.lua
│   │       ├── colorscheme.lua
│   │       ├── conform.lua
│   │       ├── dropbar.lua
│   │       ├── fff.lua
│   │       ├── flash.lua
│   │       ├── flutter-tools.off.lua
│   │       ├── gitsigns.lua
│   │       ├── lua-ls.lua
│   │       ├── markdown.lua
│   │       ├── mason-lsp.lua
│   │       ├── mason.lua
│   │       ├── mini-ai.lua
│   │       ├── mini-surround.lua
│   │       ├── neo-tree.lua
│   │       ├── nvim-ts-autotag.lua
│   │       ├── obsidian.lua
│   │       ├── pairs.lua
│   │       ├── qf.lua
│   │       ├── snacks.lua
│   │       ├── statuscolumn.lua
│   │       ├── supermaven.lua
│   │       ├── treesitter.lua
│   │       ├── ts-comments.lua
│   │       ├── typescript.lua
│   │       ├── typst.lua
│   │       ├── ufo.lua
│   │       └── which-key.lua
│   └── queries/
│       └── blade/
│           ├── highlights.scm
│           └── injections.scm
├── wezterm/
│   └── wezterm.lua
├── yazi/
│   └── yazi.toml
└── zellij/
    ├── config.kdl
    ├── layouts/
    │   └── plain.kdl
    └── themes/
        ├── rose-pine-dawn.kdl
        └── rose-pine.kdl

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
result
config/fish/fish_variables
__pycache__

nushell/history*
bin
node_modules


================================================
FILE: .gitmodules
================================================
[submodule "dotbot"]
	path = dotbot
	url = https://github.com/anishathalye/dotbot
	ignore = dirty


================================================
FILE: Makefile
================================================
linux:
	nh home switch --flake .#elianiva --print-build-logs

darwin:
	nh darwin switch .

clean:
	nh clean


================================================
FILE: README.md
================================================
# elianiva's personal dotfiles

This is my personal dotfiles repository which has gone through many iterations.

Here are some of the screenshots from time to time (the config may or may not be still here, idk):

![arch](./screenshots/preview-arch.png)
![arch-new](./screenshots/preview-arch-new.png)
![old](./screenshots/preview-old.png)
![plasma](./screenshots/preview-plasma.png)
![fedora](./screenshots/preview-fedora.png)
![fedora-2](https://github.com/user-attachments/assets/ce263afd-1986-4c55-93a8-10494302c464)
![macos](https://github.com/user-attachments/assets/e6a1be22-b773-4e0c-b022-eedc70fa8ca8)


================================================
FILE: agents/AGENTS.md
================================================
# Important Rules
- Be extremely concise. Sacrifice grammar for the sake of concision.
- Don't add tests for what the type system already guarantees.
- At the end of each plan, give me a list of unresolved questions to answer, if any. The last thing visible should be numbered list of questions or concrete steps.
- No compatibility wrappers, no legacy shims, no temporary plumbing, no backward compats, no reexport for "convenience".
- Treat the project as greenfield unless stated otherwise.
- You are not alone, expect parallel changes in unrelated files by others.


================================================
FILE: agents/opencode/opencode.json
================================================
{
  "$schema": "https://opencode.ai/config.json",
  "agent": {
    "general": {
      "disable": true
    },
    "explore": {
      "disable": true
    },
    "plan": {
      "permission": {
        "edit": {
          "*": "deny",
          "*.md": "ask"
        },
        "skill": {
          "*": "deny",
          "code-review-*": "allow",
          "brainstorming": "allow",
          "build-feature": "allow",
          "*-best-practices": "allow",
        }
      }
    }
  },
  "permission": {
    "*": "deny",
    "read": "allow",
    "write": "allow",
    "bash": "allow",
    "webfetch": "allow",
    "websearch": "allow",
    "lsp": "allow",
    "list": "allow",
    "grep": "allow",
    "glob": "allow",
    "edit": "allow",
    "external_directory": {
      "*": "ask",
      "~/Development/personal/*": "allow",
      "~/Development/work/*": "allow",
      "~/Repositories/*": "allow",
      "/tmp/*": "allow",
    },
    "question": "allow",
    "codesearch": "allow",
    "skill": {
      "*": "allow",
      "pdf": "deny",
      "xlsx": "deny",
    },
  }
}


================================================
FILE: agents/pi/extensions/agent-profiles.ts
================================================
/**
 * Agent Profiles Extension
 *
 * Define agent personas in markdown files with frontmatter.
 * Content is appended to system prompt each turn.
 *
 * Location:
 * - ~/.pi/agent/agents/*.md (global)
 * - .pi/agents/*.md (project-local, overrides)
 *
 * Format:
 * ```markdown
 * ---
 * name: my-agent
 * description: What this agent does
 * tools: [read, bash, edit, write]  # whitelist (omit for all)
 * disabledTools: [grep]             # blacklist (omit for none)
 * ---
 *
 * Your system prompt additions here...
 * ```
 *
 * Usage:
 * - `pi --agent plan` - start with plan agent
 * - `/agent` - show selector
 * - `/agent plan` - switch to plan agent
 * - `/agent default` - reset to default
 */

import { existsSync, readFileSync, readdirSync } from "node:fs";
import { homedir } from "node:os";
import { join, basename, extname } from "node:path";
import type {
  ExtensionAPI,
  ExtensionContext,
} from "@mariozechner/pi-coding-agent";
import { DynamicBorder } from "@mariozechner/pi-coding-agent";
import {
  Key,
  Container,
  type SelectItem,
  SelectList,
  Text,
} from "@mariozechner/pi-tui";

interface AgentProfile {
  name: string;
  description: string;
  tools?: string[];
  disabledTools?: string[];
  provider?: string;
  content: string; // appended to system prompt
}

const DEFAULT_TOOLS = ["read", "bash", "edit", "write", "grep", "find", "ls", "mcp", "ask"];

// Hardcoded default agent - always available as fallback
const DEFAULT_AGENT: AgentProfile = {
  name: "default",
  description: "Default agent with full capabilities",
  tools: DEFAULT_TOOLS,
  content:
    "You are pi, a minimal terminal coding agent. Use the tools available to help the user.",
};

/**
 * Parse frontmatter from markdown content
 */
function parseFrontmatter(content: string): {
  frontmatter: Record<string, unknown>;
  body: string;
} {
  const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
  if (!match) {
    return { frontmatter: {}, body: content };
  }

  const yamlText = match[1];
  const body = match[2].trim();

  const frontmatter: Record<string, unknown> = {};
  for (const line of yamlText.split("\n")) {
    const colonIdx = line.indexOf(":");
    if (colonIdx === -1) continue;

    const key = line.slice(0, colonIdx).trim();
    let value: unknown = line.slice(colonIdx + 1).trim();

    // Parse arrays: [item1, item2]
    if (
      typeof value === "string" &&
      value.startsWith("[") &&
      value.endsWith("]")
    ) {
      value = value
        .slice(1, -1)
        .split(",")
        .map((s) => s.trim())
        .filter(Boolean);
    }

    frontmatter[key] = value;
  }

  return { frontmatter, body };
}

/**
 * Load agent profiles from directory
 */
function loadAgentsFromDir(dir: string): Map<string, AgentProfile> {
  const agents = new Map<string, AgentProfile>();

  if (!existsSync(dir)) return agents;

  const entries = readdirSync(dir, { withFileTypes: true });

  for (const entry of entries) {
    if (!entry.isFile()) continue;
    if (extname(entry.name) !== ".md") continue;

    const filepath = join(dir, entry.name);
    try {
      const content = readFileSync(filepath, "utf-8");
      const { frontmatter, body } = parseFrontmatter(content);

      const name = (frontmatter.name as string) || basename(entry.name, ".md");

      agents.set(name, {
        name,
        description: (frontmatter.description as string) || "",
        tools: frontmatter.tools as string[] | undefined,
        disabledTools: frontmatter.disabledTools as string[] | undefined,
        provider: frontmatter.provider as string | undefined,
        content: body,
      });
    } catch {
      // skip invalid files
    }
  }

  return agents;
}

/**
 * Load all agents (global + project, project overrides)
 * Default agent is always available as fallback
 */
function loadAgents(cwd: string): Map<string, AgentProfile> {
  const globalDir = join(homedir(), ".pi", "agent", "agents");
  const projectDir = join(cwd, ".pi", "agents");

  // Start with default agent
  const agents = new Map<string, AgentProfile>();
  agents.set("default", DEFAULT_AGENT);

  // Load global agents (can override default if explicitly defined)
  const globalAgents = loadAgentsFromDir(globalDir);
  for (const [name, agent] of globalAgents) {
    agents.set(name, agent);
  }

  // Load project agents (override global)
  const projectAgents = loadAgentsFromDir(projectDir);
  for (const [name, agent] of projectAgents) {
    agents.set(name, agent);
  }

  return agents;
}

/**
 * Get effective tools list for an agent
 */
function getEffectiveTools(agent: AgentProfile | undefined): string[] {
  if (!agent) return DEFAULT_TOOLS;

  // Explicit whitelist
  if (agent.tools) {
    return agent.tools.filter((t) => DEFAULT_TOOLS.includes(t));
  }

  // Blacklist mode
  if (agent.disabledTools) {
    return DEFAULT_TOOLS.filter((t) => !agent.disabledTools?.includes(t));
  }

  return DEFAULT_TOOLS;
}

export default function agentProfilesExtension(pi: ExtensionAPI) {
  let agents = new Map<string, AgentProfile>();
  let activeAgent: AgentProfile | undefined;
  let baseSystemPrompt = ""; // captured at session start

  // Register --agent CLI flag
  pi.registerFlag("agent", {
    description: "Agent profile to use",
    type: "string",
  });

  /**
   * Apply an agent profile
   */
  async function applyAgent(
    name: string,
    agent: AgentProfile | undefined,
    ctx: ExtensionContext,
  ): Promise<void> {
    activeAgent = agent;

    // Emit event for other extensions (e.g., starship-prompt)
    pi.events.emit("agent-profile:changed", {
      name: agent?.name ?? "default",
      description: agent?.description ?? "",
    });

    if (!agent) {
      // Reset to default
      pi.setActiveTools(DEFAULT_TOOLS);
      ctx.ui.notify("Reset to default agent", "info");
      updateStatus(ctx);
      return;
    }

    // Apply tools - this rebuilds the system prompt with correct tool descriptions
    const tools = getEffectiveTools(agent);
    pi.setActiveTools(tools);

    ctx.ui.notify(`Agent "${name}" activated (${tools.length} tools)`, "info");
    updateStatus(ctx);
  }

  /**
   * Build description for UI
   */
  function buildDescription(agent: AgentProfile): string {
    const parts: string[] = [];

    const tools = getEffectiveTools(agent);
    if (tools.length !== DEFAULT_TOOLS.length) {
      parts.push(`${tools.length} tools`);
    }

    if (agent.description) {
      const truncated =
        agent.description.length > 40
          ? `${agent.description.slice(0, 37)}...`
          : agent.description;
      parts.push(truncated);
    }

    return parts.join(" | ") || "Custom agent profile";
  }

  /**
   * Show agent selector UI
   */
  async function showAgentSelector(ctx: ExtensionContext): Promise<void> {
    const agentList = Array.from(agents.values()).sort((a, b) =>
      a.name.localeCompare(b.name),
    );

    if (agentList.length === 0) {
      ctx.ui.notify(
        "No agent profiles found. Create files in ~/.pi/agent/agents/ or .pi/agents/",
        "warning",
      );
      return;
    }

    const items: SelectItem[] = [
      {
        value: "default",
        label: "default",
        description: "Reset to default (all tools, no additions)",
      },
      ...agentList.map((agent) => ({
        value: agent.name,
        label:
          agent.name === activeAgent?.name
            ? `${agent.name} (active)`
            : agent.name,
        description: buildDescription(agent),
      })),
    ];

    const result = await ctx.ui.custom<string | null>(
      (tui, theme, _kb, done) => {
        const container = new Container();
        container.addChild(new DynamicBorder((str) => theme.fg("accent", str)));
        container.addChild(
          new Text(theme.fg("accent", theme.bold("Select Agent Profile"))),
        );

        const selectList = new SelectList(items, Math.min(items.length, 12), {
          selectedPrefix: (text) => theme.fg("accent", text),
          selectedText: (text) => theme.fg("accent", text),
          description: (text) => theme.fg("muted", text),
          scrollInfo: (text) => theme.fg("dim", text),
          noMatch: (text) => theme.fg("warning", text),
        });

        selectList.onSelect = (item) => done(item.value);
        selectList.onCancel = () => done(null);

        const k = (s: string) => theme.bold(theme.fg("accent", s));
        const l = (s: string) => theme.fg("dim", s);
        container.addChild(selectList);
        container.addChild(
          new Text(
            ` ${k("↑↓")}${l(" select")} · ${k("enter")}${l(" submit")} · ${k("esc")}${l(" dismiss")}`,
          ),
        );
        container.addChild(new DynamicBorder((str) => theme.fg("accent", str)));

        return {
          render(width: number) {
            return container.render(width);
          },
          invalidate() {
            container.invalidate();
          },
          handleInput(data: string) {
            selectList.handleInput(data);
            tui.requestRender();
          },
        };
      },
    );

    if (!result) return;

    if (result === "default") {
      await applyAgent("default", undefined, ctx);
    } else {
      const agent = agents.get(result);
      if (agent) {
        await applyAgent(result, agent, ctx);
      }
    }
  }

  /**
   * Update status in footer
   */
  function updateStatus(ctx: ExtensionContext) {
    if (activeAgent && activeAgent.name !== "default") {
      ctx.ui.setStatus(
        "agent",
        ctx.ui.theme.fg("accent", `agent:${activeAgent.name}`),
      );
    } else {
      ctx.ui.setStatus("agent", undefined);
    }
  }

  /**
   * Get ordered list of agent names for cycling
   */
  function getAgentOrder(): string[] {
    return [
      "default",
      ...Array.from(agents.keys())
        .filter((n) => n !== "default")
        .sort(),
    ];
  }

  /**
   * Cycle to next agent
   */
  async function cycleAgent(ctx: ExtensionContext): Promise<void> {
    const agentNames = getAgentOrder();
    if (agentNames.length <= 1) {
      ctx.ui.notify("No custom agents to cycle", "warning");
      return;
    }

    const currentName = activeAgent?.name ?? "default";
    const currentIndex = agentNames.indexOf(currentName);
    const nextIndex =
      currentIndex === -1 ? 0 : (currentIndex + 1) % agentNames.length;
    const nextName = agentNames[nextIndex];

    if (nextName === "default") {
      await applyAgent("default", undefined, ctx);
    } else {
      const agent = agents.get(nextName);
      if (agent) {
        await applyAgent(nextName, agent, ctx);
      }
    }
  }

  // Register keyboard shortcut to cycle agents
  pi.registerShortcut(Key.ctrl(";"), {
    description: "Cycle to next agent profile",
    handler: (ctx) => cycleAgent(ctx),
  });

  // Inject agent content into system prompt each turn
  // This appends to the base system prompt (which was already rebuilt with correct tools)
  pi.on("before_agent_start", async (event) => {
    if (activeAgent?.content) {
      return {
        systemPrompt: `${event.systemPrompt}\n\n${activeAgent.content}`,
      };
    }
  });

  // Initialize on session start
  pi.on("session_start", async (_event, ctx) => {
    // Load agents (includes hardcoded default)
    agents = loadAgents(ctx.cwd);

    // Set default as initial active agent
    activeAgent = DEFAULT_AGENT;

    // Capture base system prompt (for reference, not used directly)
    baseSystemPrompt = ctx.getSystemPrompt();

    // Emit initial state immediately so other extensions (e.g., starship-prompt) have valid state
    pi.events.emit("agent-profile:changed", {
      name: DEFAULT_AGENT.name,
      description: DEFAULT_AGENT.description,
    });

    // Check CLI flag first
    const agentFlag = pi.getFlag("agent");
    if (typeof agentFlag === "string" && agentFlag) {
      if (agentFlag === "default") {
        // Already default, just notify
        ctx.ui.notify("Using default agent", "info");
      } else {
        const agent = agents.get(agentFlag);
        if (agent) {
          await applyAgent(agentFlag, agent, ctx);
        } else {
          const available = ["default", ...Array.from(agents.keys())].join(
            ", ",
          );
          ctx.ui.notify(
            `Unknown agent "${agentFlag}". Available: ${available}`,
            "warning",
          );
        }
      }
      updateStatus(ctx);
      return;
    }

    // Restore from session state
    const entries = ctx.sessionManager.getEntries();
    const agentEntry = entries
      .filter(
        (e: { type: string; customType?: string }) =>
          e.type === "custom" && e.customType === "agent-profile",
      )
      .pop() as { data?: { name: string } } | undefined;

    if (agentEntry?.data?.name && agentEntry.data.name !== "default") {
      const agent = agents.get(agentEntry.data.name);
      if (agent) {
        await applyAgent(agentEntry.data.name, agent, ctx);
      }
    }

    updateStatus(ctx);
  });

  // Persist active agent when it changes
  pi.on("agent-profile:changed", async (event) => {
    pi.appendEntry("agent-profile", { name: event.name });
  });

  // Register /agent command
  pi.registerCommand("agent", {
    description: "Switch agent profile",
    handler: async (args, ctx) => {
      const name = args?.trim();

      if (!name) {
        await showAgentSelector(ctx);
        return;
      }

      if (name === "default") {
        await applyAgent("default", undefined, ctx);
        return;
      }

      const agent = agents.get(name);
      if (!agent) {
        const available = ["default", ...Array.from(agents.keys())].join(", ");
        ctx.ui.notify(
          `Unknown agent "${name}". Available: ${available}`,
          "error",
        );
        return;
      }

      await applyAgent(name, agent, ctx);
    },
  });
}


================================================
FILE: agents/pi/extensions/ask.ts
================================================
/**
 * Ask Tool Extension
 *
 * Provides an interactive Q&A tool for the LLM to ask users questions
 * with multiple choice options or free-form text input.
 */

import type { ExtensionAPI, ToolResult } from "@mariozechner/pi-coding-agent";
import { Key, matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
import { Type } from "@sinclair/typebox";

// Ask tool option schema
const AskOptionSchema = Type.Object({
  label: Type.String({ description: "Display label for the option" }),
  description: Type.Optional(
    Type.String({ description: "Optional description shown below label" }),
  ),
});

const AskQuestionSchema = Type.Object({
  question: Type.String({ description: "The question to ask the user" }),
  options: Type.Array(AskOptionSchema, {
    description: "Options for the user to choose from",
  }),
  shortTitle: Type.Optional(
    Type.String({
      description: "Short 1-2 word title for tab display (defaults to number)",
    }),
  ),
});

// Single object with everything optional to avoid union issues
const AskParams = Type.Object({
  questions: Type.Optional(
    Type.Array(AskQuestionSchema, {
      description: "A list of questions to ask the user",
    }),
  ),
  question: Type.Optional(
    Type.String({ description: "The question to ask the user" }),
  ),
  options: Type.Optional(
    Type.Array(AskOptionSchema, {
      description: "Options for the user to choose from",
    }),
  ),
});

interface AskDetails {
  question: string;
  options: string[];
  answer: string | null;
  wasCustom?: boolean;
}

interface MultiAskDetails {
  results: AskDetails[];
}

interface QuestionState {
  optionIndex: number;
  editMode: boolean;
  customAnswer: string;
  answer: string | null;
  wasCustom: boolean;
}

export default function askToolExtension(pi: ExtensionAPI): void {
  pi.registerTool({
    name: "ask",
    label: "Ask",
    description:
      "Ask the user one or more questions and let them pick from options or type a custom answer. Use when you need user input to proceed with a decision.",
    parameters: AskParams,

    async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
      const questions: {
        question: string;
        options: { label: string; description?: string }[];
        shortTitle?: string;
      }[] = [];

      if (params.questions && params.questions.length > 0) {
        questions.push(...params.questions);
      } else if (params.question && params.options) {
        questions.push({ question: params.question, options: params.options });
      }

      if (questions.length === 0) {
        return {
          content: [
            {
              type: "text",
              text: "Error: No questions (or question/options) provided",
            },
          ],
        };
      }

      if (!ctx.hasUI) {
        return {
          content: [
            {
              type: "text",
              text: "Error: UI not available (running in non-interactive mode)",
            },
          ],
          details: {
            results: questions.map((q) => ({
              question: q.question,
              options: q.options.map((o) => o.label),
              answer: null,
            })),
          } as MultiAskDetails,
        };
      }

      // Single question: use simple flow (no tabs, no review)
      if (questions.length === 1) {
        return handleSingleQuestion(ctx, questions[0]);
      }

      // Multiple questions: use tabbed UI with review
      return handleMultipleQuestions(ctx, questions);
    },
  });
}

async function handleSingleQuestion(
  ctx: ExtensionAPI["ctx"],
  q: {
    question: string;
    options: { label: string; description?: string }[];
    shortTitle?: string;
  },
): Promise<ToolResult> {
  const allOptions = [
    ...q.options,
    { label: "Type your own answer", description: "Write a custom response" },
  ];

  const result = await ctx.ui.custom<{
    answer: string;
    wasCustom: boolean;
    index?: number;
  } | null>((tui, theme, _kb, done) => {
    let optionIndex = 0;
    let editMode = false;
    let customAnswer = "";
    let cachedLines: string[] | undefined;

    function refresh() {
      cachedLines = undefined;
      tui.requestRender();
    }

    function handleInput(data: string) {
      if (editMode) {
        if (matchesKey(data, Key.escape)) {
          editMode = false;
          customAnswer = "";
          refresh();
          return;
        }
        if (matchesKey(data, Key.enter)) {
          const trimmed = customAnswer.trim();
          if (trimmed) {
            done({ answer: trimmed, wasCustom: true });
          } else {
            editMode = false;
            customAnswer = "";
            refresh();
          }
          return;
        }
        if (matchesKey(data, Key.backspace)) {
          customAnswer = customAnswer.slice(0, -1);
          refresh();
          return;
        }
        if (data.length === 1 && data.charCodeAt(0) >= 32) {
          customAnswer += data;
          refresh();
        }
        return;
      }

      if (matchesKey(data, Key.up)) {
        optionIndex = Math.max(0, optionIndex - 1);
        refresh();
        return;
      }
      if (matchesKey(data, Key.down)) {
        optionIndex = Math.min(allOptions.length - 1, optionIndex + 1);
        refresh();
        return;
      }
      if (matchesKey(data, Key.enter)) {
        const selected = allOptions[optionIndex];
        const isLastOption = optionIndex === allOptions.length - 1;
        if (isLastOption) {
          editMode = true;
          refresh();
        } else {
          done({
            answer: selected.label,
            wasCustom: false,
            index: optionIndex + 1,
          });
        }
        return;
      }
      if (matchesKey(data, Key.escape)) {
        done(null);
      }
    }

    function render(width: number): string[] {
      if (cachedLines) return cachedLines;

      const lines: string[] = [];
      const add = (s: string) => lines.push(truncateToWidth(s, width));

      // Top border
      add(theme.fg("accent", "─".repeat(width)));

      // Question
      add(theme.fg("text", ` ${q.question}`));
      lines.push("");

      // Options
      for (let i = 0; i < allOptions.length; i++) {
        const opt = allOptions[i];
        const selected = i === optionIndex;
        const isLast = i === allOptions.length - 1;
        const prefix = selected ? theme.fg("accent", "> ") : "  ";
        const num = `${i + 1}.`;

        if (isLast && editMode) {
          add(prefix + theme.fg("accent", `${num} ${opt.label} ✎`));
        } else if (selected) {
          add(prefix + theme.fg("accent", `${num} ${opt.label}`));
        } else {
          add(`  ${theme.fg("text", `${num} ${opt.label}`)}`);
        }

        if (opt.description) {
          add(`     ${theme.fg("muted", opt.description)}`);
        }
      }

      if (editMode) {
        lines.push("");
        add(theme.fg("muted", " Your answer:"));
        const inputLine = ` > ${customAnswer}_`;
        add(truncateToWidth(inputLine, width));
      }

      // Help text
      lines.push("");
      const k = (s: string) => theme.bold(theme.fg("accent", s));
      const l = (s: string) => theme.fg("dim", s);
      if (editMode) {
        add(` ${k("enter")}${l(" · submit")} · ${k("esc")}${l(" go back")}`);
      } else {
        add(
          ` ${k("↑↓")}${l(" select")} · ${k("enter")}${l(" submit")} · ${k("esc")}${l(" dismiss")}`,
        );
      }

      // Bottom border
      add(theme.fg("accent", "─".repeat(width)));

      cachedLines = lines;
      return lines;
    }

    return {
      render,
      invalidate: () => {
        cachedLines = undefined;
      },
      handleInput,
    };
  });

  if (!result) {
    return {
      content: [{ type: "text", text: "User cancelled the question" }],
      details: {
        results: [
          {
            question: q.question,
            options: q.options.map((o) => o.label),
            answer: null,
          },
        ],
      } as MultiAskDetails,
    };
  }

  return {
    content: [
      {
        type: "text",
        text: result.wasCustom
          ? `User answered: ${result.answer}`
          : `User selected: ${result.answer}`,
      },
    ],
    details: {
      results: [
        {
          question: q.question,
          options: q.options.map((o) => o.label),
          answer: result.answer,
          wasCustom: result.wasCustom,
        },
      ],
    } as MultiAskDetails,
  };
}

async function handleMultipleQuestions(
  ctx: ExtensionAPI["ctx"],
  questions: {
    question: string;
    options: { label: string; description?: string }[];
    shortTitle?: string;
  }[],
): Promise<ToolResult> {
  // Initialize state for each question
  const states: QuestionState[] = questions.map(() => ({
    optionIndex: 0,
    editMode: false,
    customAnswer: "",
    answer: null as string | null,
    wasCustom: false,
  }));

  let currentQuestion = 0;
  let inReview = false;
  let reviewOptionIndex = 0; // 0 = go back, 1 = submit

  const result = await ctx.ui.custom<{
    results: { answer: string; wasCustom: boolean }[];
  } | null>((tui, theme, _kb, done) => {
    let cachedLines: string[] | undefined;

    function refresh() {
      cachedLines = undefined;
      tui.requestRender();
    }

    function getCurrentOptions() {
      const q = questions[currentQuestion];
      return [
        ...q.options,
        {
          label: "Type your own answer",
          description: "Write a custom response",
        },
      ];
    }

    function handleInput(data: string) {
      if (inReview) {
        handleReviewInput(data);
        return;
      }

      const state = states[currentQuestion];
      const allOptions = getCurrentOptions();

      if (state.editMode) {
        if (matchesKey(data, Key.escape)) {
          state.editMode = false;
          state.customAnswer = "";
          refresh();
          return;
        }
        if (matchesKey(data, Key.enter)) {
          const trimmed = state.customAnswer.trim();
          if (trimmed) {
            state.answer = trimmed;
            state.wasCustom = true;
            state.editMode = false;
            // Auto-advance to next question or review
            if (currentQuestion < questions.length - 1) {
              currentQuestion++;
            } else {
              inReview = true;
            }
            refresh();
          } else {
            state.editMode = false;
            state.customAnswer = "";
            refresh();
          }
          return;
        }
        if (matchesKey(data, Key.backspace)) {
          state.customAnswer = state.customAnswer.slice(0, -1);
          refresh();
          return;
        }
        if (data.length === 1 && data.charCodeAt(0) >= 32) {
          state.customAnswer += data;
          refresh();
        }
        return;
      }

      // Tab navigation between questions
      if (matchesKey(data, Key.tab)) {
        currentQuestion = (currentQuestion + 1) % questions.length;
        refresh();
        return;
      }
      if (matchesKey(data, Key.shift(Key.tab))) {
        currentQuestion =
          (currentQuestion - 1 + questions.length) % questions.length;
        refresh();
        return;
      }

      // Option selection within current question
      if (matchesKey(data, Key.up)) {
        state.optionIndex = Math.max(0, state.optionIndex - 1);
        refresh();
        return;
      }
      if (matchesKey(data, Key.down)) {
        state.optionIndex = Math.min(
          allOptions.length - 1,
          state.optionIndex + 1,
        );
        refresh();
        return;
      }
      if (matchesKey(data, Key.enter)) {
        const selected = allOptions[state.optionIndex];
        const isLastOption = state.optionIndex === allOptions.length - 1;
        if (isLastOption) {
          state.editMode = true;
          refresh();
        } else {
          state.answer = selected.label;
          state.wasCustom = false;
          // Auto-advance to next question or review
          if (currentQuestion < questions.length - 1) {
            currentQuestion++;
          } else {
            inReview = true;
          }
          refresh();
        }
        return;
      }
      if (matchesKey(data, Key.escape)) {
        done(null);
      }
    }

    function handleReviewInput(data: string) {
      if (matchesKey(data, Key.left) || matchesKey(data, Key.up)) {
        reviewOptionIndex = 0;
        refresh();
        return;
      }
      if (matchesKey(data, Key.right) || matchesKey(data, Key.down)) {
        reviewOptionIndex = 1;
        refresh();
        return;
      }
      if (matchesKey(data, Key.enter)) {
        if (reviewOptionIndex === 0) {
          // Go back to edit
          inReview = false;
          currentQuestion = 0;
          refresh();
        } else {
          // Submit
          done({
            results: states.map((s) => ({
              answer: s.answer!,
              wasCustom: s.wasCustom,
            })),
          });
        }
        return;
      }
      if (matchesKey(data, Key.escape)) {
        inReview = false;
        refresh();
      }
    }

    function render(width: number): string[] {
      if (cachedLines) return cachedLines;

      if (inReview) {
        return renderReview(width);
      }
      return renderQuestion(width);
    }

    function renderQuestion(width: number): string[] {
      const lines: string[] = [];
      const add = (s: string) => lines.push(truncateToWidth(s, width));
      const state = states[currentQuestion];
      const q = questions[currentQuestion];
      const allOptions = getCurrentOptions();

      // Tab bar with short titles (fallback to numbers)
      const tabs = questions.map((q, i) => {
        const isActive = i === currentQuestion;
        const isAnswered = states[i].answer !== null;
        const label = q.shortTitle || `${i + 1}`;
        if (isActive) {
          return theme.fg("accent", theme.bold(label));
        }
        if (isAnswered) {
          return theme.fg("muted", `${label}✓`);
        }
        return theme.fg("dim", label);
      });
      add(tabs.join(" · "));

      // Top border
      add(theme.fg("accent", "─".repeat(width)));

      // Question
      add(theme.fg("text", ` ${q.question}`));
      lines.push("");

      // Options
      for (let i = 0; i < allOptions.length; i++) {
        const opt = allOptions[i];
        const selected = i === state.optionIndex;
        const isLast = i === allOptions.length - 1;
        const prefix = selected ? theme.fg("accent", "> ") : "  ";
        const num = `${i + 1}.`;
        const isActive = !isLast && state.answer === opt.label;
        const check = isActive ? ` ${theme.fg("accent", "✓")}` : "";

        if (isLast && state.editMode) {
          add(prefix + theme.fg("accent", `${num} ${opt.label} ✎`));
        } else if (isLast && state.wasCustom && state.answer) {
          add(
            prefix +
              (selected
                ? theme.fg("accent", `${num} ${opt.label}`)
                : theme.fg("text", `${num} ${opt.label}`)) +
              ` ${theme.fg("accent", "✓")}`,
          );
        } else if (selected) {
          add(prefix + theme.fg("accent", `${num} ${opt.label}`) + check);
        } else {
          add(`  ${theme.fg("text", `${num} ${opt.label}`)}` + check);
        }

        if (opt.description) {
          add(`     ${theme.fg("muted", opt.description)}`);
        }
      }

      if (state.editMode) {
        lines.push("");
        add(theme.fg("muted", " Your answer:"));
        const inputLine = ` > ${state.customAnswer}_`;
        add(truncateToWidth(inputLine, width));
      }

      // Help text
      lines.push("");
      const k = (s: string) => theme.bold(theme.fg("accent", s));
      const l = (s: string) => theme.fg("dim", s);
      if (state.editMode) {
        add(` ${k("enter")}${l(" · submit")} · ${k("esc")}${l(" go back")}`);
      } else {
        add(
          ` ${k("↑↓")}${l(" select")} · ${k("tab")}${l(" next")} · ${k("enter")}${l(" submit")} · ${k("esc")}${l(" dismiss")}`,
        );
      }

      // Bottom border
      add(theme.fg("accent", "─".repeat(width)));

      cachedLines = lines;
      return lines;
    }

    function renderReview(width: number): string[] {
      const lines: string[] = [];
      const add = (s: string) => lines.push(truncateToWidth(s, width));

      // Header
      add(theme.fg("accent", theme.bold(" Review your answers")));
      add(theme.fg("accent", "─".repeat(width)));
      lines.push("");

      // Questions and answers
      for (let i = 0; i < questions.length; i++) {
        const q = questions[i];
        const state = states[i];
        const label = q.shortTitle || `Q${i + 1}`;
        add(
          ` ${theme.fg("text", theme.bold(`${label}:`))} ${theme.fg("text", q.question)}`,
        );
        if (state.answer) {
          const prefix = state.wasCustom ? "✎" : "✓";
          add(
            `   ${theme.fg("accent", prefix)} ${theme.fg("text", state.answer)}`,
          );
        } else {
          add(`   ${theme.fg("dim", "○ No answer")}`);
        }
        lines.push("");
      }

      // Action buttons
      const goBackLabel = "← Go back to edit";
      const submitLabel = "✔️Submit answers";
      const goBack =
        reviewOptionIndex === 0
          ? theme.fg("accent", theme.bold(`> ${goBackLabel}`))
          : theme.fg("dim", `  ${goBackLabel}`);
      const submit =
        reviewOptionIndex === 1
          ? theme.fg("accent", theme.bold(`> ${submitLabel}`))
          : theme.fg("dim", `  ${submitLabel}`);
      add(` ${goBack}`);
      add(` ${submit}`);

      // Help text
      lines.push("");
      const k = (s: string) => theme.bold(theme.fg("accent", s));
      const l = (s: string) => theme.fg("dim", s);
      add(
        ` ${k("↑↓")}${l(" select")} · ${k("enter")}${l(" confirm")} · ${k("esc")}${l(" go back")}`,
      );

      // Bottom border
      add(theme.fg("accent", "─".repeat(width)));

      cachedLines = lines;
      return lines;
    }

    return {
      render,
      invalidate: () => {
        cachedLines = undefined;
      },
      handleInput,
    };
  });

  if (!result) {
    return {
      content: [{ type: "text", text: "User cancelled the questions" }],
      details: {
        results: questions.map((q, i) => ({
          question: q.question,
          options: q.options.map((o) => o.label),
          answer: states[i].answer,
        })),
      } as MultiAskDetails,
    };
  }

  // Format output
  const outputText = questions
    .map((q, i) => {
      const r = result.results[i];
      const prefix = r.wasCustom ? "Answered" : "Selected";
      const label = q.shortTitle || `Question ${i + 1}`;
      return `${label}: ${q.question}\n${prefix}: ${r.answer}`;
    })
    .join("\n\n");

  return {
    content: [{ type: "text", text: outputText }],
    details: {
      results: questions.map((q, i) => ({
        question: q.question,
        options: q.options.map((o) => o.label),
        answer: result.results[i].answer,
        wasCustom: result.results[i].wasCustom,
      })),
    } as MultiAskDetails,
  };
}


================================================
FILE: agents/pi/extensions/composed-editor/index.ts
================================================
/**
 * Composed Editor - Combines starship-prompt + pi-ckers
 *
 * This is your local extension that composes multiple editor features.
 * Place this in ~/.pi/extensions/composed-editor/
 */

import { type ExtensionAPI, CustomEditor } from "@mariozechner/pi-coding-agent";
import type { Picker } from "@elianiva/pi-ckers";
import { createStarshipWidget, setupStarshipEvents } from "@elianiva/pi-starship";
import { withPickers } from "@elianiva/pi-ckers";
import { filePicker, dirPicker } from "@elianiva/pi-ckers/builtin/fff";
import { grepPicker } from "@elianiva/pi-ckers/builtin/grep";

// Compose: StarshipEditor + all builtin pickers
const pickers: Picker[] = [
  filePicker(),
  dirPicker(),
  grepPicker(),
];

const ComposedEditor = withPickers(CustomEditor, pickers);

export default function composedEditorExtension(pi: ExtensionAPI) {
  pi.on("session_start", async (_event, ctx) => {
    // if (!ctx.hasUI) return;
    //
    // // Set composed editor - pass ctx as 5th argument for picker initialization
    // ctx.ui.setEditorComponent(
    //   (tui, theme, keybindings) => new ComposedEditor(tui, theme, keybindings, undefined, ctx),
    // );

    // Clear footer
    // ctx.ui.setFooter(() => ({ invalidate() {}, render() { return []; } }));

    // // Set up starship widget
    // createStarshipWidget(pi, ctx);
  });

  // Set up starship event handlers
  // setupStarshipEvents(pi);
}


================================================
FILE: agents/pi/extensions/composed-editor/package.json
================================================
{
  "name": "composed-editor",
  "version": "1.0.0",
  "private": true,
  "description": "Composed editor with starship-prompt + pi-ckers",
  "dependencies": {
    "@elianiva/pi-ckers": "link:@elianiva/pi-ckers",
    "@elianiva/pi-starship": "link:@elianiva/pi-starship",
    "@mariozechner/pi-coding-agent": "*"
  }
}


================================================
FILE: agents/pi/extensions/custom-formatting.ts
================================================
import { Theme } from "@mariozechner/pi-coding-agent";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";

/**
 * Extension that overrides markdown bold and italic formatting to use colors instead.
 *
 * It monkey-patches the Theme prototype so it works across all themes
 * and doesn't require polling.
 */
export default function (pi: ExtensionAPI) {
  const originalBold = Theme.prototype.bold;
  const originalItalic = Theme.prototype.italic;

  // Override bold to use 'warning' color (usually yellow/orange)
  Theme.prototype.bold = function(this: Theme, text: string) {
    return originalBold(this.fg("mdHeading", text));
  };

  // Override italic to use 'accent' color (usually teal/cyan)
  Theme.prototype.italic = function(this: Theme, text: string) {
    return originalItalic(this.fg("accent", text));
  };

  // Restore originals on shutdown
  pi.on("session_shutdown", () => {
    Theme.prototype.bold = originalBold;
    Theme.prototype.italic = originalItalic;
  });
}


================================================
FILE: agents/pi/extensions/exit-command.ts
================================================
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";

export default function (pi: ExtensionAPI) {
  pi.on("input", async (event, ctx) => {
    // Only handle plain "exit" without arguments
    if (event.text.trim() === "exit") {
      ctx.shutdown();
      return { action: "handled" };
    }

    return { action: "continue" };
  });
}


================================================
FILE: agents/pi/extensions/handoff.ts
================================================
/**
 * Handoff extension - transfer context to a new focused session
 *
 * Instead of compacting (which is lossy), handoff extracts what matters
 * for your next task and creates a new session with a generated prompt.
 *
 * Usage:
 *   /handoff now implement this for teams as well
 *   /handoff execute phase one of the plan
 *   /handoff check other places that need this fix
 *
 * The generated prompt appears as a draft in the editor for review/editing.
 */

import { complete, type Message } from "@mariozechner/pi-ai";
import type { ExtensionAPI, SessionEntry } from "@mariozechner/pi-coding-agent";
import { BorderedLoader, convertToLlm, serializeConversation } from "@mariozechner/pi-coding-agent";

const SYSTEM_PROMPT = `You are a context transfer assistant. Given a conversation history and the user's goal for a new thread, generate a focused prompt that:

1. Summarizes relevant context from the conversation (decisions made, approaches taken, key findings)
2. Lists any relevant files that were discussed or modified
3. Clearly states the next task based on the user's goal
4. Is self-contained - the new thread should be able to proceed without the old conversation

Format your response as a prompt the user can send to start the new thread. Be concise but include all necessary context. Do not include any preamble like "Here's the prompt" - just output the prompt itself.

Example output format:
## Context
We've been working on X. Key decisions:
- Decision 1
- Decision 2

Files involved:
- path/to/file1.ts
- path/to/file2.ts

## Task
[Clear description of what to do next based on user's goal]`;

export default function (pi: ExtensionAPI) {
	pi.registerCommand("handoff", {
		description: "Transfer context to a new focused session",
		handler: async (args, ctx) => {
			if (!ctx.hasUI) {
				ctx.ui.notify("handoff requires interactive mode", "error");
				return;
			}

			if (!ctx.model) {
				ctx.ui.notify("No model selected", "error");
				return;
			}

			const goal = args.trim();
			if (!goal) {
				ctx.ui.notify("Usage: /handoff <goal for new thread>", "error");
				return;
			}

			// Gather conversation context from current branch
			const branch = ctx.sessionManager.getBranch();
			const messages = branch
				.filter((entry): entry is SessionEntry & { type: "message" } => entry.type === "message")
				.map((entry) => entry.message);

			if (messages.length === 0) {
				ctx.ui.notify("No conversation to hand off", "error");
				return;
			}

			// Convert to LLM format and serialize
			const llmMessages = convertToLlm(messages);
			const conversationText = serializeConversation(llmMessages);
			const currentSessionFile = ctx.sessionManager.getSessionFile();

			// Generate the handoff prompt with loader UI
			const result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {
				const loader = new BorderedLoader(tui, theme, `Generating handoff prompt...`);
				loader.onAbort = () => done(null);

				const doGenerate = async () => {
					const apiKey = await ctx.modelRegistry.getApiKey(ctx.model!);

					const userMessage: Message = {
						role: "user",
						content: [
							{
								type: "text",
								text: `## Conversation History\n\n${conversationText}\n\n## User's Goal for New Thread\n\n${goal}`,
							},
						],
						timestamp: Date.now(),
					};

					const response = await complete(
						ctx.model!,
						{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
						{ apiKey, signal: loader.signal },
					);

					if (response.stopReason === "aborted") {
						return null;
					}

					return response.content
						.filter((c): c is { type: "text"; text: string } => c.type === "text")
						.map((c) => c.text)
						.join("\n");
				};

				doGenerate()
					.then(done)
					.catch((err) => {
						console.error("Handoff generation failed:", err);
						done(null);
					});

				return loader;
			});

			if (result === null) {
				ctx.ui.notify("Cancelled", "info");
				return;
			}

			// Let user edit the generated prompt
			const editedPrompt = await ctx.ui.editor("Edit handoff prompt", result);

			if (editedPrompt === undefined) {
				ctx.ui.notify("Cancelled", "info");
				return;
			}

			// Create new session with parent tracking
			const newSessionResult = await ctx.newSession({
				parentSession: currentSessionFile,
			});

			if (newSessionResult.cancelled) {
				ctx.ui.notify("New session cancelled", "info");
				return;
			}

			// Set the edited prompt in the main editor for submission
			ctx.ui.setEditorText(editedPrompt);
			ctx.ui.notify("Handoff ready. Submit when ready.", "info");
		},
	});
}


================================================
FILE: agents/pi/extensions/lsp/index.ts
================================================
/**
 * LSP Diagnostics Extension
 *
 * Warms up LSP servers on file read, provides diagnostics on write/edit operations.
 * Pattern based on opencode's implementation.
 */

import type {
  ExtensionAPI,
  ToolResultEvent,
  ExtensionContext,
} from "@mariozechner/pi-coding-agent";
import { spawn, type ChildProcess } from "node:child_process";
import { readFileSync } from "node:fs";
import { resolve, extname } from "node:path";
import { pathToFileURL, fileURLToPath } from "node:url";
import {
  createMessageConnection,
  StreamMessageReader,
  StreamMessageWriter,
  type MessageConnection,
} from "vscode-jsonrpc/node";
import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-protocol";
import { LSP_SERVERS, LANGUAGE_MAP, type LspHandle, type LspServerInfo } from "./lsp-config.js";

const DIAGNOSTICS_TIMEOUT_MS = 5000;
const DIAGNOSTICS_DEBOUNCE_MS = 150;
const LSP_CONNECTION_TIMEOUT_MS = 5000;

type Diagnostic = VSCodeDiagnostic;

interface LspConnection {
  connection: MessageConnection;
  process: ChildProcess;
  rootDir: string;
  serverName: string;
  languages: string[];
  startedAt: number;
  lastActivity: number;
  diagnostics: Map<string, Diagnostic[]>;
  openedFiles: Map<string, number>;
  initialized: boolean;
}

interface LspStatus {
  name: string;
  pid: number | undefined;
  rootDir: string;
  languages: string[];
  uptime: number;
  lastActivity: number;
  filesTracked: number;
  initialized: boolean;
}

class LspConnectionManager {
  private connections = new Map<string, LspConnection>();
  private diagnosticCallbacks = new Map<string, Set<() => void>>();

  async getOrCreateConnections(
    filePath: string,
    cwd: string,
    ctx: ExtensionContext,
  ): Promise<LspConnection[]> {
    const ext = extname(filePath);
    const languageId = LANGUAGE_MAP[ext];
    if (!languageId) return [];

    // Find all matching servers
    const matchingServers = LSP_SERVERS.filter((server) => server.extensions.includes(ext));

    const connections: LspConnection[] = [];

    for (const server of matchingServers) {
      const rootDir = await server.root(filePath, cwd);
      if (!rootDir) continue; // Server doesn't apply to this project

      const connectionKey = `${server.id}:${rootDir}`;
      if (this.connections.has(connectionKey)) {
        const conn = this.connections.get(connectionKey)!;
        conn.lastActivity = Date.now();
        connections.push(conn);
        continue;
      }

      try {
        const handle = await server.spawn(rootDir, cwd);
        if (!handle) {
          ctx.ui.notify(`Could not start ${server.id} LSP server`, "error");
          continue;
        }
        const conn = await this.createConnection(
          connectionKey,
          server.id,
          handle,
          rootDir,
          server.extensions,
          ctx,
          AbortSignal.timeout(LSP_CONNECTION_TIMEOUT_MS),
        );
        this.connections.set(connectionKey, conn);
        connections.push(conn);
      } catch (e: any) {
        if (e.name === "TimeoutError") {
          ctx.ui.notify(`${server.id} LSP connection timed out, skipping`, "warning");
        } else {
          ctx.ui.notify(`Failed to start ${server.id} LSP: ${e}`, "error");
        }
      }
    }

    return connections;
  }

  private async createConnection(
    key: string,
    name: string,
    handle: LspHandle,
    rootDir: string,
    languages: string[],
    ctx: ExtensionContext,
    signal: AbortSignal,
  ): Promise<LspConnection> {
    ctx.ui.notify(`Starting ${name} LSP...`, "info");

    const connection = createMessageConnection(
      new StreamMessageReader(handle.process.stdout),
      new StreamMessageWriter(handle.process.stdin),
    );

    const conn: LspConnection = {
      connection,
      process: handle.process,
      rootDir,
      serverName: name,
      languages: [...languages],
      startedAt: Date.now(),
      lastActivity: Date.now(),
      diagnostics: new Map(),
      openedFiles: new Map(),
      initialized: false,
    };

    // Handle diagnostics
    connection.onNotification("textDocument/publishDiagnostics", (params: any) => {
      const filePath = this.normalizePath(fileURLToPath(params.uri));
      conn.diagnostics.set(filePath, params.diagnostics);

      // Notify waiters
      const callbacks = this.diagnosticCallbacks.get(filePath);
      if (callbacks) {
        for (const cb of callbacks) cb();
      }
    });

    // Handle window/workDoneProgress/create
    connection.onRequest("window/workDoneProgress/create", () => null);

    // Handle workspace/configuration
    connection.onRequest("workspace/configuration", async () => [handle.initialization ?? {}]);

    // Handle client/registerCapability
    connection.onRequest("client/registerCapability", async () => {});

    // Handle client/unregisterCapability
    connection.onRequest("client/unregisterCapability", async () => {});

    // Handle workspace/workspaceFolders
    connection.onRequest("workspace/workspaceFolders", async () => [
      {
        name: "workspace",
        uri: pathToFileURL(rootDir).href,
      },
    ]);

    connection.listen();

    // Initialize with timeout using AbortSignal
    try {
      await this.initializeConnection(connection, handle, rootDir, signal);
    } catch (e: any) {
      if (e.name === "TimeoutError") {
        ctx.ui.notify(`${name} LSP connection timed out, continuing anyway`, "warning");
      } else {
        throw e;
      }
    }

    conn.initialized = true;

    // Handle stderr
    handle.process.stderr?.on("data", (data: Buffer) => {
      const msg = data.toString().trim();
      if (msg) console.error(`[LSP:${name}]`, msg.slice(0, 200));
    });

    // Handle process exit
    handle.process.on("exit", (code) => {
      if (code && code !== 0) {
        ctx.ui.notify(`${name} LSP exited with code ${code}`, "error");
      }
      this.connections.delete(key);
    });

    ctx.ui.notify(`${name} LSP ready`, "success");
    return conn;
  }

  private async initializeConnection(
    connection: MessageConnection,
    handle: LspHandle,
    rootDir: string,
    signal: AbortSignal,
  ): Promise<void> {
    await connection.sendRequest("initialize", {
      rootUri: pathToFileURL(rootDir).href,
      processId: handle.process.pid,
      workspaceFolders: [
        {
          name: "workspace",
          uri: pathToFileURL(rootDir).href,
        },
      ],
      initializationOptions: handle.initialization ?? {},
      capabilities: {
        window: {
          workDoneProgress: true,
        },
        workspace: {
          configuration: true,
          didChangeWatchedFiles: {
            dynamicRegistration: true,
          },
        },
        textDocument: {
          synchronization: {
            didOpen: true,
            didChange: true,
          },
          publishDiagnostics: {
            versionSupport: true,
          },
        },
      },
    });

    await connection.sendNotification("initialized", {});
    if (handle.initialization) {
      await connection.sendNotification("workspace/didChangeConfiguration", {
        settings: handle.initialization,
      });
    }
  }

  /**
   * Touch file with diagnostic subscription BEFORE sending didOpen
   * This is the key fix from opencode to avoid race conditions
   */
  async touchFile(
    conn: LspConnection,
    filePath: string,
    content: string,
    languageId: string,
    waitForDiagnostics: boolean = false,
  ): Promise<Diagnostic[]> {
    const normalizedPath = this.normalizePath(filePath);
    const uri = pathToFileURL(normalizedPath).href;
    const existingVersion = conn.openedFiles.get(normalizedPath);

    // Set up diagnostic listener BEFORE sending notification (opencode pattern)
    let diagnosticsPromise: Promise<Diagnostic[]> | undefined;
    let debounceTimer: ReturnType<typeof setTimeout> | undefined;
    let unsubscribe: (() => void) | undefined;

    if (waitForDiagnostics) {
      diagnosticsPromise = new Promise<Diagnostic[]>((resolve) => {
        let resolved = false;

        const tryResolve = () => {
          if (resolved) return;
          if (debounceTimer) clearTimeout(debounceTimer);
          debounceTimer = setTimeout(() => {
            resolved = true;
            unsubscribe?.();
            resolve(conn.diagnostics.get(normalizedPath) ?? []);
          }, DIAGNOSTICS_DEBOUNCE_MS);
        };

        if (!this.diagnosticCallbacks.has(normalizedPath)) {
          this.diagnosticCallbacks.set(normalizedPath, new Set());
        }
        const callbacks = this.diagnosticCallbacks.get(normalizedPath)!;
        callbacks.add(tryResolve);
        unsubscribe = () => callbacks.delete(tryResolve);

        // Timeout fallback
        setTimeout(() => {
          if (!resolved) {
            resolved = true;
            unsubscribe?.();
            resolve(conn.diagnostics.get(normalizedPath) ?? []);
          }
        }, DIAGNOSTICS_TIMEOUT_MS);
      });
    }

    // Now send the notification
    if (existingVersion !== undefined) {
      conn.diagnostics.delete(normalizedPath);
      const nextVersion = existingVersion + 1;
      conn.openedFiles.set(normalizedPath, nextVersion);

      await conn.connection.sendNotification("workspace/didChangeWatchedFiles", {
        changes: [{ uri, type: 2 }], // Changed
      });

      await conn.connection.sendNotification("textDocument/didChange", {
        textDocument: { uri, version: nextVersion },
        contentChanges: [{ text: content }],
      });
    } else {
      conn.openedFiles.set(normalizedPath, 0);
      conn.diagnostics.delete(normalizedPath);

      await conn.connection.sendNotification("workspace/didChangeWatchedFiles", {
        changes: [{ uri, type: 1 }], // Created
      });

      await conn.connection.sendNotification("textDocument/didOpen", {
        textDocument: { uri, languageId, version: 0, text: content },
      });
    }

    if (diagnosticsPromise) {
      return diagnosticsPromise;
    }
    return [];
  }

  getDiagnostics(conn: LspConnection, filePath: string): Diagnostic[] {
    const normalizedPath = this.normalizePath(filePath);
    return conn.diagnostics.get(normalizedPath) ?? [];
  }

  getAllDiagnostics(filePath: string): { conn: LspConnection; diagnostics: Diagnostic[] }[] {
    const normalizedPath = this.normalizePath(filePath);
    const results: { conn: LspConnection; diagnostics: Diagnostic[] }[] = [];
    for (const conn of this.connections.values()) {
      const diags = conn.diagnostics.get(normalizedPath);
      if (diags && diags.length > 0) {
        results.push({ conn, diagnostics: diags });
      }
    }
    return results;
  }

  async shutdown(conn: LspConnection): Promise<void> {
    try {
      await conn.connection.sendRequest("shutdown", undefined);
      await conn.connection.sendNotification("exit", {});
      conn.connection.end();
      conn.connection.dispose();
    } catch {
      // Ignore shutdown errors
    }
    conn.process.kill();
  }

  async shutdownAll(): Promise<void> {
    const promises = Array.from(this.connections.values()).map((conn) => this.shutdown(conn));
    await Promise.all(promises);
    this.connections.clear();
  }

  killConnection(key: string): boolean {
    const conn = this.connections.get(key);
    if (!conn) return false;

    conn.process.kill("SIGTERM");
    setTimeout(() => {
      if (!conn.process.killed) {
        conn.process.kill("SIGKILL");
      }
    }, 1000);

    this.connections.delete(key);
    return true;
  }

  getStatus(): LspStatus[] {
    return Array.from(this.connections.entries()).map(([key, conn]) => ({
      name: conn.serverName,
      pid: conn.process.pid,
      rootDir: conn.rootDir,
      languages: conn.languages,
      uptime: Date.now() - conn.startedAt,
      lastActivity: Date.now() - conn.lastActivity,
      filesTracked: conn.openedFiles.size,
      initialized: conn.initialized,
    }));
  }

  private normalizePath(filePath: string): string {
    return resolve(filePath);
  }
}

// Helper Functions

function extractFileFromEvent(event: ToolResultEvent): { path: string; isWrite: boolean } | null {
  if (!event.isError && (event.toolName === "write" || event.toolName === "edit")) {
    return { path: event.input.path as string, isWrite: true };
  }
  if (!event.isError && event.toolName === "read") {
    return { path: event.input.path as string, isWrite: false };
  }
  return null;
}

function formatDiagnostics(diagnostics: Diagnostic[]): string {
  const severityLabels = ["", "ERROR", "WARNING", "INFO", "HINT"];

  return diagnostics
    .map((d) => {
      const line = (d.range?.start?.line ?? 0) + 1;
      const col = (d.range?.start?.character ?? 0) + 1;
      const severity = severityLabels[d.severity ?? 0] || "UNKNOWN";
      const code = d.code ? `[${d.code}]` : "";
      // const source = d.source ? `${d.source}` : "";
      return `${severity} [${line}:${col}] ${d.message}`;
    })
    .join("\n");
}

function formatDuration(ms: number): string {
  if (ms < 1000) return `${ms}ms`;
  if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
  return `${(ms / 60000).toFixed(1)}m`;
}

export default function (pi: ExtensionAPI) {
  const manager = new LspConnectionManager();

  // Warm up LSP on read, full diagnostics on write/edit
  pi.on("tool_result", async (event: ToolResultEvent, ctx: ExtensionContext) => {
    const fileInfo = extractFileFromEvent(event);
    if (!fileInfo) return;

    const { path: filePath, isWrite } = fileInfo;
    const absPath = resolve(ctx.cwd, filePath);

    const conns = await manager.getOrCreateConnections(filePath, ctx.cwd, ctx);
    if (conns.length === 0) return;

    let content: string;
    try {
      content = readFileSync(absPath, "utf-8");
    } catch {
      return;
    }

    const ext = extname(filePath);
    const languageId = LANGUAGE_MAP[ext];
    if (!languageId) return;

    // For read operations: warm up and fetch existing diagnostics if available
    if (!isWrite) {
      await Promise.all(
        conns.map((conn) => manager.touchFile(conn, absPath, content, languageId, false)),
      );
      const allDiags = manager.getAllDiagnostics(absPath);
      // if (allDiags.length > 0) {
      //   const combined = allDiags.flatMap((d) => d.diagnostics);
      //   const formatted = formatDiagnostics(combined);
      //   pi.sendUserMessage(`Current diagnostics for \`${filePath}\`:\n${formatted}`, {
      //     deliverAs: "steer",
      //   });
      // }
      return;
    }
    // For write operations: use opencode pattern - subscribe BEFORE sending
    const diagnostics = (
      await Promise.all(
        conns.map((conn) => manager.touchFile(conn, absPath, content, languageId, true)),
      )
    ).flat();

    // Show results
    if (diagnostics.length > 0) {
      const formatted = formatDiagnostics(diagnostics);
      pi.sendUserMessage(`Diagnostics for \`${filePath}\`:\n${formatted}`, {
        deliverAs: "steer",
      });
    } else {
      ctx.ui.notify(`✓ ${filePath}: clean`, "success");
    }
  });

  // Cleanup on shutdown
  pi.on("session_shutdown", async () => {
    await manager.shutdownAll();
  });

  // /lsp command - dashboard
  pi.registerCommand("lsp", {
    description:
      "LSP status dashboard - show running servers, available LSPs, and manage processes",
    getArgumentCompletions: (prefix: string) => {
      const actions = ["status", "available", "kill", "killall"];
      const filtered = actions.filter((a) => a.startsWith(prefix));
      return filtered.length > 0 ? filtered.map((a) => ({ value: a, label: a })) : null;
    },
    handler: async (args: string, ctx) => {
      const parts = args.trim().split(/\s+/);
      const action = parts[0] || "status";
      const serverKey = parts[1];

      switch (action) {
        case "status": {
          const status = manager.getStatus();
          if (status.length === 0) {
            ctx.ui.notify("No LSP servers currently running", "info");
            return;
          }

          const lines = [
            "📊 LSP Server Status",
            "",
            ...status.map((s) => {
              const uptime = formatDuration(s.uptime);
              const statusStr = s.initialized ? "🟢 ready" : "🟡 initializing";
              return `  ${s.name}\n    PID: ${s.pid} | Status: ${statusStr}\n    Root: ${s.rootDir}\n    Languages: ${s.languages.join(", ")}\n    Uptime: ${uptime} | Files: ${s.filesTracked}`;
            }),
            "",
            "Use `/lsp kill <server>` to kill a specific server",
            "Use `/lsp killall` to kill all servers",
          ];

          ctx.ui.notify(lines.join("\n"), "info");
          break;
        }

        case "available": {
          const lines = [
            "🔧 Available LSP Servers",
            "",
            "Configured servers:",
            ...LSP_SERVERS.map((s) => `  ${s.id} - ${s.extensions.join(", ")}`),
          ];

          ctx.ui.notify(lines.join("\n"), "info");
          break;
        }

        case "kill": {
          if (!serverKey) {
            const status = manager.getStatus();
            if (status.length === 0) {
              ctx.ui.notify("No servers running", "info");
              return;
            }

            const keys = status.map((s) => `${s.name}:${s.rootDir}`);
            ctx.ui.notify("Usage: /lsp kill <server-key>\n\nAvailable servers:", "error");
            ctx.ui.notify(keys.join("\n"), "info");
            return;
          }

          const killed = manager.killConnection(serverKey);
          if (killed) {
            ctx.ui.notify(`Killed LSP server: ${serverKey}`, "success");
          } else {
            ctx.ui.notify(`Server not found: ${serverKey}`, "error");
          }
          break;
        }

        case "killall": {
          const status = manager.getStatus();
          await manager.shutdownAll();
          ctx.ui.notify(
            `Killed ${status.length} LSP server${status.length > 1 ? "s" : ""}`,
            "success",
          );
          break;
        }
      }
    },
  });
}


================================================
FILE: agents/pi/extensions/lsp/lsp-config.ts
================================================
/**
 * LSP Server Configurations
 *
 * Each server defines:
 * - id: Unique identifier
 * - extensions: File extensions this server handles
 * - root: Function to find project root directory
 * - spawn: Function to start the LSP server process
 */

import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process";
import { access, constants } from "node:fs/promises";
import { resolve, dirname } from "node:path";
import { homedir } from "node:os";

// Mason bin path (Neovim plugin manager)
const MASON_BIN_PATH = resolve(homedir(), ".local/share/nvim/mason/bin");

export interface LspHandle {
  process: ChildProcessWithoutNullStreams;
  initialization?: Record<string, unknown>;
}

export type RootFunction = (file: string, cwd: string) => Promise<string | undefined>;

export interface LspServerInfo {
  id: string;
  extensions: string[];
  root: RootFunction;
  spawn(root: string, cwd: string): Promise<LspHandle | undefined>;
}

// Language ID mapping for LSP
export const LANGUAGE_MAP: Record<string, string> = {
  ".ts": "typescript",
  ".tsx": "typescriptreact",
  ".js": "javascript",
  ".jsx": "javascriptreact",
  ".mjs": "javascript",
  ".cjs": "javascript",
  ".mts": "typescript",
  ".cts": "typescript",
  ".lua": "lua",
  ".py": "python",
  ".pyi": "python",
  ".rs": "rust",
  ".php": "php",
  ".svelte": "svelte",
  ".astro": "astro",
  ".vue": "vue",
  ".css": "css",
  ".scss": "scss",
  ".less": "less",
  ".html": "html",
  ".json": "json",
  ".jsonc": "json",
  ".yaml": "yaml",
  ".yml": "yaml",
  ".md": "markdown",
  ".typ": "typst",
  ".typc": "typst",
  ".go": "go",
  ".zig": "zig",
  ".zon": "zig",
  ".c": "c",
  ".cpp": "cpp",
  ".cc": "cpp",
  ".cxx": "cpp",
  ".c++": "cpp",
  ".h": "c",
  ".hpp": "cpp",
  ".hh": "cpp",
  ".hxx": "cpp",
  ".h++": "cpp",
  ".ex": "elixir",
  ".exs": "elixir",
  ".cs": "csharp",
  ".fs": "fsharp",
  ".fsi": "fsharp",
  ".fsx": "fsharp",
  ".fsscript": "fsharp",
  ".swift": "swift",
  ".kt": "kotlin",
  ".kts": "kotlin",
  ".java": "java",
  ".rb": "ruby",
  ".rake": "ruby",
  ".dart": "dart",
  ".ml": "ocaml",
  ".mli": "ocaml",
  ".sh": "shellscript",
  ".bash": "shellscript",
  ".zsh": "shellscript",
  ".ksh": "shellscript",
  ".nix": "nix",
  ".gleam": "gleam",
  ".clj": "clojure",
  ".cljs": "clojure",
  ".cljc": "clojure",
  ".edn": "clojure",
  ".hs": "haskell",
  ".lhs": "haskell",
  ".jl": "julia",
  ".tf": "terraform",
  ".tfvars": "terraform",
  ".tex": "latex",
  ".bib": "latex",
  ".prisma": "prisma",
};

/**
 * Check if a path exists (async)
 */
async function pathExists(path: string): Promise<boolean> {
  try {
    await access(path, constants.F_OK);
    return true;
  } catch {
    return false;
  }
}

/**
 * Find binary in PATH, checking Mason bin first
 */
export async function which(bin: string): Promise<string | undefined> {
  // 1. Check Mason bin first (Neovim LSP servers)
  const masonPath = resolve(MASON_BIN_PATH, bin);
  if (await pathExists(masonPath)) return masonPath;

  // 2. Check PATH
  const pathEnv = process.env.PATH || "";
  for (const dir of pathEnv.split(":")) {
    if (!dir) continue;
    const fullPath = resolve(dir, bin);
    if (await pathExists(fullPath)) return fullPath;
  }

  return undefined;
}

/**
 * Helper to find nearest file upward in directory tree
 */
export function nearestRoot(includePatterns: string[], excludePatterns?: string[]): RootFunction {
  return async (file: string, cwd: string) => {
    let current = dirname(file);
    const stopAt = cwd;

    // Check for exclusions first
    if (excludePatterns) {
      while (current !== "/" && current !== dirname(current)) {
        for (const pattern of excludePatterns) {
          if (await pathExists(resolve(current, pattern))) {
            return undefined;
          }
        }
        if (current === stopAt) break;
        current = dirname(current);
      }
    }

    // Reset and check for inclusions
    current = dirname(file);
    while (current !== "/" && current !== dirname(current)) {
      for (const pattern of includePatterns) {
        if (await pathExists(resolve(current, pattern))) {
          return current;
        }
      }
      if (current === stopAt) break;
      current = dirname(current);
    }
    return undefined;
  };
}

/**
 * Create a simple spawn handle
 */
function createHandle(
  bin: string,
  args: string[],
  root: string,
  initialization?: Record<string, unknown>,
): LspHandle | undefined {
  const proc = spawn(bin, args, { cwd: root }) as ChildProcessWithoutNullStreams;
  return { process: proc, initialization };
}

// ============================================================================
// LSP Server Definitions
// ============================================================================

export const LSP_SERVERS: LspServerInfo[] = [
  // TypeScript/JavaScript
  {
    id: "typescript",
    extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
    root: nearestRoot(
      [
        "package-lock.json",
        "bun.lockb",
        "bun.lock",
        "pnpm-lock.yaml",
        "yarn.lock",
        "package.json",
        "tsconfig.json",
      ],
      ["deno.json", "deno.jsonc"],
    ),
    async spawn(root, cwd) {
      // Try to find local tsserver first
      let tsserver: string | undefined;
      const possiblePaths = [
        resolve(cwd, "node_modules", "typescript", "lib", "tsserver.js"),
        resolve(root, "node_modules", "typescript", "lib", "tsserver.js"),
      ];
      for (const p of possiblePaths) {
        if (await pathExists(p)) {
          tsserver = p;
          break;
        }
      }

      const bin = await which("typescript-language-server");
      if (!bin) return undefined;

      return createHandle(
        bin,
        ["--stdio"],
        root,
        tsserver ? { tsserver: { path: tsserver } } : undefined,
      );
    },
  },

  // Deno
  {
    id: "deno",
    extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"],
    root: nearestRoot(
      ["deno.json", "deno.jsonc"],
      [
        "package-lock.json",
        "bun.lockb",
        "bun.lock",
        "pnpm-lock.yaml",
        "yarn.lock",
        "package.json",
        "tsconfig.json",
      ],
    ),
    async spawn(root) {
      const bin = await which("deno");
      if (!bin) return undefined;
      return createHandle(bin, ["lsp"], root);
    },
  },

  // Oxlint
  {
    id: "oxlint",
    extensions: [
      ".ts",
      ".tsx",
      ".js",
      ".jsx",
      ".mjs",
      ".cjs",
      ".mts",
      ".cts",
      ".json",
      ".jsonc",
      ".vue",
      ".astro",
      ".svelte",
      ".css",
    ],
    root: nearestRoot([
      ".oxlintrc.json",
      "package-lock.json",
      "bun.lockb",
      "bun.lock",
      "pnpm-lock.yaml",
      "yarn.lock",
      "package.json",
    ]),
    async spawn(root) {
      // Try local oxlint first
      let bin = resolve(root, "node_modules", ".bin", "oxlint");
      if (!(await pathExists(bin))) {
        bin = (await which("oxlint")) || "";
      }

      if (!bin || !(await pathExists(bin))) {
        // Try bun x oxlint
        const bunBin = (await which("bun")) || "bun";
        const proc = spawn(bunBin, ["x", "oxlint", "--lsp"], {
          cwd: root,
        }) as ChildProcessWithoutNullStreams;
        return { process: proc };
      }

      return createHandle(bin, ["--lsp"], root);
    },
  },

  // Rust
  {
    id: "rust",
    extensions: [".rs"],
    root: nearestRoot(["Cargo.toml", "Cargo.lock"]),
    async spawn(root) {
      const bin = await which("rust-analyzer");
      if (!bin) return undefined;
      return createHandle(bin, [], root);
    },
  },

  // Go
  {
    id: "gopls",
    extensions: [".go"],
    root: nearestRoot(["go.work", "go.mod", "go.sum"]),
    async spawn(root) {
      const bin = await which("gopls");
      if (!bin) return undefined;
      return createHandle(bin, [], root);
    },
  },

  // Python (Pyright)
  {
    id: "pyright",
    extensions: [".py", ".pyi"],
    root: nearestRoot([
      "pyproject.toml",
      "setup.py",
      "setup.cfg",
      "requirements.txt",
      "Pipfile",
      "pyrightconfig.json",
    ]),
    async spawn(root) {
      let bin = await which("pyright-langserver");

      if (!bin) {
        // Try bun x
        const bunBin = (await which("bun")) || "bun";
        const proc = spawn(bunBin, ["x", "pyright", "--stdio"], {
          cwd: root,
        }) as ChildProcessWithoutNullStreams;
        return { process: proc };
      }

      const initialization: Record<string, string> = {};
      // Check for virtual env
      const venvPaths = [
        process.env.VIRTUAL_ENV,
        resolve(root, ".venv"),
        resolve(root, "venv"),
      ].filter(Boolean) as string[];

      for (const venvPath of venvPaths) {
        const pythonPath =
          process.platform === "win32"
            ? resolve(venvPath, "Scripts", "python.exe")
            : resolve(venvPath, "bin", "python");
        if (await pathExists(pythonPath)) {
          initialization.pythonPath = pythonPath;
          break;
        }
      }

      return createHandle(bin, ["--stdio"], root, initialization);
    },
  },

  // Lua
  {
    id: "lua",
    extensions: [".lua"],
    root: nearestRoot([
      ".luarc.json",
      ".luarc.jsonc",
      ".luacheckrc",
      ".stylua.toml",
      "stylua.toml",
      ".git",
    ]),
    async spawn(root) {
      const bin = await which("lua-language-server");
      if (!bin) return undefined;
      return createHandle(bin, [], root, { Lua: { diagnostics: { globals: ["vim"] } } });
    },
  },

  // PHP
  {
    id: "intelephense",
    extensions: [".php"],
    root: nearestRoot(["composer.json", "composer.lock", ".php-version"]),
    async spawn(root) {
      const bin = await which("intelephense");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root, { telemetry: { enabled: false } });
    },
  },

  // Svelte
  {
    id: "svelte",
    extensions: [".svelte"],
    root: nearestRoot([
      "package-lock.json",
      "bun.lockb",
      "bun.lock",
      "pnpm-lock.yaml",
      "yarn.lock",
      "package.json",
    ]),
    async spawn(root) {
      const bin = await which("svelteserver");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root);
    },
  },

  // Vue
  {
    id: "vue",
    extensions: [".vue"],
    root: nearestRoot([
      "package-lock.json",
      "bun.lockb",
      "bun.lock",
      "pnpm-lock.yaml",
      "yarn.lock",
      "package.json",
    ]),
    async spawn(root) {
      const bin = await which("vue-language-server");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root);
    },
  },

  // Astro
  {
    id: "astro",
    extensions: [".astro"],
    root: nearestRoot([
      "package-lock.json",
      "bun.lockb",
      "bun.lock",
      "pnpm-lock.yaml",
      "yarn.lock",
      "package.json",
    ]),
    async spawn(root, cwd) {
      const bin = await which("astro-ls");
      if (!bin) return undefined;

      // Find typescript for astro
      let tsdk: string | undefined;
      const possiblePaths = [
        resolve(cwd, "node_modules", "typescript", "lib"),
        resolve(root, "node_modules", "typescript", "lib"),
      ];
      for (const p of possiblePaths) {
        if (await pathExists(p)) {
          tsdk = p;
          break;
        }
      }

      return createHandle(bin, ["--stdio"], root, tsdk ? { typescript: { tsdk } } : undefined);
    },
  },

  // Zig
  {
    id: "zls",
    extensions: [".zig", ".zon"],
    root: nearestRoot(["build.zig", "build.zig.zon"]),
    async spawn(root) {
      const bin = await which("zls");
      if (!bin) return undefined;
      return createHandle(bin, [], root);
    },
  },

  // C/C++
  {
    id: "clangd",
    extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"],
    root: nearestRoot([
      "compile_commands.json",
      "compile_flags.txt",
      ".clangd",
      "CMakeLists.txt",
      "Makefile",
    ]),
    async spawn(root) {
      const bin = await which("clangd");
      if (!bin) return undefined;
      return createHandle(bin, ["--background-index", "--clang-tidy"], root);
    },
  },

  // C#
  {
    id: "csharp",
    extensions: [".cs"],
    root: nearestRoot([".slnx", ".sln", ".csproj", "global.json"]),
    async spawn(root) {
      const bin = (await which("csharp-ls")) || (await which("omnisharp"));
      if (!bin) return undefined;
      return createHandle(bin, ["-lsp"], root);
    },
  },

  // Swift
  {
    id: "sourcekit-lsp",
    extensions: [".swift"],
    root: nearestRoot(["Package.swift", "*.xcodeproj", "*.xcworkspace"]),
    async spawn(root) {
      const bin = await which("sourcekit-lsp");
      if (!bin) return undefined;
      return createHandle(bin, [], root);
    },
  },

  // Elixir
  {
    id: "elixir-ls",
    extensions: [".ex", ".exs"],
    root: nearestRoot(["mix.exs", "mix.lock"]),
    async spawn(root) {
      const bin = (await which("elixir-ls")) || (await which("language_server.sh"));
      if (!bin) return undefined;
      return createHandle(bin, [], root);
    },
  },

  // Kotlin
  {
    id: "kotlin-ls",
    extensions: [".kt", ".kts"],
    root: nearestRoot([
      "settings.gradle.kts",
      "settings.gradle",
      "build.gradle.kts",
      "build.gradle",
      "pom.xml",
    ]),
    async spawn(root) {
      const bin = await which("kotlin-lsp");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root);
    },
  },

  // Dart
  {
    id: "dart",
    extensions: [".dart"],
    root: nearestRoot(["pubspec.yaml", "analysis_options.yaml"]),
    async spawn(root) {
      const bin = await which("dart");
      if (!bin) return undefined;
      return createHandle(bin, ["language-server", "--lsp"], root);
    },
  },

  // OCaml
  {
    id: "ocaml-lsp",
    extensions: [".ml", ".mli"],
    root: nearestRoot(["dune-project", "dune-workspace", ".merlin", "opam"]),
    async spawn(root) {
      const bin = await which("ocamllsp");
      if (!bin) return undefined;
      return createHandle(bin, [], root);
    },
  },

  // Bash
  {
    id: "bash",
    extensions: [".sh", ".bash", ".zsh", ".ksh"],
    root: () => undefined, // Will use cwd
    async spawn(root) {
      const bin = await which("bash-language-server");
      if (!bin) return undefined;
      return createHandle(bin, ["start"], root);
    },
  },

  // Nix
  {
    id: "nixd",
    extensions: [".nix"],
    root: nearestRoot(["flake.nix", "flake.lock", ".git"]),
    async spawn(root) {
      const bin = await which("nixd");
      if (!bin) return undefined;
      return createHandle(bin, [], root);
    },
  },

  // YAML
  {
    id: "yaml",
    extensions: [".yaml", ".yml"],
    root: nearestRoot(["package.json"]),
    async spawn(root) {
      const bin = await which("yaml-language-server");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root);
    },
  },

  // JSON
  {
    id: "json",
    extensions: [".json", ".jsonc"],
    root: nearestRoot(["package.json"]),
    async spawn(root) {
      const bin = await which("vscode-json-language-server");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root);
    },
  },

  // HTML
  {
    id: "html",
    extensions: [".html"],
    root: nearestRoot(["package.json"]),
    async spawn(root) {
      const bin = await which("vscode-html-language-server");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root);
    },
  },

  // CSS
  {
    id: "css",
    extensions: [".css", ".scss", ".less"],
    root: nearestRoot(["package.json"]),
    async spawn(root) {
      const bin = await which("vscode-css-language-server");
      if (!bin) return undefined;
      return createHandle(bin, ["--stdio"], root);
    },
  },

  // Typst
  {
    id: "tinymist",
    extensions: [".typ", ".typc"],
    root: nearestRoot(["typst.toml"]),
    async spawn(root) {
      const bin = await which("tinymist");
      if (!bin) return undefined;
      return createHandle(bin, ["lsp"], root);
    },
  },

  // Terraform
  {
    id: "terraform",
    extensions: [".tf", ".tfvars"],
    root: nearestRoot([".terraform.lock.hcl", "terraform.tfstate", "*.tf"]),
    async spawn(root) {
      const bin = await which("terraform-ls");
      if (!bin) return undefined;
      return createHandle(bin, ["serve"], root);
    },
  },

  // Gleam
  {
    id: "gleam",
    extensions: [".gleam"],
    root: nearestRoot(["gleam.toml", "manifest.toml"]),
    async spawn(root) {
      const bin = await which("gleam");
      if (!bin) return undefined;
      return createHandle(bin, ["lsp"], root);
    },
  },

  // Clojure
  {
    id: "clojure-lsp",
    extensions: [".clj", ".cljs", ".cljc", ".edn"],
    root: nearestRoot(["deps.edn", "project.clj", "shadow-cljs.edn", "bb.edn", "build.boot"]),
    async spawn(root) {
      const bin = await which("clojure-lsp");
      if (!bin) return undefined;
      return createHandle(bin, ["listen"], root);
    },
  },

  // Haskell
  {
    id: "haskell-language-server",
    extensions: [".hs", ".lhs"],
    root: nearestRoot(["stack.yaml", "cabal.project", "hie.yaml", "*.cabal"]),
    async spawn(root) {
      const bin = await which("haskell-language-server-wrapper");
      if (!bin) return undefined;
      return createHandle(bin, ["--lsp"], root);
    },
  },

  // Julia
  {
    id: "julials",
    extensions: [".jl"],
    root: nearestRoot(["Project.toml", "Manifest.toml"]),
    async spawn(root) {
      const bin = await which("julia");
      if (!bin) return undefined;
      const proc = spawn(
        bin,
        ["--startup-file=no", "--history-file=no", "-e", "using LanguageServer; runserver()"],
        { cwd: root },
      ) as ChildProcessWithoutNullStreams;
      return { process: proc };
    },
  },

  // Prisma
  {
    id: "prisma",
    extensions: [".prisma"],
    root: nearestRoot(["schema.prisma", "prisma/schema.prisma"]),
    async spawn(root) {
      const bin = await which("prisma");
      if (!bin) return undefined;
      return createHandle(bin, ["language-server"], root);
    },
  },
];


================================================
FILE: agents/pi/extensions/notify.ts
================================================
/**
 * Pi Notify Extension
 *
 * Sends a native terminal notification when Pi agent is done and waiting for input.
 * Supports multiple terminal protocols:
 * - OSC 777: Ghostty, iTerm2, WezTerm, rxvt-unicode
 * - OSC 99: Kitty
 * - Windows toast: Windows Terminal (WSL)
 */

import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";

function windowsToastScript(title: string, body: string): string {
	const type = "Windows.UI.Notifications";
	const mgr = `[${type}.ToastNotificationManager, ${type}, ContentType = WindowsRuntime]`;
	const template = `[${type}.ToastTemplateType]::ToastText01`;
	const toast = `[${type}.ToastNotification]::new($xml)`;
	return [
		`${mgr} > $null`,
		`$xml = [${type}.ToastNotificationManager]::GetTemplateContent(${template})`,
		`$xml.GetElementsByTagName('text')[0].AppendChild($xml.CreateTextNode('${body}')) > $null`,
		`[${type}.ToastNotificationManager]::CreateToastNotifier('${title}').Show(${toast})`,
	].join("; ");
}

function notifyOSC777(title: string, body: string): void {
	process.stdout.write(`\x1b]777;notify;${title};${body}\x07`);
}

function notifyOSC99(title: string, body: string): void {
	// Kitty OSC 99: i=notification id, d=0 means not done yet, p=body for second part
	process.stdout.write(`\x1b]99;i=1:d=0;${title}\x1b\\`);
	process.stdout.write(`\x1b]99;i=1:p=body;${body}\x1b\\`);
}

function notifyWindows(title: string, body: string): void {
	const { execFile } = require("child_process");
	execFile("powershell.exe", ["-NoProfile", "-Command", windowsToastScript(title, body)]);
}

function notify(title: string, body: string): void {
	if (process.env.WT_SESSION) {
		notifyWindows(title, body);
	} else if (process.env.KITTY_WINDOW_ID) {
		notifyOSC99(title, body);
	} else {
		notifyOSC777(title, body);
	}
}

export default function (pi: ExtensionAPI) {
	pi.on("agent_end", async () => {
		notify("Pi", "Ready for input!");
	});
}


================================================
FILE: agents/pi/extensions/pi-codemode/README.md
================================================
# pi-codemode

Executor plugins for codemode plus curated npm/jj commands and whitelisted bash.

## Tools
- `pi.*` builtins (filesystem, bash, webfetch)
- `fff.*` search tools
- `npm.run` run npm scripts
- `npm.install` install packages via lockfile-aware package manager selection
- `jj.status` / `jj.diff` / `jj.log` / `jj.new` / `jj.describe` / `jj.commit` for jj

## Bash whitelist
- Package managers: `npm`, `pnpm`, `bun`, `yarn`, `npx`, `node`
- File operations: `mkdir`, `touch`, `cp`, `mv`, `rm`, `ln`, `chmod`, `chown`
- Utilities: `pwd`, `echo`, `which`, `uname`, `date`, `sleep`
- Everything else is blocked with guidance to use the equivalent `tools.pi.*` tool

## Rules
- no full bash access — whitelisted package managers only
- use JS sandbox + named tools instead
- repo.install picks pnpm if pnpm-lock.yaml exists, bun if bun.lock/bun.lockb exists, else npm

================================================
FILE: agents/pi/extensions/pi-codemode/executor.jsonc
================================================
{
  "sources": [
    {
      "kind": "mcp",
      "transport": "remote",
      "name": "mcp-typescript server on vercel",
      "endpoint": "https://mcp.exa.ai/mcp",
      "remoteTransport": "auto",
      "namespace": "mcp_typescript_server_on_vercel"
    }
  ]
}


================================================
FILE: agents/pi/extensions/pi-codemode/index.ts
================================================
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { createCodemodeTool } from "./src/codemode.js";
import { disposeAllExecutors, getExecutor } from "./src/executor-cache.js";
import { acquireSandbox, disposeAll as disposeAllSandboxes } from "./src/sandbox-cache.js";
import { initFinder } from "./src/fff.js";

export default function registerCodemode(pi: ExtensionAPI) {
  pi.registerTool(createCodemodeTool());

  const activate = () => pi.setActiveTools(["codemode"]);

  // Pre-warm sandbox, finder, and executor on session start
  pi.on("session_start", async (event, ctx) => {
    if (event.reason === "startup" || event.reason === "reload" || event.reason === "new") {
      await acquireSandbox(ctx.cwd);           // creates & caches sandbox
      initFinder(ctx.cwd).catch(() => {});     // fire-and-forget fff scan
      getExecutor(ctx.cwd).catch(() => {});    // fire-and-forget executor creation
    }
    activate();
  });

  pi.on("before_agent_start", async () => {
    activate();
    return undefined;
  });

  pi.on("session_shutdown", async () => {
    await Promise.allSettled([
      disposeAllExecutors(),
      disposeAllSandboxes(),
    ]);
  });
}


================================================
FILE: agents/pi/extensions/pi-codemode/package.json
================================================
{
  "name": "pi-codemode",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "description": "pi codemode extension with executor SDK and secure-exec sandbox",
  "keywords": [
    "pi-package"
  ],
  "peerDependencies": {
    "@mariozechner/pi-ai": "*",
    "@mariozechner/pi-agent-core": "*",
    "@mariozechner/pi-coding-agent": "*",
    "@mariozechner/pi-tui": "*",
    "@sinclair/typebox": "*"
  },
  "dependencies": {
    "@executor-js/plugin-graphql": "^0.0.1-beta.2",
    "@executor-js/plugin-mcp": "^0.0.1-beta.2",
    "@executor-js/plugin-openapi": "^0.0.1-beta.2",
    "@executor-js/sdk": "^0.0.1-beta.2",
    "@ff-labs/fff-node": "^0.5.2",
    "jsonc-parser": "^3.3.1",
    "secure-exec": "^0.2.1",
    "turndown": "^7.2.4"
  },
  "devDependencies": {},
  "pi": {
    "extensions": [
      "./index.ts"
    ]
  },
  "packageManager": "bun@1.3.12"
}

================================================
FILE: agents/pi/extensions/pi-codemode/src/builtins.ts
================================================
import {
  createBashTool,
  createEditTool,
  createFindTool,
  createGrepTool,
  createLsTool,
  createReadTool,
  createWriteTool,
} from "@mariozechner/pi-coding-agent";
import { createCustomReadTool } from "./read.js";
import { webfetch } from "./webfetch.js";
import type { BuiltinToolName } from "./types.js";
import { Type } from "@sinclair/typebox";

export type BuiltinTool = {
  name: string;
  description: string;
  parameters: unknown;
  execute: (...args: any[]) => Promise<unknown>;
};

// Only package managers — everything else has a codemode tool equivalent
const BASH_COMMAND_WHITELIST = new Set([
  // Package managers
  "vp",
  "vpx",
  "npm",
  "pnpm",
  "bun",
  "yarn",
  "npx",
  // File operations (no codemode tool equivalent)
  "mkdir",
  "touch",
  "cp",
  "mv",
  // Utilities
  "pwd",
  "which",
  "type",
  "uname",
]);

const WHITELIST_HELP = () => [
  `Allowed commands: ${[...BASH_COMMAND_WHITELIST].sort().join(", ")}`,
  "Use tools.pi.* for reading, writing, searching, grepping, editing files.",
].join("\n");

function extractCommandName(command: string): string | null {
  // Strip shell redirects, pipes, chaining, then grab first word
  const cleaned = command
    .replace(/\\s*[|&;<>]/g, " ")
    .replace(/\(/g, " ")
    .trim();
  const first = cleaned.split(/\s+/)[0];
  if (!first) return null;
  // Strip leading path (e.g., ./node_modules/.bin/npm) — not whitelisted
  if (first.includes("/")) return null;
  return first;
}

function createWhitelistedBashTool(cwd: string): BuiltinTool {
  const bashTool = createBashTool(cwd) as BuiltinTool;

  return {
    name: bashTool.name,
    description:
      "Run package manager commands (npm, pnpm, bun, yarn, npx, node). Other commands are blocked — use tools.pi.* instead.",
    parameters: bashTool.parameters,
    async execute(toolCallId: string, args: any, signal: AbortSignal | undefined, onUpdate: any) {
      const command = String(args?.command ?? "").trim();
      if (!command) {
        return {
          content: [{ type: "text", text: "No command provided.\n\n" + WHITELIST_HELP() }],
        };
      }

      const cmdName = extractCommandName(command);

      if (!cmdName || !BASH_COMMAND_WHITELIST.has(cmdName)) {
        const blocked = cmdName ? `"${cmdName}" is not whitelisted` : "Could not parse command";
        return {
          content: [
            {
              type: "text",
              text: [`Error: ${blocked}`, "", WHITELIST_HELP()].join("\n"),
            },
          ],
        };
      }

      // Proxy: forward execute via original tool's execute
      const result = await bashTool.execute(toolCallId, args, signal, onUpdate);
      return result;
    },
  };
}

const webfetchTool: BuiltinTool = {
  name: "webfetch",
  description:
    "Fetch web content and convert to markdown, text, or html. Use when URLs are mentioned to retrieve content. HTTP URLs upgraded to HTTPS. Images and binary content return empty text.",
  parameters: Type.Object({
    url: Type.String({ description: "The URL to fetch content from" }),
    format: Type.Optional(
      Type.Union([Type.Literal("markdown"), Type.Literal("text"), Type.Literal("html")], {
        description: "Output format: markdown (default), text, or html",
      }),
    ),
    timeout: Type.Optional(
      Type.Number({ description: "Timeout in seconds (max 120, default 30)" }),
    ),
  }),
  execute: webfetch,
};

export type BuiltinToolset = Record<BuiltinToolName, BuiltinTool>;

const PI_SIGNATURES = [
  "tools.pi.read({ path, offset?, limit? })",
  "tools.pi.bash({ command, timeout? })",
  "tools.pi.edit({ path, edits: [{ oldText, newText }] })",
  "tools.pi.write({ path, content })",
  "tools.pi.grep({ pattern, path?, glob?, ignoreCase?, literal?, context?, limit? })",
  "tools.pi.find({ pattern, path?, limit? })",
  "tools.pi.ls({ path?, limit? })",
  "tools.pi.webfetch({ url, format?, timeout? })",
];

const FFF_SIGNATURES = [
  "tools.fff.grep({ pattern, path?, mode?, smartCase?, glob?, maxMatchesPerFile?, context?, classifyDefinitions?, limit? })",
  "tools.fff.fileSearch({ query, path?, limit? })",
  "tools.fff.multiGrep({ patterns, path?, limit? })",
  "tools.fff.recentFiles({ path?, limit?, minFrecencyScore?, includeUntracked? })",
  "tools.fff.searchThenGrep({ pathQuery, contentQuery, path?, maxFiles?, limit? })",
];

const META_APIS = ["tools.list()", "tools.schema(name)", "tools.definitions()"];

export function createBuiltinToolset(cwd: string) {
  return {
    read: createCustomReadTool(cwd) as BuiltinTool,
    edit: createEditTool(cwd) as BuiltinTool,
    write: createWriteTool(cwd) as BuiltinTool,
    grep: createGrepTool(cwd) as BuiltinTool,
    find: createFindTool(cwd) as BuiltinTool,
    ls: createLsTool(cwd) as BuiltinTool,
    bash: createWhitelistedBashTool(cwd) as BuiltinTool,
    webfetch: webfetchTool,
  };
}

export function buildCodemodeApiPrompt(): string {
  return [
    "## Available APIs",
    "",
    "### pi tools",
    ...PI_SIGNATURES,
    "",
    "### fff tools",
    ...FFF_SIGNATURES,
    "",
    "### Discovery",
    ...META_APIS,
    "",
    "All pi and fff tools return plain text strings. Other tools (MCP, OpenAPI, GraphQL) return objects.",
    "If the user mentions an unknown tool, call tools.list() to get a list of available tools",
    "Before using any unfamiliar tool, call tools.schema('tool.name') to get its exact parameter and return types.",
    "Dynamically loaded tools are namespaced: tools.openapi.petstore.listPets, tools.mcp.myServer.search.",
    "Prefer one codemode call; batch work with JS and Promise.all.",
    "",
    "### Bash restrictions",
    `tools.pi.bash only allows: ${[...BASH_COMMAND_WHITELIST].sort().join(", ")}.`,
    "Everything else is blocked — use the dedicated tools above instead.",
  ].join("\n");
}


================================================
FILE: agents/pi/extensions/pi-codemode/src/codemode.ts
================================================
import { Type } from "@sinclair/typebox";
import { Text } from "@mariozechner/pi-tui";
import type { ExtensionContext, Theme, ToolDefinition } from "@mariozechner/pi-coding-agent";
import { buildCodemodeApiPrompt } from "./builtins.js";
import { getExecutor } from "./executor-cache.js";
import { renderCodemodeCall, renderCodemodeResult } from "./render.js";
import { runCodemode } from "./runtime.js";
import { formatTraceForAgent, summarizeTraceForContext } from "./trace.js";
import type { CodemodeResultDetails } from "./types.js";
import { buildPromptGuidelines, stripCodeFences } from "./util.js";

const codemodeSchema = Type.Object({
  code: Type.String({ description: "JavaScript code with tools.pi.* access" }),
});

export function createCodemodeTool(): ToolDefinition<typeof codemodeSchema, CodemodeResultDetails> {
  return {
    name: "codemode",
    label: "codemode",
    description: "Execute JavaScript in a secure sandbox with access to pi filesystem tools, fff search tools, and dynamically loaded executor tools (MCP, OpenAPI, GraphQL).",
    promptSnippet: buildCodemodeApiPrompt(),
    promptGuidelines: buildPromptGuidelines(),
    parameters: codemodeSchema,

    async execute(
      _toolCallId: string,
      params: { code: string },
      signal: AbortSignal | undefined,
      _onUpdate: unknown,
      ctx: ExtensionContext,
    ) {
      const code = stripCodeFences(params.code);
      const executor = await getExecutor(ctx.cwd);
      const result = await runCodemode({
        code,
        cwd: ctx.cwd,
        executor,
        signal,
      });
      const { text, images } = formatTraceForAgent(result.trace, result.value, result.logs);

      return {
        content: [
          { type: "text", text },
          ...images.map((img) => ({ type: "image" as const, data: img.data, mimeType: img.mimeType })),
        ],
        details: {
          trace: result.trace,
          value: result.value,
          logs: result.logs,
          summary: summarizeTraceForContext(result.trace),
        },
      };
    },

    renderCall(args: { code?: string }, theme: Theme) {
      return renderCodemodeCall(args.code ?? "", theme);
    },

    renderResult(result, options, theme) {
      const trace = result.details?.trace;
      if (!trace) return new Text(theme.fg("error", "Missing codemode trace"), 0, 0);
      if (options.isPartial) return new Text(theme.fg("warning", "Executing..."), 0, 0);
      return renderCodemodeResult(trace, options.expanded, theme);
    },
  };
}


================================================
FILE: agents/pi/extensions/pi-codemode/src/executor-cache.ts
================================================
import { createExecutor, type Executor } from "@executor-js/sdk";
import { mcpPlugin } from "@executor-js/plugin-mcp";
import { openApiPlugin } from "@executor-js/plugin-openapi";
import { graphqlPlugin } from "@executor-js/plugin-graphql";
import { piPlugin } from "./pi-plugin.js";
import { fffPlugin } from "./fff-plugin.js";
import { getExecutorConfigPath, loadSourcesFromConfig } from "./source-config.js";
import { hydrateExecutorSources } from "./source-hydrate.js";
import { stat } from "node:fs/promises";

type CachedExecutor = {
  executor: Executor;
  mtimeMs: number;
};

const cache = new Map<string, CachedExecutor>();

const configMtime = async (): Promise<number> => {
  try {
    return (await stat(getExecutorConfigPath())).mtimeMs;
  } catch {
    return 0;
  }
};

export const getExecutor = async (cwd: string): Promise<Executor> => {
  const mtimeMs = await configMtime();
  const cached = cache.get(cwd);
  if (cached && cached.mtimeMs === mtimeMs) return cached.executor;

  if (cached) {
    await cached.executor.close();
    cache.delete(cwd);
  }

  const loaded = await loadSourcesFromConfig();

  const executor = await createExecutor({
    scope: { name: "pi-codemode-" + cwd },
    plugins: [
      piPlugin(cwd),
      fffPlugin(cwd),
      mcpPlugin(),
      openApiPlugin(),
      graphqlPlugin(),
    ] as const,
  });

  await hydrateExecutorSources(executor, loaded.sources, {
    configPath: loaded.configPath,
    unsupported: loaded.unsupported,
  });

  cache.set(cwd, { executor, mtimeMs: loaded.mtimeMs });
  return executor;
};

export const disposeExecutor = async (cwd: string): Promise<void> => {
  const cached = cache.get(cwd);
  if (!cached) return;
  await cached.executor.close();
  cache.delete(cwd);
};

export const disposeAllExecutors = async (): Promise<void> => {
  await Promise.allSettled(Array.from(cache.values()).map((entry) => entry.executor.close()));
  cache.clear();
};

================================================
FILE: agents/pi/extensions/pi-codemode/src/fff-plugin.ts
================================================
import {
  definePlugin,
  ToolRegistration,
  ToolId,
  ToolInvocationResult,
  type PluginContext,
} from "@executor-js/sdk";
import { createFffBuiltinToolset, initFinder } from "./fff.js";
import { fffToolNames, type FffToolName } from "./types.js";
import { formatError } from "./util.js";

export const fffPlugin = (cwd: string) =>
  definePlugin({
    key: "fff",
    init: async (ctx: PluginContext) => {
      // Eagerly initialize finder on plugin load
      await initFinder(cwd);

      const tools = createFffBuiltinToolset(cwd);

      // Register fff.* SIMD-accelerated search tools
      await ctx.tools.registerInvoker("fff", {
        invoke: async (toolId: string, args: unknown, _options: unknown) => {
          const name = toolId.split(".").pop() as FffToolName | undefined;
          if (!name || !(name in tools)) {
            return new ToolInvocationResult({ data: null, error: "Unknown fff tool: " + toolId });
          }

          const tool = tools[name];
          try {
            const data = await tool.execute(toolId, args ?? {}, undefined, () => {});
            return new ToolInvocationResult({ data, error: null });
          } catch (cause) {
            return new ToolInvocationResult({ data: null, error: formatError(cause) });
          }
        },
      });

      await ctx.tools.register(
        fffToolNames.map((name) => {
          const tool = tools[name];
          return new ToolRegistration({
            id: ToolId.make("fff." + name),
            pluginKey: "fff",
            sourceId: "pi",
            name,
            description: tool.description,
            inputSchema: tool.parameters as Record<string, unknown>,
          });
        }),
      );

      return { extension: {} };
    },
  });

================================================
FILE: agents/pi/extensions/pi-codemode/src/fff.ts
================================================
import { FileFinder } from "@ff-labs/fff-node";
import { Type } from "@sinclair/typebox";
import { resolve } from "node:path";
import type { BuiltinTool } from "./builtins.js";
import type { FffToolName } from "./types.js";

// Global instance cache
const finderCache = new Map<string, FileFinder>();

async function getFinder(cwd: string, searchPath?: string): Promise<FileFinder> {
  const basePath = resolve(cwd, searchPath || ".");
  if (!finderCache.has(basePath)) {
    const result = FileFinder.create({ basePath });
    if (!result.ok) throw new Error(result.error || "unknown");
    finderCache.set(basePath, result.value);
    result.value.waitForScan(5000).catch(() => console.log("fff scan timeout"));
  }
  return finderCache.get(basePath)!;
}

// Eagerly initialize finder for a path (call on session start)
export async function initFinder(cwd: string, searchPath?: string): Promise<void> {
  await getFinder(cwd, searchPath);
}

export function destroyAllFinders(): void {
  for (const f of finderCache.values()) f.destroy();
  finderCache.clear();
}

// Grep tool
export const grepTool: BuiltinTool = {
  name: "grep",
  description: "Search file contents using fff (SIMD-accelerated). Use as tools.fff.grep()",
  parameters: Type.Object({
    pattern: Type.String(),
    path: Type.Optional(Type.String()),
    mode: Type.Optional(
      Type.Union([Type.Literal("plain"), Type.Literal("regex"), Type.Literal("fuzzy")]),
    ),
    smartCase: Type.Optional(Type.Boolean()),
    glob: Type.Optional(Type.String()),
    maxMatchesPerFile: Type.Optional(Type.Number()),
    context: Type.Optional(Type.Number()),
    classifyDefinitions: Type.Optional(Type.Boolean()),
    limit: Type.Optional(Type.Number()),
  }),
  execute: async (_id: string, args: any, cwd: string) => {
    const finder = await getFinder(cwd, args.path);
    const query = args.glob ? args.glob + " " + args.pattern : args.pattern;
    const res = finder.grep(query, {
      mode: args.mode || "plain",
      maxFileSize: args.maxFileSize || 0,
      maxMatchesPerFile: args.maxMatchesPerFile || 0,
      smartCase: args.smartCase ?? true,
      beforeContext: args.context || 0,
      afterContext: args.context || 0,
      classifyDefinitions: args.classifyDefinitions || false,
    } as any);
    if (!res.ok) throw new Error(res.error);
    const items = args.limit ? res.value.items.slice(0, args.limit) : res.value.items;
    return {
      matches: items.map((m: any) => ({
        path: m.relativePath,
        line: m.lineNumber,
        column: m.col,
        content: m.lineContent,
        matchRanges: m.matchRanges,
        isDefinition: m.isDefinition ?? false,
      })),
      totalMatched: res.value.totalMatched,
      totalFilesSearched: res.value.totalFilesSearched,
      nextCursor: res.value.nextCursor,
    };
  },
};

// File search tool
export const fileSearchTool: BuiltinTool = {
  name: "fileSearch",
  description: "Fuzzy search for files by path. Use as tools.fff.fileSearch()",
  parameters: Type.Object({
    query: Type.String(),
    path: Type.Optional(Type.String()),
    limit: Type.Optional(Type.Number()),
  }),
  execute: async (_id: string, args: any, cwd: string) => {
    const finder = await getFinder(cwd, args.path);
    const res = finder.fileSearch(args.query, { pageSize: args.limit || 20 });
    if (!res.ok) throw new Error(res.error);
    return {
      files: res.value.items.map((item: any) => ({
        path: item.relativePath,
        name: item.fileName,
        gitStatus: item.gitStatus,
        frecencyScore: item.totalFrecencyScore,
      })),
    };
  },
};

// Multi-pattern grep
export const multiGrepTool: BuiltinTool = {
  name: "multiGrep",
  description: "Multi-pattern search (OR logic). Use as tools.fff.multiGrep()",
  parameters: Type.Object({
    patterns: Type.Array(Type.String()),
    path: Type.Optional(Type.String()),
    limit: Type.Optional(Type.Number()),
  }),
  execute: async (_id: string, args: any, cwd: string) => {
    const finder = await getFinder(cwd, args.path);
    const res = finder.multiGrep({
      patterns: args.patterns,
      smartCase: true,
    });
    if (!res.ok) throw new Error(res.error);
    const items = args.limit ? res.value.items.slice(0, args.limit) : res.value.items;
    return {
      matches: items.map((m: any) => ({
        path: m.relativePath,
        line: m.lineNumber,
        content: m.lineContent,
      })),
    };
  },
};

// Recent files
export const recentFilesTool: BuiltinTool = {
  name: "recentFiles",
  description: "Get recently accessed files (frecency). Use as tools.fff.recentFiles()",
  parameters: Type.Object({
    path: Type.Optional(Type.String()),
    limit: Type.Optional(Type.Number()),
    minFrecencyScore: Type.Optional(Type.Number()),
    includeUntracked: Type.Optional(Type.Boolean()),
  }),
  execute: async (_id: string, args: any, cwd: string) => {
    const finder = await getFinder(cwd, args.path);
    const res = finder.fileSearch("", { pageSize: (args.limit || 20) * 2 });
    if (!res.ok) throw new Error(res.error);
    let files = res.value.items.map((item: any, i: number) => ({
      path: item.relativePath,
      name: item.fileName,
      gitStatus: item.gitStatus,
      frecencyScore: res.value.scores[i]?.baseScore || 0,
    }));
    if (args.minFrecencyScore)
      files = files.filter((f: any) => f.frecencyScore >= args.minFrecencyScore);
    if (args.includeUntracked === false) files = files.filter((f: any) => f.gitStatus !== "??");
    if (args.limit) files = files.slice(0, args.limit);
    return { files };
  },
};

// Search then grep
export const searchThenGrepTool: BuiltinTool = {
  name: "searchThenGrep",
  description: "Fuzzy search files then grep within. Use as tools.fff.searchThenGrep()",
  parameters: Type.Object({
    pathQuery: Type.String(),
    contentQuery: Type.String(),
    path: Type.Optional(Type.String()),
    maxFiles: Type.Optional(Type.Number()),
    limit: Type.Optional(Type.Number()),
  }),
  execute: async (_id: string, args: any, cwd: string) => {
    const finder = await getFinder(cwd, args.path);
    const fileRes = finder.fileSearch(args.pathQuery, { pageSize: args.maxFiles || 50 });
    if (!fileRes.ok) throw new Error(fileRes.error);
    if (fileRes.value.items.length === 0) return { matches: [], fileMatches: 0 };
    const paths = fileRes.value.items.map((item: any) => item.relativePath);
    const res = finder.grep(args.contentQuery + " " + paths.join(" "), { mode: "plain" });
    if (!res.ok) throw new Error(res.error);
    const items = args.limit ? res.value.items.slice(0, args.limit) : res.value.items;
    return {
      matches: items.map((m: any) => ({
        path: m.relativePath,
        line: m.lineNumber,
        content: m.lineContent,
      })),
      fileMatches: paths.length,
      totalMatched: res.value.totalMatched,
    };
  },
};

export type FffBuiltinToolset = Record<FffToolName, BuiltinTool>;

export function createFffBuiltinToolset(cwd: string): FffBuiltinToolset {
  const withCwd = (tool: BuiltinTool): BuiltinTool => ({
    ...tool,
    execute: async (_toolCallId: string, args: any, _signal: any, _onUpdate: any) =>
      tool.execute(_toolCallId, args, cwd),
  });

  return {
    grep: withCwd(grepTool),
    fileSearch: withCwd(fileSearchTool),
    multiGrep: withCwd(multiGrepTool),
    recentFiles: withCwd(recentFilesTool),
    searchThenGrep: withCwd(searchThenGrepTool),
  };
}

================================================
FILE: agents/pi/extensions/pi-codemode/src/jj-plugin.ts
================================================
import {
  definePlugin,
  ToolRegistration,
  ToolId,
  ToolInvocationResult,
  type PluginContext,
} from "@executor-js/sdk";
import { spawn } from "node:child_process";
import { formatError } from "./util.js";

const run = async (args: string[], cwd: string, signal?: AbortSignal) =>
  await new Promise((resolve, reject) => {
    const child = spawn("jj", args, { cwd, signal, stdio: ["ignore", "pipe", "pipe"] });
    let stdout = "";
    let stderr = "";
    child.stdout.on("data", (d) => (stdout += d.toString()));
    child.stderr.on("data", (d) => (stderr += d.toString()));
    child.on("error", reject);
    child.on("close", (code) =>
      resolve({ code: code ?? 0, stdout, stderr, command: ["jj", ...args] }),
    );
  });
const summarize = (r: any) =>
  [
    "$ " + r.command.join(" "),
    r.stdout?.trim(),
    r.stderr?.trim() ? "stderr: " + r.stderr.trim() : "",
    "exit " + r.code,
  ]
    .filter(Boolean)
    .join(" ");
const text = (s: string) => [{ type: "text", text: s }];

export const jjPlugin = (cwd: string) =>
  definePlugin({
    key: "jj",
    init: async (ctx: PluginContext) => {
      const tools = {
        status: {
          description: "Show jj status",
          parameters: { type: "object", properties: {}, additionalProperties: false },
          execute: async () => {
            const r = await run(["status"], cwd);
            return { content: text(summarize(r)), details: { result: r } };
          },
        },
        diff: {
          description: "Show jj diff",
          parameters: { type: "object", properties: {}, additionalProperties: false },
          execute: async () => {
            const r = await run(["diff"], cwd);
            return { content: text(summarize(r)), details: { result: r } };
          },
        },
        log: {
          description: "Show jj log",
          parameters: { type: "object", properties: {}, additionalProperties: false },
          execute: async () => {
            const r = await run(["log"], cwd);
            return { content: text(summarize(r)), details: { result: r } };
          },
        },
        new: {
          description: "Create a new jj change",
          parameters: { type: "object", properties: {}, additionalProperties: false },
          execute: async () => {
            const r = await run(["new"], cwd);
            return { content: text(summarize(r)), details: { result: r } };
          },
        },
        describe: {
          description: "Describe the current jj change",
          parameters: {
            type: "object",
            properties: { description: { type: "string" } },
            required: ["description"],
            additionalProperties: false,
          },
          execute: async (_id: string, args: any) => {
            const description = String(args?.description ?? "");
            if (!description) throw new Error("Missing description");
            const r = await run(["describe", "-m", description], cwd);
            return { content: text(summarize(r)), details: { result: r } };
          },
        },
        commit: {
          description: "Commit with jj",
          parameters: {
            type: "object",
            properties: { message: { type: "string" } },
            required: ["message"],
            additionalProperties: false,
          },
          execute: async (_id: string, args: any) => {
            const message = String(args?.message ?? "");
            if (!message) throw new Error("Missing message");
            const r = await run(["commit", "-m", message], cwd);
            return { content: text(summarize(r)), details: { result: r } };
          },
        },
      } as const;
      await ctx.tools.registerInvoker("jj", {
        invoke: async (toolId: string, args: unknown) => {
          const name = toolId.split(".").pop() as keyof typeof tools | undefined;
          if (!name || !(name in tools))
            return new ToolInvocationResult({ data: null, error: "Unknown jj tool: " + toolId });
          try {
            return new ToolInvocationResult({
              data: await tools[name].execute(toolId, args ?? {}),
              error: null,
            });
          } catch (cause) {
            return new ToolInvocationResult({ data: null, error: formatError(cause) });
          }
        },
      });
      await ctx.tools.register(
        Object.entries(tools).map(
          ([name, tool]) =>
            new ToolRegistration({
              id: ToolId.make("jj." + name),
              pluginKey: "jj",
              sourceId: "pi",
              name,
              description: tool.description,
              inputSchema: tool.parameters as Record<string, unknown>,
            }),
        ),
      );
      return { extension: {} };
    },
  });


================================================
FILE: agents/pi/extensions/pi-codemode/src/npm-plugin.ts
================================================
import {
  definePlugin,
  ToolRegistration,
  ToolId,
  ToolInvocationResult,
  type PluginContext,
} from "@executor-js/sdk";
import { spawn } from "node:child_process";
import { promises as fs } from "node:fs";
import { join } from "node:path";
import { formatError } from "./util.js";

const readMaybe = async (path: string) => {
  try {
    return await fs.readFile(path, "utf8");
  } catch {
    return null;
  }
};

const pmCache = new Map<string, { bin: string; args: readonly string[] }>();

const detectPackageManager = async (cwd: string) => {
  const cached = pmCache.get(cwd);
  if (cached) return cached;

  let result: { bin: string; args: readonly string[] };
  if ((await readMaybe(join(cwd, "pnpm-lock.yaml"))) !== null)
    result = { bin: "pnpm", args: ["add"] as const };
  else if ((await readMaybe(join(cwd, "bun.lockb"))) !== null)
    result = { bin: "bun", args: ["add"] as const };
  else if ((await readMaybe(join(cwd, "bun.lock"))) !== null)
    result = { bin: "bun", args: ["add"] as const };
  else if ((await readMaybe(join(cwd, "package-lock.json"))) !== null)
    result = { bin: "npm", args: ["install"] as const };
  else
    result = { bin: "npm", args: ["install"] as const };

  pmCache.set(cwd, result);
  return result;
};

const run = async (cmd: string, args: string[], cwd: string, signal?: AbortSignal) =>
  await new Promise((resolve, reject) => {
    const child = spawn(cmd, args, { cwd, signal, stdio: ["ignore", "pipe", "pipe"] });
    let stdout = "";
    let stderr = "";
    child.stdout.on("data", (d) => (stdout += d.toString()));
    child.stderr.on("data", (d) => (stderr += d.toString()));
    child.on("error", reject);
    child.on("close", (code) =>
      resolve({ code: code ?? 0, stdout, stderr, command: [cmd, ...args] }),
    );
  });

const summarize = (r: any) =>
  [
    "$ " + r.command.join(" "),
    r.stdout?.trim(),
    r.stderr?.trim() ? "stderr: " + r.stderr.trim() : "",
    "exit " + r.code,
  ]
    .filter(Boolean)
    .join(" ");
const text = (s: string) => [{ type: "text", text: s }];

export const npmPlugin = (cwd: string) =>
  definePlugin({
    key: "npm",
    init: async (ctx: PluginContext) => {
      const tools = {
        run: {
          description: "Run npm scripts",
          parameters: {
            type: "object",
            properties: { name: { type: "string" } },
            required: ["name"],
            additionalProperties: false,
          },
          execute: async (_id: string, args: any) => {
            const name = String(args?.name ?? "");
            if (!name) throw new Error("Missing script name");
            const r = await run("npm", ["run", name], cwd);
            return { content: text(summarize(r)), details: { result: r } };
          },
        },
        install: {
          description: "Install packages with lockfile-aware package manager",
          parameters: {
            type: "object",
            properties: { packages: { type: "array", items: { type: "string" } } },
            required: ["packages"],
            additionalProperties: false,
          },
          execute: async (_id: string, args: any) => {
            const packages = Array.isArray(args?.packages)
              ? args.packages.map(String).filter(Boolean)
              : [];
            if (!packages.length) throw new Error("Missing packages");
            const pm = await detectPackageManager(cwd);
            const r = await run(pm.bin, [...pm.args, ...packages], cwd);
            return { content: text(summarize(r)), details: { result: r, packageManager: pm.bin } };
          },
        },
      } as const;
      await ctx.tools.registerInvoker("npm", {
        invoke: async (toolId: string, args: unknown) => {
          const name = toolId.split(".").pop() as keyof typeof tools | undefined;
          if (!name || !(name in tools))
            return new ToolInvocationResult({ data: null, error: "Unknown npm tool: " + toolId });
          try {
            return new ToolInvocationResult({
              data: await tools[name].execute(toolId, args ?? {}),
              error: null,
            });
          } catch (cause) {
            return new ToolInvocationResult({ data: null, error: formatError(cause) });
          }
        },
      });
      await ctx.tools.register(
        Object.entries(tools).map(
          ([name, tool]) =>
            new ToolRegistration({
              id: ToolId.make("npm." + name),
              pluginKey: "npm",
              sourceId: "pi",
              name,
              description: tool.description,
              inputSchema: tool.parameters as Record<string, unknown>,
            }),
        ),
      );
      return { extension: {} };
    },
  });

================================================
FILE: agents/pi/extensions/pi-codemode/src/pi-plugin.ts
================================================
import {
  definePlugin,
  ToolRegistration,
  ToolId,
  ToolInvocationResult,
  type PluginContext,
} from "@executor-js/sdk";
import { createBuiltinToolset } from "./builtins.js";
import { builtinToolNames, type BuiltinToolName } from "./types.js";
import { formatError } from "./util.js";

export const piPlugin = (cwd: string) =>
  definePlugin({
    key: "pi",
    init: async (ctx: PluginContext) => {
      const tools = createBuiltinToolset(cwd);

      await ctx.tools.registerInvoker("pi", {
        invoke: async (toolId: string, args: unknown) => {
          const name = toolId.split(".").pop() as BuiltinToolName | undefined;
          if (!name || !(name in tools)) {
            return new ToolInvocationResult({ data: null, error: `Unknown pi tool: ${toolId}` });
          }

          const tool = tools[name];
          try {
            const result = await tool.execute(toolId, args ?? {}, undefined, () => {});
            return new ToolInvocationResult({ data: result, error: null });
          } catch (cause) {
            return new ToolInvocationResult({ data: null, error: formatError(cause) });
          }
        },
      });

      await ctx.tools.register(
        builtinToolNames.map((name) => {
          const tool = tools[name];
          return new ToolRegistration({
            id: ToolId.make(`pi.${name}`),
            pluginKey: "pi",
            sourceId: "pi",
            name,
            description: tool.description,
            inputSchema: tool.parameters as Record<string, unknown>,
          });
        }),
      );

      return { extension: {} };
    },
  });

================================================
FILE: agents/pi/extensions/pi-codemode/src/read.ts
================================================
import { access as fsAccess, readFile as fsReadFile } from "fs/promises";
import { constants } from "fs";
import { extname } from "path";
import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
import { Type } from "@sinclair/typebox";

// Much higher defaults than the built-in read tool (2000 lines / 50KB)
export const CUSTOM_MAX_LINES = 100_000;
export const CUSTOM_MAX_BYTES = 10 * 1024 * 1024; // 10MB

const IMAGE_MIME_TYPES: Record<string, string> = {
  ".jpg": "image/jpeg",
  ".jpeg": "image/jpeg",
  ".png": "image/png",
  ".gif": "image/gif",
  ".webp": "image/webp",
};

function isImageFile(filePath: string): string | null {
  const ext = extname(filePath).toLowerCase();
  return IMAGE_MIME_TYPES[ext] || null;
}

function formatSize(bytes: number): string {
  if (bytes < 1024) return `${bytes}B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
}

const readSchema = Type.Object({
  path: Type.String({ description: "Path to the file to read (relative or absolute)" }),
  offset: Type.Optional(
    Type.Number({ description: "Line number to start reading from (1-indexed)" }),
  ),
  limit: Type.Optional(Type.Number({ description: "Maximum number of lines to read" })),
});

export interface ReadToolOptions {
  maxLines?: number;
  maxBytes?: number;
}

export function createCustomReadTool(cwd: string, options?: ReadToolOptions) {
  const maxLines = options?.maxLines ?? CUSTOM_MAX_LINES;
  const maxBytes = options?.maxBytes ?? CUSTOM_MAX_BYTES;

  return {
    name: "read",
    label: "read",
    description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${maxLines.toLocaleString()} lines or ${formatSize(maxBytes)} (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,
    parameters: readSchema,
    execute: async (
      _toolCallId: string,
      { path, offset, limit }: { path: string; offset?: number; limit?: number },
      signal?: AbortSignal,
    ): Promise<{ content: (TextContent | ImageContent)[] }> => {
      if (signal?.aborted) throw new Error("Operation aborted");

      const absolutePath = path.startsWith("/") ? path : `${cwd}/${path}`;

      // Check accessibility
      try {
        await fsAccess(absolutePath, constants.R_OK);
      } catch {
        throw new Error(`File not readable: ${path}`);
      }

      const mimeType = isImageFile(absolutePath);
      if (mimeType) {
        // Read image as base64
        const buffer = await fsReadFile(absolutePath);
        const base64 = buffer.toString("base64");
        return {
          content: [
            { type: "text", text: `Read image file [${mimeType}]` },
            { type: "image", data: base64, mimeType },
          ],
        };
      }

      // Read text file
      const buffer = await fsReadFile(absolutePath);
      const textContent = buffer.toString("utf-8");
      const allLines = textContent.split("\n");
      const totalFileLines = allLines.length;

      // Apply offset (1-indexed)
      const startLine = offset ? Math.max(0, offset - 1) : 0;
      const startLineDisplay = startLine + 1;

      if (startLine >= allLines.length) {
        throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);
      }

      // Slice content based on offset/limit
      let selectedLines: string[];
      let userLimitApplied = false;

      if (limit !== undefined) {
        const endLine = Math.min(startLine + limit, allLines.length);
        selectedLines = allLines.slice(startLine, endLine);
        userLimitApplied = endLine - startLine < allLines.length - startLine;
      } else {
        selectedLines = allLines.slice(startLine);
      }

      // Apply our own truncation (much higher limits)
      const result = truncateHead(selectedLines.join("\n"), { maxLines, maxBytes });

      let outputText: string;

      if (result.firstLineExceedsLimit) {
        const firstLineSize = formatSize(Buffer.byteLength(selectedLines[0] || "", "utf-8"));
        outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(maxBytes)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${maxBytes}]`;
      } else if (result.truncated) {
        const endLineDisplay = startLineDisplay + result.outputLines - 1;
        const nextOffset = endLineDisplay + 1;
        outputText = result.content;
        if (result.truncatedBy === "lines") {
          outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;
        } else {
          outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(maxBytes)} limit). Use offset=${nextOffset} to continue.]`;
        }
      } else if (userLimitApplied) {
        const endLine = startLine + (limit ?? 0);
        const remaining = totalFileLines - endLine;
        const nextOffset = endLine + 1;
        outputText = result.content;
        outputText += `\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;
      } else {
        outputText = result.content;
      }

      return {
        content: [{ type: "text", text: outputText }],
      };
    },
  };
}

interface TruncationResult {
  content: string;
  truncated: boolean;
  truncatedBy: "lines" | "bytes" | null;
  outputLines: number;
  firstLineExceedsLimit: boolean;
}

interface TruncationOptions {
  maxLines: number;
  maxBytes: number;
}

function truncateHead(content: string, options: TruncationOptions): TruncationResult {
  const { maxLines, maxBytes } = options;
  const totalBytes = Buffer.byteLength(content, "utf-8");
  const lines = content.split("\n");
  const totalLines = lines.length;

  if (totalLines <= maxLines && totalBytes <= maxBytes) {
    return {
      content,
      truncated: false,
      truncatedBy: null,
      outputLines: totalLines,
      firstLineExceedsLimit: false,
    };
  }

  // Check if first line alone exceeds limit
  const firstLineBytes = Buffer.byteLength(lines[0], "utf-8");
  if (firstLineBytes > maxBytes) {
    return {
      content: "",
      truncated: true,
      truncatedBy: "bytes",
      outputLines: 0,
      firstLineExceedsLimit: true,
    };
  }

  const outputLinesArr: string[] = [];
  let outputBytesCount = 0;
  let truncatedBy: "lines" | "bytes" = "lines";

  for (let i = 0; i < lines.length && i < maxLines; i++) {
    const line = lines[i];
    const lineBytes = Buffer.byteLength(line, "utf-8") + (i > 0 ? 1 : 0);
    if (outputBytesCount + lineBytes > maxBytes) {
      truncatedBy = "bytes";
      break;
    }
    outputLinesArr.push(line);
    outputBytesCount += lineBytes;
  }

  if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
    truncatedBy = "lines";
  }

  return {
    content: outputLinesArr.join("\n"),
    truncated: true,
    truncatedBy,
    outputLines: outputLinesArr.length,
    firstLineExceedsLimit: false,
  };
}


================================================
FILE: agents/pi/extensions/pi-codemode/src/render.ts
================================================
import { Text } from "@mariozechner/pi-tui";
import type { Theme } from "@mariozechner/pi-coding-agent";
import type { CodemodeTrace, TraceStep } from "./types.js";

const truncate = (value: string, max: number): string => (value.length <= max ? value : `${value.slice(0, max - 1)}…`);

const formatDuration = (ms: number): string => {
  if (ms < 1000) return `${ms}ms`;
  return `${(ms / 1000).toFixed(ms < 10_000 ? 1 : 0)}s`;
};

const summarizeStep = (step: TraceStep): string => {
  if (step.error) return truncate(step.error, 80);
  if (!step.output?.text) return "";
  return truncate(step.output.text.split(/\r?\n/)[0] ?? "", 80);
};

export function renderCodemodeCall(code: string, theme: Theme): Text {
  const lines = code.trim().split(/\r?\n/);
  const suffix = lines.length > 1 ? theme.fg("muted", ` (${lines.length} lines)`) : "";
  const shown = lines.slice(0, 12).map((line) => theme.fg("accent", line)).join("\n");

  let content = `${theme.fg("toolTitle", theme.bold("codemode"))}${suffix}\n${shown}`;
  if (lines.length > 12) content += theme.fg("muted", `\n… (${lines.length - 12} more lines)`);

  return new Text(content, 0, 0);
}

export function renderCodemodeResult(trace: CodemodeTrace, expanded: boolean, theme: Theme): Text {
  const duration = trace.endedAt ? formatDuration(trace.endedAt - trace.startedAt) : "running";
  const isError = trace.status === "error" || trace.steps.some((step) => step.status === "error");
  const statusColor = isError ? "error" : trace.status === "ok" ? "success" : "accent";

  if (!expanded) {
    const lines: string[] = [
      `${theme.fg("toolTitle", theme.bold("codemode"))} ${theme.fg(statusColor, trace.status)} ${theme.fg("muted", duration)}`,
    ];

    for (const step of trace.steps) {
      const icon = step.status === "error" ? "✗" : step.status === "ok" ? "✓" : "○";
      const iconColor = step.status === "error" ? "error" : step.status === "ok" ? "success" : "muted";
      const summary = summarizeStep(step);
      lines.push(`${theme.fg(iconColor, icon)} ${step.label}${summary ? ` — ${theme.fg("muted", summary)}` : ""}`);
    }

    if (trace.value !== undefined) {
      const value = typeof trace.value === "string" ? trace.value : JSON.stringify(trace.value);
      lines.push(`→ ${theme.fg("success", truncate(value, 120))}`);
    }

    if (trace.error) lines.push(`→ ${theme.fg("error", truncate(trace.error, 120))}`);

    return new Text(lines.join("\n"), 0, 0);
  }

  const lines: string[] = [
    theme.fg("toolTitle", theme.bold("codemode execution")),
    `status: ${theme.fg(statusColor, trace.status)} · ${duration} · ${trace.steps.length} step${trace.steps.length === 1 ? "" : "s"}`,
    "",
    theme.fg("muted", "// executed code:"),
    ...trace.code.trim().split(/\r?\n/).map((line) => theme.fg("accent", line)),
  ];

  if (trace.steps.length > 0) {
    lines.push("", theme.bold("steps:"));
    for (const step of trace.steps) {
      const color = step.status === "error" ? "error" : step.status === "ok" ? "success" : "warning";
      lines.push(`${theme.fg(color, step.status === "error" ? "✗" : "✓")} ${step.label}`);
      lines.push(theme.fg("muted", `  input: ${truncate(typeof step.input === "string" ? step.input : JSON.stringify(step.input), 240)}`));
      if (step.output?.text) {
        for (const line of step.output.text.split(/\r?\n/).slice(0, 100)) lines.push(theme.fg("toolOutput", `  ${line}`));
      }
      if (step.error) lines.push(theme.fg("error", `  ${step.error}`));
    }
  }

  if (trace.logs.length > 0) {
    lines.push("", theme.bold(`logs (${trace.logs.length}):`));
    for (const log of trace.logs.slice(0, 200)) lines.push(theme.fg("muted", `  ${log}`));
    if (trace.logs.length > 200) lines.push(theme.fg("muted", `  … (${trace.logs.length - 200} more)`));
  }

  if (trace.value !== undefined) {
    lines.push("", theme.bold("result:"));
    const value = typeof trace.value === "string" ? trace.value : JSON.stringify(trace.value, null, 2);
    for (const line of value.split(/\r?\n/).slice(0, 200)) lines.push(theme.fg("success", line));
  }

  if (trace.error) {
    lines.push("", theme.bold("error:"), theme.fg("error", trace.error));
  }

  return new Text(lines.join("\n"), 0, 0);
}

================================================
FILE: agents/pi/extensions/pi-codemode/src/runtime.ts
================================================
import type { Executor } from "@executor-js/sdk";
import { acquireSandbox, type SandboxDelegates } from "./sandbox-cache.js";
import { CodemodeTraceRecorder } from "./trace.js";
import type { ImageContent } from "@mariozechner/pi-ai";
import type { CodemodeTrace, ToolResultSnapshot } from "./types.js";

const DEFAULT_TIMEOUT_MS = 30_000;
const MAX_CODE_SIZE = 100_000;

type RuntimeOptions = {
  code: string;
  cwd: string;
  executor: Executor;
  timeoutMs?: number;
  signal?: AbortSignal;
  onUpdate?: () => void;
};

export type CodemodeExecutionResult = {
  value?: unknown;
  trace: CodemodeTrace;
  logs: string[];
};

const formatError = (cause: unknown): string => {
  if (cause instanceof Error) {
    const message = cause.message.trim();
    return message.length > 0 ? message : cause.name;
  }
  if (typeof cause === "string") return cause;
  if (typeof cause === "object" && cause !== null) {
    if ("message" in cause && typeof cause.message === "string") {
      const message = cause.message.trim();
      if (message.length > 0) return message;
    }
    try {
      return JSON.stringify(cause);
    } catch {
      return String(cause);
    }
  }
  return String(cause);
};

const isToolResult = (value: unknown): value is { content: unknown[] } =>
  typeof value === "object" &&
  value !== null &&
  "content" in value &&
  Array.isArray((value as { content?: unknown[] }).content);

const extractText = (value: unknown): string => {
  if (typeof value === "string") return value;
  if (typeof value === "undefined") return "";
  if (value === null) return "null";

  if (isToolResult(value)) {
    return value.content
      .filter(
        (entry): entry is { type?: unknown; text?: unknown } =>
          typeof entry === "object" && entry !== null,
      )
      .map((entry) => {
        if (entry.type === "text" && typeof entry.text === "string") return entry.text;
        return "";
      })
      .filter((line) => line.length > 0)
      .join(" ")
      .trim();
  }

  return "";
};

const extractImages = (value: unknown): ImageContent[] => {
  if (!isToolResult(value)) return [];
  return value.content.filter(
    (entry): entry is ImageContent =>
      typeof entry === "object" &&
      entry !== null &&
      (entry as Record<string, unknown>).type === "image" &&
      typeof (entry as Record<string, unknown>).data === "string" &&
      typeof (entry as Record<string, unknown>).mimeType === "string",
  );
};

const toSnapshot = (value: unknown, isError = false): ToolResultSnapshot => ({
  value,
  text: extractText(value),
  images: extractImages(value),
  isError,
});

const CODE_PREFIX = [
  '"use strict";',
  "",
  "const __invokeTool = SecureExec.bindings.invokeTool;",
  "const __emitLog = SecureExec.bindings.emitLog;",
  "const __emitResult = SecureExec.bindings.emitResult;",
  'const __formatArg = (value) => typeof value === "string" ? value : JSON.stringify(value);',
  'const __formatLine = (args) => args.map(__formatArg).join(" ");',
  "",
  "const __makeToolsProxy = (path = []) => new Proxy(() => undefined, {",
  "  get(_target, prop) {",
  '    if (prop === "then" || typeof prop === "symbol") return undefined;',
  "    return __makeToolsProxy([...path, String(prop)]);",
  "  },",
  "  apply(_target, _thisArg, args) {",
  '    const toolPath = path.join(".");',
  '    if (!toolPath) throw new Error("Tool path missing in invocation");',
  "    return Promise.resolve(__invokeTool(toolPath, args[0])).catch((err) => {",
  '      throw new Error(err?.error || err?.message || "Tool invocation failed");',
  "    });",
  "  },",
  "});",
  "const tools = __makeToolsProxy();",
  "",
  "const console = {",
  '  log: (...args) => __emitLog("log", __formatLine(args)),',
  '  warn: (...args) => __emitLog("warn", __formatLine(args)),',
  '  error: (...args) => __emitLog("error", __formatLine(args)),',
  '  info: (...args) => __emitLog("info", __formatLine(args)),',
  '  debug: (...args) => __emitLog("debug", __formatLine(args)),',
  "};",
  "",
  "(async () => {",
  "try {",
  "const value = await (async () => {",
].join("\n");

const CODE_POSTFIX = [
  "})();",
  "__emitResult(value);",
  "} catch (error) {",
  'const message = error && typeof error === "object" ? (error.stack || error.message || String(error)) : String(error);',
  'process.stderr.write(message + "\\n");',
  "process.exitCode = 1;",
  "}",
  "})();",
].join("\n");

const buildExecutionSource = (code: string): string =>
  CODE_PREFIX + "\n" + code + "\n" + CODE_POSTFIX;

const invokeExecutorApi = async (
  executor: Executor,
  path: string,
  args: unknown,
): Promise<{ handled: true; data: unknown } | { handled: false }> => {
  switch (path) {
    case "list":
    case "tools.list":
      return { handled: true, data: await executor.tools.list(args ?? {}) };
    case "schema":
    case "tools.schema":
      return { handled: true, data: await executor.tools.schema(String(args)) };
    case "definitions":
    case "tools.definitions":
      return { handled: true, data: await executor.tools.definitions() };

    case "sources.list":
      return { handled: true, data: await executor.sources.list() };
    case "sources.remove":
      return { handled: true, data: await executor.sources.remove(String(args)) };
    case "sources.refresh":
      return { handled: true, data: await executor.sources.refresh(String(args)) };
    case "sources.detect":
      return { handled: true, data: await executor.sources.detect(String(args)) };

    case "policies.list":
      return { handled: true, data: await executor.policies.list() };
    case "policies.add":
      return { handled: true, data: await executor.policies.add(args as any) };
    case "policies.remove":
      return { handled: true, data: await executor.policies.remove(String(args)) };

    case "secrets.list":
      return { handled: true, data: await executor.secrets.list() };
    case "secrets.resolve":
      return { handled: true, data: await executor.secrets.resolve(String(args)) };
    case "secrets.status":
      return { handled: true, data: await executor.secrets.status(String(args)) };
    case "secrets.set":
      return { handled: true, data: await executor.secrets.set(args as any) };
    case "secrets.remove":
      return { handled: true, data: await executor.secrets.remove(String(args)) };
    case "secrets.addProvider":
      return { handled: true, data: await executor.secrets.addProvider(args as any) };
    case "secrets.providers":
      return { handled: true, data: await executor.secrets.providers() };

    default:
      return { handled: false };
  }
};

// --- Tool invocation bridge (host side) ---
// Uses structured clone via secure-exec bindings — no JSON serialization.

const createInvokeTool =
  (executor: Executor, recorder: CodemodeTraceRecorder, onStep?: () => void) =>
    async (path: unknown, args: unknown): Promise<unknown> => {
      const toolPath = String(path);
      const step = recorder.startStep({ label: `tools.${toolPath}`, toolPath, input: args });

      try {
        const direct = await invokeExecutorApi(executor, toolPath, args);
        let data: unknown;

        if (direct.handled) {
          data = direct.data;
        } else {
          const invoked = await executor.tools.invoke(toolPath, args, {
            onElicitation: "accept-all",
          });
          if (invoked.error != null) {
            const message = formatError(invoked.error);
            recorder.finishStep(step, undefined, message);
            onStep?.();
            throw { error: message };
          }
          data = invoked.data;
        }

        const snapshot = toSnapshot(data);
        recorder.finishStep(step, snapshot);
        onStep?.();

        // pi and fff tools return ToolResult objects ({ content: [...] }) — extract text
        // for backwards compat. Other tools (MCP, OpenAPI, GraphQL) return objects as-is.
        if ((toolPath.startsWith("pi.") || toolPath.startsWith("fff.")) && isToolResult(data)) {
          return extractText(data);
        }
        return data;
      } catch (cause) {
        const message = formatError(cause);
        recorder.finishStep(step, undefined, message);
        onStep?.();
        throw { error: message };
      }
    };

// --- Sequential per-cwd execution queue ---

const executionQueues = new Map<string, Promise<unknown>>();

export const runCodemode = async (options: RuntimeOptions): Promise<CodemodeExecutionResult> => {
  const key = options.cwd;
  const prev = executionQueues.get(key);
  const next = (async (): Promise<CodemodeExecutionResult> => {
    if (prev) {
      try {
        await prev;
      } catch {
        /* ignore previous execution errors */
      }
    }
    return _runCodemode(options);
  })();
  executionQueues.set(key, next);
  try {
    return await next;
  } finally {
    if (executionQueues.get(key) === next) {
      executionQueues.delete(key);
    }
  }
};

// --- Core execution ---

const noopDelegates: SandboxDelegates = {
  invokeTool: async () => undefined,
  emitLog: () => { },
  emitResult: () => {},
};

const _runCodemode = async (options: RuntimeOptions): Promise<CodemodeExecutionResult> => {
  const code = options.code;
  const timeoutMs = Math.max(100, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
  const recorder = new CodemodeTraceRecorder({ cwd: options.cwd, code });
  const logs: string[] = [];

  if (code.length > MAX_CODE_SIZE) {
    const message = `Code exceeds ${MAX_CODE_SIZE} bytes`;
    const trace = recorder.finish({ status: "error", error: message });
    return { trace, logs };
  }

  const sandbox = await acquireSandbox(options.cwd);

  // Wire up delegates for this execution
  sandbox.delegates.invokeTool = createInvokeTool(options.executor, recorder, options.onUpdate);
  sandbox.delegates.emitResult = (value: unknown) => {
    capturedResult = value;
  };
  sandbox.delegates.emitLog = (level: unknown, line: unknown) => {
    const entry = `[${String(level)}] ${String(line)}`;
    logs.push(entry);
    recorder.log(entry);
  };

  let capturedResult: unknown = undefined;

  try {
    let aborted = false;
    let timedOut = false;

    const source = buildExecutionSource(code);

    const stdoutDecoder = new TextDecoder();
    const stderrDecoder = new TextDecoder();
    let stdout = "";
    let stderr = "";

    const proc = sandbox.kernel.spawn("node", ["-e", source], {
      cwd: options.cwd,
      onStdout: (data) => {
        stdout += stdoutDecoder.decode(data, { stream: true });
      },
      onStderr: (data) => {
        stderr += stderrDecoder.decode(data, { stream: true });
      },
    });

    const timeoutId = setTimeout(() => {
      timedOut = true;
      proc.kill(9);
    }, timeoutMs);

    let abortHandler: (() => void) | undefined;
    if (options.signal) {
      abortHandler = () => {
        aborted = true;
        proc.kill(9);
      };
      if (options.signal.aborted) abortHandler();
      else options.signal.addEventListener("abort", abortHandler, { once: true });
    }

    let exitCode: number;
    try {
      exitCode = await proc.wait();
    } finally {
      clearTimeout(timeoutId);
      if (options.signal && abortHandler) options.signal.removeEventListener("abort", abortHandler);
      stdout += stdoutDecoder.decode();
      stderr += stderrDecoder.decode();
    }

    const value = capturedResult;

    if (timedOut) {
      const trace = recorder.finish({
        status: "error",
        error: `Execution timed out after ${timeoutMs}ms`,
      });
      return { trace, logs };
    }

    if (aborted || options.signal?.aborted) {
      const trace = recorder.finish({ status: "aborted", value, error: "Execution aborted" });
      return { value, trace, logs };
    }

    if (exitCode !== 0) {
      const adjustedStderr = stderr.trim();
      const error = adjustedStderr || stdout.trim() || `Process exited with code ${exitCode}`;
      const trace = recorder.finish({ status: "error", value, error });
      return { value, trace, logs };
    }

    const trace = recorder.finish({ status: "ok", value });
    return { value, trace, logs };
  } catch (cause) {
    const message = formatError(cause);
    const trace = recorder.finish({
      status: options.signal?.aborted ? "aborted" : "error",
      error: message,
    });
    return { trace, logs };
  } finally {
    // Reset delegates to no-ops so next execution starts clean
    sandbox.delegates.invokeTool = noopDelegates.invokeTool;
    sandbox.delegates.emitLog = noopDelegates.emitLog;
    sandbox.delegates.emitResult = noopDelegates.emitResult;
  }
};


================================================
FILE: agents/pi/extensions/pi-codemode/src/sandbox-cache.ts
================================================
import { createInMemoryFileSystem, createKernel, createNodeRuntime, type Kernel } from "secure-exec";

// Bound once into secure-exec. Mutable delegates allow per-execution handler swap
// without recreating the kernel.
export type SandboxDelegates = {
  invokeTool: (path: unknown, args: unknown) => Promise<unknown>;
  emitLog: (level: unknown, line: unknown) => void;
  emitResult: (value: unknown) => void;
};

export type SandboxEntry = {
  kernel: Kernel;
  delegates: SandboxDelegates;
};

const noopDelegates: SandboxDelegates = {
  invokeTool: async () => undefined,
  emitLog: () => {},
  emitResult: () => {},
};

const cache = new Map<string, SandboxEntry>();

export const acquireSandbox = async (cwd: string): Promise<SandboxEntry> => {
  const existing = cache.get(cwd);
  if (existing) return existing;

  const delegates: SandboxDelegates = { ...noopDelegates };

  // Fixed bindings that forward through mutable delegates
  const bindings = {
    invokeTool: (path: unknown, args: unknown) => delegates.invokeTool(path, args),
    emitLog: (level: unknown, line: unknown) => delegates.emitLog(level, line),
    emitResult: (value: unknown) => delegates.emitResult(value),
  };

  const kernel = createKernel({ filesystem: createInMemoryFileSystem(), cwd });
  await kernel.mount(createNodeRuntime({ bindings }));

  const entry: SandboxEntry = { kernel, delegates };
  cache.set(cwd, entry);
  return entry;
};

export const disposeAll = async (): Promise<void> => {
  await Promise.allSettled(
    Array.from(cache.values()).map((entry) => entry.kernel.dispose()),
  );
  cache.clear();
};

================================================
FILE: agents/pi/extensions/pi-codemode/src/source-config.ts
================================================
import { readFile, stat } from "node:fs/promises";
import { homedir } from "node:os";
import { join } from "node:path";
import { parse, printParseErrorCode, type ParseError } from "jsonc-parser";

const SECRET_REF_PREFIX = "secret-public-ref:";

type UnknownRecord = Record<string, unknown>;

type HeaderSecretRef = { secretId: string; prefix?: string };
type PluginHeaderValue = string | HeaderSecretRef;

export type OpenApiSourceConfig = {
  kind: "openapi";
  spec: string;
  baseUrl?: string;
  namespace?: string;
  headers?: Record<string, PluginHeaderValue>;
};

export type GraphqlSourceConfig = {
  kind: "graphql";
  endpoint: string;
  introspectionJson?: string;
  namespace?: string;
  headers?: Record<string, PluginHeaderValue>;
};

export type McpRemoteSourceConfig = {
  kind: "mcp";
  transport: "remote";
  name: string;
  endpoint: string;
  remoteTransport?: "streamable-http" | "sse" | "auto";
  namespace?: string;
  queryParams?: Record<string, string>;
  headers?: Record<string, string>;
};

export type McpStdioSourceConfig = {
  kind: "mcp";
  transport: "stdio";
  name: string;
  command: string;
  args?: string[];
  env?: Record<string, string>;
  cwd?: string;
  namespace?: string;
};

export type SupportedSourceConfig =
  | OpenApiSourceConfig
  | GraphqlSourceConfig
  | McpRemoteSourceConfig
  | McpStdioSourceConfig;

export type UnsupportedSourceConfig = {
  index: number;
  reason: string;
  value: unknown;
  kind?: string;
};

export type LoadedSourceConfig = {
  configPath: string;
  mtimeMs: number;
  sources: SupportedSourceConfig[];
  unsupported: UnsupportedSourceConfig[];
};

const isRecord = (value: unknown): value is UnknownRecord =>
  typeof value === "object" && value !== null && !Array.isArray(value);

const parseStringMap = (value: unknown): Record<string, string> | null => {
  if (!isRecord(value)) return null;
  const output: Record<string, string> = {};
  for (const [key, item] of Object.entries(value)) {
    if (typeof item !== "string") return null;
    output[key] = item;
  }
  return output;
};

const parseStringArray = (value: unknown): string[] | null => {
  if (!Array.isArray(value)) return null;
  if (value.some((item) => typeof item !== "string")) return null;
  return [...value] as string[];
};

const parseHeaderValue = (value: unknown): PluginHeaderValue | null => {
  if (typeof value === "string") {
    if (value?.startsWith(SECRET_REF_PREFIX)) {
      return { secretId: value.slice(SECRET_REF_PREFIX.length) };
    }
    return value;
  }

  if (!isRecord(value) || typeof value.value !== "string") return null;

  const prefix = typeof value.prefix === "string" ? value.prefix : undefined;
  const raw = value.value;

  if (raw?.startsWith(SECRET_REF_PREFIX)) {
    const secretId = raw.slice(SECRET_REF_PREFIX.length);
    return prefix ? { secretId, prefix } : { secretId };
  }

  return prefix ? prefix + raw : raw;
};

const parseHeaderMap = (value: unknown): Record<string, PluginHeaderValue> | null => {
  if (!isRecord(value)) return null;
  const output: Record<string, PluginHeaderValue> = {};
  for (const [key, item] of Object.entries(value)) {
    const parsed = parseHeaderValue(item);
    if (parsed == null) return null;
    output[key] = parsed;
  }
  return output;
};

const parseMcpSource = (entry: UnknownRecord): { source?: SupportedSourceConfig; reason?: string } => {
  const transport = entry.transport;
  if (transport !== "remote" && transport !== "stdio") {
    return { reason: "mcp.transport must be \"remote\" or \"stdio\"" };
  }

  if (typeof entry.name !== "string" || entry.name.trim().length === 0) {
    return { reason: "mcp.name must be a non-empty string" };
  }

  if (entry.namespace !== undefined && typeof entry.namespace !== "string") {
    return { reason: "mcp.namespace must be a string" };
  }

  if (transport === "remote") {
    if (typeof entry.endpoint !== "string" || entry.endpoint.trim().length === 0) {
      return { reason: "mcp(remote).endpoint must be a non-empty string" };
    }

    if (
      entry.remoteTransport !== undefined &&
      entry.remoteTransport !== "streamable-http" &&
      entry.remoteTransport !== "sse" &&
      entry.remoteTransport !== "auto"
    ) {
      return { reason: "mcp(remote).remoteTransport must be streamable-http|sse|auto" };
    }

    if (entry.queryParams !== undefined && parseStringMap(entry.queryParams) == null) {
      return { reason: "mcp(remote).queryParams must be a string map" };
    }

    if (entry.headers !== undefined && parseStringMap(entry.headers) == null) {
      return { reason: "mcp(remote).headers must be a string map" };
    }

    return {
      source: {
        kind: "mcp",
        transport: "remote",
        name: entry.name,
        endpoint: entry.endpoint,
        remoteTransport: entry.remoteTransport,
        namespace: entry.namespace,
        queryParams: entry.queryParams as Record<string, string> | undefined,
        headers: entry.headers as Record<string, string> | undefined,
      },
    };
  }

  if (typeof entry.command !== "string" || entry.command.trim().length === 0) {
    return { reason: "mcp(stdio).command must be a non-empty string" };
  }

  if (entry.args !== undefined && parseStringArray(entry.args) == null) {
    return { reason: "mcp(stdio).args must be a string array" };
  }

  if (entry.env !== undefined && parseStringMap(entry.env) == null) {
    return { reason: "mcp(stdio).env must be a string map" };
  }

  if (entry.cwd !== undefined && typeof entry.cwd !== "string") {
    return { reason: "mcp(stdio).cwd must be a string" };
  }

  return {
    source: {
      kind: "mcp",
      transport: "stdio",
      name: entry.name,
      command: entry.command,
      args: entry.args as string[] | undefined,
      env: entry.env as Record<string, string> | undefined,
      cwd: entry.cwd as string | undefined,
      namespace: entry.namespace,
    },
  };
};

const parseOpenApiSource = (entry: UnknownRecord): { source?: SupportedSourceConfig; reason?: string } => {
  if (typeof entry.spec !== "string" || entry.spec.trim().length === 0) {
    return { reason: "openapi.spec must be a non-empty string" };
  }

  if (entry.baseUrl !== undefined && typeof entry.baseUrl !== "string") {
    return { reason: "openapi.baseUrl must be a string" };
  }

  if (entry.namespace !== undefined && typeof entry.namespace !== "string") {
    return { reason: "openapi.namespace must be a string" };
  }

  const headers = entry.headers === undefined ? undefined : parseHeaderMap(entry.headers);
  if (entry.headers !== undefined && headers == null) {
    return { reason: "openapi.headers must map to string or secret refs" };
  }

  return {
    source: {
      kind: "openapi",
      spec: entry.spec,
      baseUrl: entry.baseUrl as string | undefined,
      namespace: entry.namespace as string | undefined,
      headers: headers ?? undefined,
    },
  };
};

const parseGraphqlSource = (entry: UnknownRecord): { source?: SupportedSourceConfig; reason?: string } => {
  if (typeof entry.endpoint !== "string" || entry.endpoint.trim().length === 0) {
    return { reason: "graphql.endpoint must be a non-empty string" };
  }

  if (entry.introspectionJson !== undefined && typeof entry.introspectionJson !== "string") {
    return { reason: "graphql.introspectionJson must be a string" };
  }

  if (entry.namespace !== undefined && typeof entry.namespace !== "string") {
    return { reason: "graphql.namespace must be a string" };
  }

  const headers = entry.headers === undefined ? undefined : parseHeaderMap(entry.headers);
  if (entry.headers !== undefined && headers == null) {
    return { reason: "graphql.headers must map to string or secret refs" };
  }

  return {
    source: {
      kind: "graphql",
      endpoint: entry.endpoint,
      introspectionJson: entry.introspectionJson as string | undefined,
      namespace: entry.namespace as string | undefined,
      headers: headers ?? undefined,
    },
  };
};

const parseErrorsToMessage = (errors: ParseError[]): string =>
  errors.map((error) => "offset " + error.offset + ": " + printParseErrorCode(error.error)).join("; ");

export const getExecutorConfigPath = (): string => join(homedir(), ".pi", "agent", "executor.jsonc");

export const loadSourcesFromConfig = async (): Promise<LoadedSourceConfig> => {
  const configPath = getExecutorConfigPath();

  let raw: string;
  let mtimeMs: number;
  try {
    mtimeMs = (await stat(configPath)).mtimeMs;
    raw = await readFile(configPath, "utf8");
  } catch (cause) {
    const error = cause as NodeJS.ErrnoException;
    if (error?.code === "ENOENT") {
      return {
        configPath,
        mtimeMs: 0,
        sources: [],
        unsupported: [],
      };
    }
    throw new Error("Failed reading " + configPath + ": " + (error?.message ?? String(cause)));
  }

  const parseErrors: ParseError[] = [];
  const parsed = parse(raw, parseErrors);
  if (parseErrors.length > 0) {
    throw new Error("Invalid JSONC in " + configPath + ": " + parseErrorsToMessage(parseErrors));
  }

  if (!isRecord(parsed)) {
    throw new Error("Invalid config at " + configPath + ": root must be an object");
  }

  const rawSources = parsed.sources;

  if (rawSources === undefined) {
    return { configPath, mtimeMs, sources: [], unsupported: [] };
  }

  if (!Array.isArray(rawSources)) {
    throw new Error("Invalid config at " + configPath + ": \"sources\" must be an array");
  }

  const sources: SupportedSourceConfig[] = [];
  const unsupported: UnsupportedSourceConfig[] = [];

  for (let index = 0; index < rawSources.length; index++) {
    const rawSource = rawSources[index];
    if (!isRecord(rawSource)) {
      unsupported.push({ index, reason: "source entry must be an object", value: rawSource });
      continue;
    }

    const kind = typeof rawSource.kind === "string" ? rawSource.kind : undefined;

    if (kind === "mcp") {
      const parsedSource = parseMcpSource(rawSource);
      if (!parsedSource.source) {
        unsupported.push({ index, kind, reason: parsedSource.reason ?? "invalid mcp source", value: rawSource });
        continue;
      }
      sources.push(parsedSource.source);
      continue;
    }

    if (kind === "openapi") {
      const parsedSource = parseOpenApiSource(rawSource);
      if (!parsedSource.source) {
        unsupported.push({ index, kind, reason: parsedSource.reason ?? "invalid openapi source", value: rawSource });
        continue;
      }
      sources.push(parsedSource.source);
      continue;
    }

    if (kind === "graphql") {
      const parsedSource = parseGraphqlSource(rawSource);
      if (!parsedSource.source) {
        unsupported.push({ index, kind, reason: parsedSource.reason ?? "invalid graphql source", value: rawSource });
        continue;
      }
      sources.push(parsedSource.source);
      continue;
    }

    unsupported.push({
      index,
      kind,
      reason: kind ? "unsupported source kind: " + kind : "source.kind is required",
      value: rawSource,
    });
  }

  return { configPath, mtimeMs, sources, unsupported };
};

================================================
FILE: agents/pi/extensions/pi-codemode/src/source-hydrate.ts
================================================
import type { Executor } from "@executor-js/sdk";
import type { SupportedSourceConfig, UnsupportedSourceConfig } from "./source-config.js";

type ExecutorWithPlugins = Executor & {
  mcp?: { addSource: (source: unknown) => Promise<unknown> };
  openapi?: { addSpec: (source: unknown) => Promise<unknown> };
  graphql?: { addSource: (source: unknown) => Promise<unknown> };
};

type HydrateOptions = {
  configPath: string;
  unsupported: UnsupportedSourceConfig[];
};

const sourceKey = (source: SupportedSourceConfig): string => {
  if (source.namespace) return source.kind + ":" + source.namespace;

  if (source.kind === "mcp") {
    if (source.transport === "remote") return "mcp:remote:" + source.endpoint;
    return "mcp:stdio:" + source.command + ":" + (source.args ?? []).join("\u0000") + ":" + (source.cwd ?? "");
  }

  if (source.kind === "openapi") return "openapi:" + source.spec;
  return "graphql:" + source.endpoint;
};

const summarize = (source: SupportedSourceConfig): string => {
  if (source.namespace) return source.kind + ":" + source.namespace;
  if (source.kind === "mcp") return source.transport === "remote" ? "mcp:" + source.endpoint : "mcp:" + source.command;
  if (source.kind === "openapi") return "openapi:" + source.spec;
  return "graphql:" + source.endpoint;
};

export const hydrateExecutorSources = async (
  executor: Executor,
  sources: SupportedSourceConfig[],
  options: HydrateOptions,
): Promise<void> => {
  if (options.unsupported.length > 0) {
    for (const entry of options.unsupported) {
      console.warn(
        "[codemode] Skipping unsupported source in " +
          options.configPath +
          " (#" +
          entry.index +
          "): " +
          entry.reason,
      );
    }
  }

  if (sources.length === 0) return;

  const ext = executor as ExecutorWithPlugins;
  const existing = await executor.sources.list();
  const existingIds = new Set(existing.map((source: { id: string }) => source.id));
  const seen = new Set<string>();

  for (const source of sources) {
    const key = sourceKey(source);
    if (seen.has(key)) continue;
    seen.add(key);

    if (source.namespace && existingIds.has(source.namespace)) continue;

    if (source.kind === "mcp") {
      if (!ext.mcp?.addSource) {
        throw new Error("Missing MCP plugin while hydrating " + summarize(source) + " from " + options.configPath);
      }
      await ext.mcp.addSource(source);
      continue;
    }

    if (source.kind === "openapi") {
      if (!ext.openapi?.addSpec) {
        throw new Error("Missing OpenAPI plugin while hydrating " + summarize(source) + " from " + options.configPath);
      }
      await ext.openapi.addSpec(source);
      continue;
    }

    if (!ext.graphql?.addSource) {
      throw new Error("Missing GraphQL plugin while hydrating " + summarize(source) + " from " + options.configPath);
    }
    await ext.graphql.addSource(source);
  }
};


================================================
FILE: agents/pi/extensions/pi-codemode/src/trace.ts
================================================
import type { ImageContent } from "@mariozechner/pi-ai";
import type { CodemodeTrace, ToolResultSnapshot, TraceStep } from "./types.js";

const clone = <T>(value: T): T => {
  if (typeof structuredClone === "function") return structuredClone(value);
  return JSON.parse(JSON.stringify(value)) as T;
};

const formatDuration = (ms: number): string => {
  if (ms < 1000) return `${ms}ms`;
  return `${(ms / 1000).toFixed(ms < 10_000 ? 1 : 0)}s`;
};

const summarizeText = (text: string, max = 140): string => {
  const first = text.split(/\r?\n/).find((line) => line.trim().length > 0) ?? "";
  if (first.length <= max) return first;
  return `${first.slice(0, max - 1)}…`;
};

const summarizeValue = (value: unknown): string => {
  if (value === undefined) return "undefined";
  if (value === null) return "null";
  if (typeof value === "string") return JSON.stringify(value.length > 80 ? `${value.slice(0, 77)}…` : value);
  if (typeof value === "number" || typeof value === "boolean") return String(value);
  if (Array.isArray(value)) return `[${value.length} items]`;
  if (typeof value === "object") return `{${Object.keys(value as Record<string, unknown>).slice(0, 4).join(", ")}}`;
  return String(value);
};

export class CodemodeTraceRecorder {
  private readonly trace: CodemodeTrace;
  private readonly steps = new Map<string, TraceStep>();
  private id = 0;

  constructor(input: { cwd: string; code: string }) {
    this.trace = {
      cwd: input.cwd,
      code: input.code,
      startedAt: Date.now(),
      status: "running",
      logs: [],
      steps: [],
    };
  }

  log(line: string): void {
    this.trace.logs.push(line);
  }

  startStep(input: { label: string; toolPath: string; input: unknown }): string {
    const id = `step_${++this.id}`;
    const step: TraceStep = {
      id,
      label: input.label,
      toolPath: input.toolPath,
      input: clone(input.input),
      startedAt: Date.now(),
      status: "running",
    };
    this.steps.set(id, step);
    this.trace.steps.push(step);
    return id;
  }

  finishStep(id: string, output?: ToolResultSnapshot, error?: string): void {
    const step = this.steps.get(id);
    if (!step) return;
    step.endedAt = Date.now();

    if (error) {
      step.status = "error";
      step.error = error;
      return;
    }

    if (output) {
      step.output = clone(output);
      step.status = output.isError ? "error" : "ok";
      if (output.isError) step.error = output.text;
      return;
    }

    step.status = "ok";
  }

  finish(input: { status: CodemodeTrace["status"]; value?: unknown; error?: string }): CodemodeTrace {
    this.trace.endedAt = Date.now();
    this.trace.status = input.status;
    this.trace.value = input.value;
    this.trace.error = input.error;
    return clone(this.trace);
  }
}

export const summarizeTraceForContext = (trace: CodemodeTrace): string => {
  const duration = trace.endedAt ? formatDuration(trace.endedAt - trace.startedAt) : undefined;
  const errors = trace.steps.filter((s) => s.status === "error").length;

  return [
    `codemode ${trace.status}`,
    duration,
    `${trace.steps.length} step${trace.steps.length === 1 ? "" : "s"}`,
    errors > 0 ? `${errors} err` : undefined,
    trace.logs.length > 0 ? `${trace.logs.length} log${trace.logs.length === 1 ? "" : "s"}` : undefined,
    trace.value !== undefined ? `value=${summarizeValue(trace.value)}` : undefined,
    trace.error ? `error=${summarizeText(trace.error, 120)}` : undefined,
  ]
    .filter((v): v is string => Boolean(v))
    .join(" · ");
};

export const formatTraceForAgent = (trace: CodemodeTrace, value: unknown, logs: string[]): { text: string; images: ImageContent[] } => {
  const durationMs = trace.endedAt ? trace.endedAt - trace.startedAt : 0;
  const duration = formatDuration(durationMs);

  const result: string[] = [`status:${trace.status} duration:${duration}`];

  if (trace.steps.length > 0) {
    result.push("", "steps:");
    for (const step of trace.steps) {
      const stepDuration = step.endedAt ? formatDuration(step.endedAt - step.startedAt) : "";
      const prefix = step.status === "error" ? "[ERR]" : step.status === "ok" ? "[OK]" : "[...]";
      result.push(`${prefix} ${step.label} ${stepDuration}`);
      if (step.error) {
        result.push(`  error: ${step.error}`);
      } else if (step.output?.text) {
        const lines = step.output.text.split(/\r?\n/).filter((l) => l.trim().length > 0);
        const preview = lines.slice(0, 8).join("\n  ");
        result.push(`  output: ${preview}${lines.length > 8 ? `\n  ... (${lines.length - 8} more lines)` : ""}`);
      }
    }
  }

  if (trace.error) {
    result.push("", `execution error: ${trace.error}`);
  }

  if (value !== undefined) {
    const raw = typeof value === "string" ? value : JSON.stringify(value);
    result.push("", `return value: ${raw}`);
  }

  if (logs.length > 0) {
    result.push("", "logs:");
    for (const log of logs) {
      result.push(log.replace(/^\[\w+\] /, ""));
    }
  }

  const images = trace.steps.flatMap((s) => s.output?.images ?? []);

  return { text: result.join("\n"), images };
};


================================================
FILE: agents/pi/extensions/pi-codemode/src/turndown.d.ts
================================================
declare module "turndown" {
  export default class TurndownService {
    turndown(html: string): string;
  }
}


================================================
FILE: agents/pi/extensions/pi-codemode/src/types.ts
================================================
import type { ImageContent } from "@mariozechner/pi-ai";

export const builtinToolNames = ["read", "bash", "edit", "write", "grep", "find", "ls", "webfetch"] as const;
export type BuiltinToolName = (typeof builtinToolNames)[number];

export const fffToolNames = [
  "grep",
  "fileSearch",
  "multiGrep",
  "recentFiles",
  "searchThenGrep",
] as const;
export type FffToolName = (typeof fffToolNames)[number];

export type ToolResultSnapshot = {
  value: unknown;
  text: string;
  images?: ImageContent[];
  isError: boolean;
};

export type TraceStep = {
  id: string;
  label: string;
  toolPath: string;
  input: unknown;
  startedAt: number;
  endedAt?: number;
  status: "running" | "ok" | "error";
  output?: ToolResultSnapshot;
  error?: string;
};

export type CodemodeTrace = {
  cwd: string;
  code: string;
  startedAt: number;
  endedAt?: number;
  status: "running" | "ok" | "error" | "aborted";
  value?: unknown;
  logs: string[];
  steps: TraceStep[];
  error?: string;
};

export type CodemodeResultDetails = {
  trace: CodemodeTrace;
  value?: unknown;
  logs: string[];
  summary: string;
};

================================================
FILE: agents/pi/extensions/pi-codemode/src/util.ts
================================================
export const stripCodeFences = (code: string): string => {
  const trimmed = code.trim();
  const match = trimmed.match(/^(```|~~~)(?:\w+)?\r?\n([\s\S]+)\r?\n\1$/);
  if (match) return match[2].trim();
  return trimmed;
};

export const buildPromptGuidelines = () => [
  "Write plain JavaScript body only. No imports/exports. No markdown fences",
  "Use things from tools.* namespace to access tools",
  "Only do filesystem related operations using tools.pi.*",
  "Never rely on bash if it can be done in JavaScript",
  "Batch related work in one codemode call",
  "Prefer tools.pi.read over shell commands: read({ offset, limit }) gives line ranges",
  "Prefer tools.pi.grep over grep: it returns structured results with line numbers",
  "Output visibility: use `return value` to show output visibly, use `console.log(value)` for logs. Bare expressions like `result;` or string tricks like `'' + result` are silently swallowed.",
  "Bash is available for package managers (npm, pnpm, bun, yarn, npx, node), file operations (mkdir, cp, mv, rm, ln, chmod), and utilities (pwd, echo, which, uname, date). Use tools.pi.* for reading/writing/searching/grepping/editing files.",
];

export const formatError = (cause: unknown): string => {
  if (cause instanceof Error) return cause.message || cause.name;
  if (typeof cause === "string") return cause;
  try {
    return JSON.stringify(cause);
  } catch {
    return String(cause);
  }
};

================================================
FILE: agents/pi/extensions/pi-codemode/src/webfetch.ts
================================================
import TurndownService from "turndown";

export type WebfetchInput = {
  url: string;
  format?: "markdown" | "text" | "html";
  timeout?: number;
};

const MAX_RESPONSE_SIZE = 5 * 1024 * 1024;
const DEFAULT_TIMEOUT = 30 * 1000;
const MAX_TIMEOUT = 120 * 1000;

const turndownService = new TurndownService();

// Simple HTML to text conversion
function htmlToText(html: string): string {
  return (
    html
      .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "")
      .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "")
      .replace(/<\/p>/gi, "\n\n")
      .replace(/<br\s*\/?>/gi, "\n")
      .replace(/<\/div>/gi, "\n")
      .replace(/<\/h[1-6]>/gi, "\n\n")
      .replace(/<\/li>/gi, "\n")
      .replace(/<[^>]+>/g, "")
      .replace(/&nbsp;/g, " ")
      .replace(/&amp;/g, "&")
      .replace(/&lt;/g, "<")
      .replace(/&gt;/g, ">")
      .replace(/&quot;/g, '"')
      .replace(/&#39;/g, "'")
      .replace(/\n{3,}/g, "\n\n")
      .trim()
  );
}

function htmlToMarkdown(html: string): string {
  try {
    return turndownService.turndown(html);
  } catch {
    return htmlToText(html);
  }
}

export async function webfetch(
  _toolId: string,
  args: WebfetchInput,
  _signal: AbortSignal | undefined,
  _onUpdate: () => void,
): Promise<{ content: Array<{ type: "text"; text: string }>; details?: Record<string, unknown> }> {
  const format = args.format ?? "markdown";
  let url = args.url;

  if (url.startsWith("http://")) {
    try {
      const parsed = new URL(url);
      const isLocalhost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "::1";
      if (!isLocalhost) {
        url = url.replace("http://", "https://");
      }
    } catch {
      return {
        content: [{ type: "text", text: "" }],
        details: { url: args.url, format, error: "Invalid URL" },
      };
    }
  }
  if (!url.startsWith("https://")) {
    return {
      content: [{ type: "text", text: "" }],
      details: { url: args.url, format, error: "Invalid URL" },
    };
  }

  const timeout = Math.min((args.timeout ?? DEFAULT_TIMEOUT / 1000) * 1000, MAX_TIMEOUT);
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, {
      signal: controller.signal,
      headers: {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
      },
    });

    clearTimeout(timeoutId);

    if (!response.ok) {
      return {
        content: [{ type: "text", text: "" }],
        details: { url, format, error: `HTTP ${response.status}` },
      };
    }

    const contentLength = response.headers.get("content-length");
    if (contentLength && parseInt(contentLength) > MAX_RESPONSE_SIZE) {
      return {
        content: [{ type: "text", text: "" }],
        details: { url, format, error: "Response too large" },
      };
    }

    const contentType = response.headers.get("content-type") || "";
    const mime = contentType.split(";")[0]?.trim().toLowerCase() || "";

    if (
      mime.startsWith("image/") ||
      mime.startsWith("video/") ||
      mime.startsWith("audio/") ||
      mime.startsWith("application/pdf") ||
      mime.startsWith("application/zip") ||
      mime.startsWith("application/octet-stream")
    ) {
      return {
        content: [{ type: "text", text: "" }],
        details: { url, format, contentType: mime, skipped: true },
      };
    }

    const arrayBuffer = await response.arrayBuffer();

    if (arrayBuffer.byteLength > MAX_RESPONSE_SIZE) {
      return {
        content: [{ type: "text", text: "" }],
        details: { url, format, error: "Response too large" },
      };
    }

    let text = new TextDecoder().decode(arrayBuffer);
    let output = "";

    switch (format) {
      case "markdown":
        output = mime.includes("text/html") ? htmlToMarkdown(text) : text;
        break;
      case "text":
        output = mime.includes("text/html") ? htmlToText(text) : text;
        break;
      case "html":
        output = text;
        break;
    }

    return {
      content: [{ type: "text", text: output.trim() }],
      details: { url, format, contentType: mime },
    };
  } catch (error) {
    clearTimeout(timeoutId);
    const errorMsg = error instanceof Error ? error.message : "Unknown error";
    return {
      content: [{ type: "text", text: "" }],
      details: { url, format, error: errorMsg },
    };
  }
}

================================================
FILE: agents/pi/extensions/pi-codemode/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "noEmit": true,
    "paths": {
      "@executor/codemode-core": ["./node_modules/@executor/codemode-core/src/index.ts"]
    }
  },
  "include": ["./src/**/*.ts", "./index.ts"],
  "exclude": ["node_modules", "examples"]
}


================================================
FILE: agents/pi/extensions/prompt-timer.ts
================================================
import type { AssistantMessage } from "@mariozechner/pi-ai";
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";

function isAssistantMessage(message: unknown): message is AssistantMessage {
  if (!message || typeof message !== "object") return false;
  const role = (message as { role?: unknown }).role;
  return role === "assistant";
}

function formatDuration(ms: number): string {
  const seconds = Math.floor(ms / 1000);
  const mins = Math.floor(seconds / 60);
  const secs = seconds % 60;

  if (mins > 0) {
    return `${mins}m ${secs}s`;
  }
  return `${secs}s`;
}

export default function (pi: ExtensionAPI) {
  let agentStartMs: number | null = null;

  pi.on("agent_start", () => {
    agentStartMs = Date.now();
  });

  pi.on("agent_end", (event, ctx) => {
    if (!ctx.hasUI) return;
    if (agentStartMs === null) return;

    const elapsedMs = Date.now() - agentStartMs;
    agentStartMs = null;
    if (elapsedMs <= 0) return;

    let input = 0;
    let output = 0;
    let cacheRead = 0;
    let cacheWrite = 0;
    let totalTokens = 0;

    for (const message of event.messages) {
      if (!isAssistantMessage(message)) continue;
      input += message.usage.input || 0;
      output += message.usage.output || 0;
      cacheRead += message.usage.cacheRead || 0;
      cacheWrite += message.usage.cacheWrite || 0;
      totalTokens += message.usage.totalTokens || 0;
    }

    if (output <= 0) return;

    const elapsedSeconds = elapsedMs / 1000;
    const tokensPerSecond = output / elapsedSeconds;
    const message = `TPS: ${tokensPerSecond.toFixed(1)} tok/s · took ${formatDuration(elapsedMs)}`;
    ctx.ui.notify(message, "info");
  });
}


================================================
FILE: agents/pi/extensions/session-breakdown.ts
================================================
/**
 * /session-breakdown
 *
 * Interactive TUI that analyzes ~/.pi/agent/sessions (recursively, *.jsonl) and shows
 * last 7/30/90 days of:
 * - sessions/day
 * - messages/day
 * - tokens/day (if available)
 * - cost/day (if available)
 * - model breakdown (sessions/messages/tokens + cost)
 *
 * Graph:
 * - GitHub-contributions-style calendar (weeks x weekdays)
 * - Hue: weighted mix of popular model colors (weighted by the selected metric)
 * - Brightness: selected metric per day (log-scaled)
 */

import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
import { BorderedLoader } from "@mariozechner/pi-coding-agent";
import {
	Key,
	matchesKey,
	sliceByColumn,
	type Component,
	type TUI,
	truncateToWidth,
	visibleWidth,
} from "@mariozechner/pi-tui";
import os from "node:os";
import path from "node:path";
import fs from "node:fs/promises";
import { createReadStream, type Dirent } from "node:fs";
import readline from "node:readline";

type ModelKey = string; // `${provider}/${model}`

interface ParsedSession {
	filePath: string;
	startedAt: Date;
	dayKeyLocal: string; // YYYY-MM-DD (local)
	modelsUsed: Set<ModelKey>;
	messages: number;
	tokens: number;
	totalCost: number;
	costByModel: Map<ModelKey, number>;
	messagesByModel: Map<ModelKey, number>;
	tokensByModel: Map<ModelKey, number>;
}

interface DayAgg {
	date: Date; // local midnight
	dayKeyLocal: string;
	sessions: number;
	messages: number;
	tokens: number;
	totalCost: number;
	costByModel: Map<ModelKey, number>;
	sessionsByModel: Map<ModelKey, number>;
	messagesByModel: Map<ModelKey, number>;
	tokensByModel: Map<ModelKey, number>;
}

interface RangeAgg {
	days: DayAgg[];
	dayByKey: Map<string, DayAgg>;
	sessions: number;
	totalMessages: number;
	totalTokens: number;
	totalCost: number;
	modelCost: Map<ModelKey, number>;
	modelSessions: Map<ModelKey, number>; // number of sessions where model was used
	modelMessages: Map<ModelKey, number>;
	modelTokens: Map<ModelKey, number>;
}

interface RGB {
	r: number;
	g: number;
	b: number;
}

interface BreakdownData {
	generatedAt: Date;
	ranges: Map<number, RangeAgg>;
	palette: {
		modelColors: Map<ModelKey, RGB>;
		otherColor: RGB;
		orderedModels: ModelKey[];
	};
}

const SESSION_ROOT = path.join(os.homedir(), ".pi", "agent", "sessions");
const RANGE_DAYS = [7, 30, 90] as const;

type MeasurementMode = "sessions" | "messages" | "tokens";

type BreakdownProgressPhase = "scan" | "parse" | "finalize";

interface BreakdownProgressState {
	phase: BreakdownProgressPhase;
	foundFiles: number;
	parsedFiles: number;
	totalFiles: number;
	currentFile?: string;
}

function setBorderedLoaderMessage(loader: BorderedLoader, message: string) {
	// BorderedLoader wraps a (Cancellable)Loader which supports setMessage(),
	// but it doesn't expose it publicly. Access the inner loader for progress updates.
	const inner = (loader as any)["loader"]; // eslint-disable-line @typescript-eslint/no-explicit-any
	if (inner && typeof inner.setMessage === "function") {
		inner.setMessage(message);
	}
}

// Dark-ish background and empty cell color (close to GitHub dark)
const DEFAULT_BG: RGB = { r: 13, g: 17, b: 23 };
const EMPTY_CELL_BG: RGB = { r: 22, g: 27, b: 34 };

// Default palette (assigned to top models)
const PALETTE: RGB[] = [
	{ r: 64, g: 196, b: 99 }, // green
	{ r: 47, g: 129, b: 247 }, // blue
	{ r: 163, g: 113, b: 247 }, // purple
	{ r: 255, g: 159, b: 10 }, // orange
	{ r: 244, g: 67, b: 54 }, // red
];

function clamp01(x: number): number {
	return Math.max(0, Math.min(1, x));
}

function lerp(a: number, b: number, t: number): number {
	return a + (b - a) * t;
}

function mixRgb(a: RGB, b: RGB, t: number): RGB {
	return {
		r: Math.round(lerp(a.r, b.r, t)),
		g: Math.round(lerp(a.g, b.g, t)),
		b: Math.round(lerp(a.b, b.b, t)),
	};
}

function weightedMix(colors: Array<{ color: RGB; weight: number }>): RGB {
	let total = 0;
	let r = 0;
	let g = 0;
	let b = 0;
	for (const c of colors) {
		if (!Number.isFinite(c.weight) || c.weight <= 0) continue;
		total += c.weight;
		r += c.color.r * c.weight;
		g += c.color.g * c.weight;
		b += c.color.b * c.weight;
	}
	if (total <= 0) return EMPTY_CELL_BG;
	return { r: Math.round(r / total), g: Math.round(g / total), b: Math.round(b / total) };
}

function ansiBg(rgb: RGB, text: string): string {
	return `\x1b[48;2;${rgb.r};${rgb.g};${rgb.b}m${text}\x1b[0m`;
}

function ansiFg(rgb: RGB, text: string): string {
	return `\x1b[38;2;${rgb.r};${rgb.g};${rgb.b}m${text}\x1b[0m`;
}

function dim(text: string): string {
	return `\x1b[2m${text}\x1b[0m`;
}

function bold(text: string): string {
	return `\x1b[1m${text}\x1b[0m`;
}

function formatCount(n: number): string {
	if (!Number.isFinite(n) || n === 0) return "0";
	if (n >= 1_000_000_000) return `${(n / 1_000_000_000).toFixed(1)}B`;
	if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
	if (n >= 10_000) return `${(n / 1_000).toFixed(1)}K`;
	return n.toLocaleString("en-US");
}

function formatUsd(cost: number): string {
	if (!Number.isFinite(cost)) return "$0.00";
	if (cost >= 1) return `$${cost.toFixed(2)}`;
	if (cost >= 0.1) return `$${cost.toFixed(3)}`;
	return `$${cost.toFixed(4)}`;
}

function padRight(s: string, n: number): string {
	const delta = n - s.length;
	return delta > 0 ? s + " ".repeat(delta) : s;
}

function padLeft(s: string, n: number): string {
	const delta = n - s.length;
	return delta > 0 ? " ".repeat(delta) + s : s;
}

function toLocalDayKey(d: Date): string {
	const yyyy = d.getFullYear();
	const mm = String(d.getMonth() + 1).padStart(2, "0");
	const dd = String(d.getDate()).padStart(2, "0");
	return `${yyyy}-${mm}-${dd}`;
}

function localMidnight(d: Date): Date {
	return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
}

function addDaysLocal(d: Date, days: number): Date {
	const x = new Date(d);
	x.setDate(x.getDate() + days);
	return x;
}

function countDaysInclusiveLocal(start: Date, end: Date): number {
	// Avoid ms-based day math because DST transitions can make a “day” 23/25h in local time.
	let n = 0;
	for (let d = new Date(start); d <= end; d = addDaysLocal(d, 1)) n++;
	return n;
}

function mondayIndex(date: Date): number {
	// Mon=0 .. Sun=6
	return (date.getDay() + 6) % 7;
}

function modelKeyFromParts(provider?: unknown, model?: unknown): ModelKey | null {
	const p = typeof provider === "string" ? provider.trim() : "";
	const m = typeof model === "string" ? model.trim() : "";
	if (!p && !m) return null;
	if (!p) return m;
	if (!m) return p;
	return `${p}/${m}`;
}

function parseSessionStartFromFilename(name: string): Date | null {
	// Example: 2026-02-02T21-52-28-774Z_<uuid>.jsonl
	const m = name.match(/^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z_/);
	if (!m) return null;
	const iso = `${m[1]}T${m[2]}:${m[3]}:${m[4]}.${m[5]}Z`;
	const d = new Date(iso);
	return Number.isFinite(d.getTime()) ? d : null;
}

function extractProviderModelAndUsage(obj: any): { provider?: any; model?: any; modelId?: any; usage?: any } {
	// Session format varies across versions.
	// - Newer: { provider, model, usage } on the message wrapper
	// - Older: { message: { provider, model, usage } }
	const msg = obj?.message;
	return {
		provider: obj?.provider ?? msg?.provider,
		model: obj?.model ?? msg?.model,
		modelId: obj?.modelId ?? msg?.modelId,
		usage: obj?.usage ?? msg?.usage,
	};
}

function extractCostTotal(usage: any): number {
	if (!usage) return 0;
	const c = usage?.cost;
	if (typeof c === "number") return Number.isFinite(c) ? c : 0;
	if (typeof c === "string") {
		const n = Number(c);
		return Number.isFinite(n) ? n : 0;
	}
	const t = c?.total;
	if (typeof t === "number") return Number.isFinite(t) ? t : 0;
	if (typeof t === "string") {
		const n = Number(t);
		return Number.isFinite(n) ? n : 0;
	}
	return 0;
}

function extractTokensTotal(usage: any): number {
	// Usage format varies across providers and pi versions.
	// We try a few common shapes:
	// - { totalTokens }
	// - { total_tokens }
	// - { promptTokens, completionTokens }
	// - { prompt_tokens, completion_tokens }
	// - { input_tokens, output_tokens }
	// - { inputTokens, outputTokens }
	// - { tokens: number | { total } }
	if (!usage) return 0;

	const readNum = (v: any): number => {
		if (typeof v === "number") return Number.isFinite(v) ? v : 0;
		if (typeof v === "string") {
			const n = Number(v);
			return Number.isFinite(n) ? n : 0;
		}
		return 0;
	};

	let total = 0;
	// direct totals
	total =
		readNum(usage?.totalTokens) ||
		readNum(usage?.total_tokens) ||
		readNum(usage?.tokens) ||
		readNum(usage?.tokenCount) ||
		readNum(usage?.token_count);
	if (total > 0) return total;

	// nested tokens object
	total = readNum(usage?.tokens?.total) || readNum(usage?.tokens?.totalTokens) || readNum(usage?.tokens?.total_tokens);
	if (total > 0) return total;

	// sum of parts
	const a =
		readNum(usage?.promptTokens) ||
		readNum(usage?.prompt_tokens) ||
		readNum(usage?.inputTokens) ||
		readNum(usage?.input_tokens);
	const b =
		readNum(usage?.completionTokens) ||
		readNum(usage?.completion_tokens) ||
		readNum(usage?.outputTokens) ||
		readNum(usage?.output_tokens);
	const sum = a + b;
	return sum > 0 ? sum : 0;
}

async function walkSessionFiles(
	root: string,
	startCutoffLocal: Date,
	signal?: AbortSignal,
	onFound?: (found: number) => void,
): Promise<string[]> {
	const out: string[] = [];
	const stack: string[] = [root];
	while (stack.length) {
		if (signal?.aborted) break;
		const dir = stack.pop()!;
		let entries: Dirent[] = [];
		try {
			entries = await fs.readdir(dir, { withFileTypes: true });
		} catch {
			continue;
		}

		for (const ent of entries) {
			if (signal?.aborted) break;
			const p = path.join(dir, ent.name);
			if (ent.isDirectory()) {
				stack.push(p);
				continue;
			}
			if (!ent.isFile() || !ent.name.endsWith(".jsonl")) continue;

			// Prefer filename timestamp, else fall back to mtime.
			const startedAt = parseSessionStartFromFilename(ent.name);
			if (startedAt) {
				if (localMidnight(startedAt) >= startCutoffLocal) {
					out.push(p);
					if (onFound && out.length % 10 === 0) onFound(out.length);
				}
				continue;
			}

			try {
				const st = await fs.stat(p);
				const approx = new Date(st.mtimeMs);
				if (localMidnight(approx) >= startCutoffLocal) {
					out.push(p);
					if (onFound && out.length % 10 === 0) onFound(out.length);
				}
			} catch {
				// ignore
			}
		}
	}
	onFound?.(out.length);
	return out;
}

async function parseSessionFile(filePath: string, signal?: AbortSignal): Promise<ParsedSession | null> {
	const fileName = path.basename(filePath);
	let startedAt = parseSessionStartFromFilename(fileName);
	let currentModel: ModelKey | null = null;

	const modelsUsed = new Set<ModelKey>();
	let messages = 0;
	let tokens = 0;
	let totalCost = 0;
	const costByModel = new Map<ModelKey, number>();
	const messagesByModel = new Map<ModelKey, number>();
	const tokensByModel = new Map<ModelKey, number>();

	const stream = createReadStream(filePath, { encoding: "utf8" });
	const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });

	try {
		for await (const line of rl) {
			if (signal?.aborted) {
				rl.close();
				stream.destroy();
				return null;
			}
			if (!line) continue;
			let obj: any;
			try {
				obj = JSON.parse(line);
			} catch {
				continue;
			}

			if (!startedAt && obj?.type === "session" && typeof obj?.timestamp === "string") {
				const d = new Date(obj.timestamp);
				if (Number.isFinite(d.getTime())) startedAt = d;
				continue;
			}

			if (obj?.type === "model_change") {
				const mk = modelKeyFromParts(obj.provider, obj.modelId);
				if (mk) {
					currentModel = mk;
					modelsUsed.add(mk);
				}
				continue;
			}

			if (obj?.type !== "message") continue;

			const { provider, model, modelId, usage } = extractProviderModelAndUsage(obj);
			const mk =
				modelKeyFromParts(provider, model) ??
				modelKeyFromParts(provider, modelId) ??
				currentModel ??
				"unknown";
			modelsUsed.add(mk);

			messages += 1;
			messagesByModel.set(mk, (messagesByModel.get(mk) ?? 0) + 1);

			const tok = extractTokensTotal(usage);
			if (tok > 0) {
				tokens += tok;
				tokensByModel.set(mk, (tokensByModel.get(mk) ?? 0) + tok);
			}

			const cost = extractCostTotal(usage);
			if (cost > 0) {
				totalCost += cost;
				costByModel.set(mk, (costByModel.get(mk) ?? 0) + cost);
			}
		}
	} finally {
		rl.close();
		stream.destroy();
	}

	if (!startedAt) return null;
	const dayKeyLocal = toLocalDayKey(startedAt);
	return {
		filePath,
		startedAt,
		dayKeyLocal,
		modelsUsed,
		messages,
		tokens,
		totalCost,
		costByModel,
		messagesByModel,
		tokensByModel,
	};
}

function buildRangeAgg(days: number, now: Date): RangeAgg {
	const end = localMidnight(now);
	const start = addDaysLocal(end, -(days - 1));
	const outDays: DayAgg[] = [];
	const dayByKey = new Map<string, DayAgg>();

	for (let i = 0; i < days; i++) {
		const d = addDaysLocal(start, i);
		const dayKeyLocal = toLocalDayKey(d);
		const day: DayAgg = {
			date: d,
			dayKeyLocal,
			sessions: 0,
			messages: 0,
			tokens: 0,
			totalCost: 0,
			costByModel: new Map(),
			sessionsByModel: new Map(),
			messagesByModel: new Map(),
			tokensByModel: new Map(),
		};
		outDays.push(day);
		dayByKey.set(dayKeyLocal, day);
	}

	return {
		days: outDays,
		dayByKey,
		sessions: 0,
		totalMessages: 0,
		totalTokens: 0,
		totalCost: 0,
		modelCost: new Map(),
		modelSessions: new Map(),
		modelMessages: new Map(),
		modelTokens: new Map(),
	};
}

function addSessionToRange(range: RangeAgg, session: ParsedSession): void {
	const day = range.dayByKey.get(session.dayKeyLocal);
	if (!day) return;

	range.sessions += 1;
	range.totalMessages += session.messages;
	range.totalTokens += session.tokens;
	range.totalCost += session.totalCost;
	day.sessions += 1;
	day.messages += session.messages;
	day.tokens += session.tokens;
	day.totalCost += session.totalCost;

	// Sessions-per-model (presence)
	for (const mk of session.modelsUsed) {
		day.sessionsByModel.set(mk, (day.sessionsByModel.get(mk) ?? 0) + 1);
		range.modelSessions.set(mk, (range.modelSessions.get(mk) ?? 0) + 1);
	}

	// Messages-per-model
	for (const [mk, n] of session.messagesByModel.entries()) {
		day.messagesByModel.set(mk, (day.messagesByModel.get(mk) ?? 0) + n);
		range.modelMessages.set(mk, (range.modelMessages.get(mk) ?? 0) + n);
	}

	// Tokens-per-model
	for (const [mk, n] of session.tokensByModel.entries()) {
		day.tokensByModel.set(mk, (day.tokensByModel.get(mk) ?? 0) + n);
		range.modelTokens.set(mk, (range.modelTokens.get(mk) ?? 0) + n);
	}

	// Cost-per-model
	for (const [mk, cost] of session.costByModel.entries()) {
		day.costByModel.set(mk, (day.costByModel.get(mk) ?? 0) + cost);
		range.modelCost.set(mk, (range.modelCost.get(mk) ?? 0) + cost);
	}
}

function sortMapByValueDesc<K extends string>(m: Map<K, number>): Array<{ key: K; value: number }> {
	return [...m.entries()]
		.map(([key, value]) => ({ key, value }))
		.sort((a, b) => b.value - a.value);
}

function choosePaletteFromLast30Days(range30: RangeAgg, topN = 4): {
	modelColors: Map<ModelKey, RGB>;
	otherColor: RGB;
	orderedModels: ModelKey[];
} {
	// Prefer cost if any cost exists, else tokens, else messages, else sessions.
	const costSum = [...range30.modelCost.values()].reduce((a, b) => a + b, 0);
	const popularity =
		costSum > 0
			? range30.modelCost
			: range30.totalTokens > 0
				? range30.modelTokens
				: range30.totalMessages > 0
					? range30.modelMessages
					: range30.modelSessions;

	const sorted = sortMapByValueDesc(popularity);
	const orderedModels = sorted.slice(0, topN).map((x) => x.key);
	const modelColors = new Map<ModelKey, RGB>();
	for (let i = 0; i < orderedModels.length; i++) {
		modelColors.set(orderedModels[i], PALETTE[i % PALETTE.length]);
	}
	return {
		modelColors,
		otherColor: { r: 160, g: 160, b: 160 },
		orderedModels,
	};
}

function dayMixedColor(
	day: DayAgg,
	modelColors: Map<ModelKey, RGB>,
	otherColor: RGB,
	mode: MeasurementMode,
): RGB {
	const parts: Array<{ color: RGB; weight: number }> = [];
	let otherWeight = 0;

	let map: Map<ModelKey, number>;
	if (mode === "tokens") {
		map = day.tokens > 0 ? day.tokensByModel : day.messages > 0 ? day.messagesByModel : day.sessionsByModel;
	} else if (mode === "messages") {
		map = day.messages > 0 ? day.messagesByModel : day.sessionsByModel;
	} else {
		map = day.sessionsByModel;
	}

	for (const [mk, w] of map.entries()) {
		const c = modelColors.get(mk);
		if (c) parts.push({ color: c, weight: w });
		else otherWeight += w;
	}
	if (otherWeight > 0) parts.push({ color: otherColor, weight: otherWeight });
	return weightedMix(parts);
}

function graphMetricForRange(
	range: RangeAgg,
	mode: MeasurementMode,
): { kind: "sessions" | "messages" | "tokens"; max: number; denom: number } {
	if (mode === "tokens") {
		const maxTokens = Math.max(0, ...range.days.map((d) => d.tokens));
		if (maxTokens > 0) return { kind: "tokens", max: maxTokens, denom: Math.log1p(maxTokens) };
		// fall back if tokens aren't available
		mode = "messages";
	}

	if (mode === "messages") {
		const maxMessages = Math.max(0, ...range.days.map((d) => d.messages));
		if (maxMessages > 0) return { kind: "messages", max: maxMessages, denom: Math.log1p(maxMessages) };
		// fall back if messages aren't available
		mode = "sessions";
	}

	const maxSessions = Math.max(0, ...range.days.map((d) => d.sessions));
	return { kind: "sessions", max: maxSessions, denom: Math.log1p(maxSessions) };
}

function weeksForRange(range: RangeAgg): number {
	const days = range.days;
	const start = days[0].date;
	const end = days[days.length - 1].date;
	const gridStart = addDaysLocal(start, -mondayIndex(start));
	const gridEnd = addDaysLocal(end, 6 - mondayIndex(end));
	const totalGridDays = countDaysInclusiveLocal(gridStart, gridEnd);
	return Math.ceil(totalGridDays / 7);
}

function renderGraphLines(
	range: RangeAgg,
	modelColors: Map<ModelKey, RGB>,
	otherColor: RGB,
	mode: MeasurementMode,
	options?: { cellWidth?: number; gap?: number },
): string[] {
	const days = range.days;
	const start = days[0].date;
	const end = days[days.length - 1].date;

	const gridStart = addDaysLocal(start, -mondayIndex(start));
	const gridEnd = addDaysLocal(end, 6 - mondayIndex(end));
	const totalGridDays = countDaysInclusiveLocal(gridStart, gridEnd);
	const weeks = Math.ceil(totalGridDays / 7);

	const cellWidth = Math.max(1, Math.floor(options?.cellWidth ?? 1));
	const gap = Math.max(0, Math.floor(options?.gap ?? 1));
	const block = "█".repeat(cellWidth);
	const gapStr = " ".repeat(gap);

	const metric = graphMetricForRange(range, mode);
	const denom = metric.denom;

	// Label only Mon/Wed/Fri like GitHub (saves space)
	const labelByRow = new Map<number, string>([
		[0, "Mon"],
		[2, "Wed"],
		[4, "Fri"],
	]);

	const lines: string[] = [];
	for (let row = 0; row < 7; row++) {
		const label = labelByRow.get(row);
		let line = label ? padRight(label, 3) + " " : "    ";

		for (let w = 0; w < weeks; w++) {
			const cellDate = addDaysLocal(gridStart, w * 7 + row);
			const inRange = cellDate >= start && cellDate <= end;
			const colGap = w < weeks - 1 ? gapStr : "";
			if (!inRange) {
				line += " ".repeat(cellWidth) + colGap;
				continue;
			}

			const key = toLocalDayKey(cellDate);
			const day = range.dayByKey.get(key);
			const value =
				metric.kind === "tokens"
					? (day?.tokens ?? 0)
					: metric.kind === "messages"
						? (day?.messages ?? 0)
						: (day?.sessions ?? 0);

			if (!day || value <= 0) {
				line += ansiFg(EMPTY_CELL_BG, block) + colGap;
				continue;
			}

			const hue = dayMixedColor(day, modelColors, otherColor, mode);
			let t = denom > 0 ? Math.log1p(value) / denom : 0;
			t = clamp01(t);
			const minVisible = 0.2;
			const intensity = minVisible + (1 - minVisible) * t;
			const rgb = mixRgb(DEFAULT_BG, hue, intensity);
			line += ansiFg(rgb, block) + colGap;
		}

		lines.push(line);
	}

	return lines;
}

function displayModelName(modelKey: string): string {
	const idx = modelKey.indexOf("/");
	return idx === -1 ? modelKey : modelKey.slice(idx + 1);
}

function renderLegendItems(modelColors: Map<ModelKey, RGB>, orderedModels: ModelKey[], otherColor: RGB): string[] {
	const items: string[] = [];
	for (const mk of orderedModels) {
		const c = modelColors.get(mk);
		if (!c) continue;
		items.push(`${ansiFg(c, "█")} ${displayModelName(mk)}`);
	}
	items.push(`${ansiFg(otherColor, "█")} other`);
	return items;
}

function fitRight(text: string, width: number): string {
	if (width <= 0) return "";
	let w = visibleWidth(text);
	let t = text;
	if (w > width) {
		t = sliceByColumn(t, w - width, width, true);
		w = visibleWidth(t);
	}
	return " ".repeat(Math.max(0, width - w)) + t;
}

function renderLegendBlock(leftLabel: string, items: string[], width: number): string[] {
	if (width <= 0) return [];
	if (items.length === 0) return [truncateToWidth(leftLabel, width)];

	const lines: string[] = [];
	// First line: label on left, first item right-aligned into remaining space.
	const leftW = visibleWidth(leftLabel);
	if (leftW >= width) {
		lines.push(truncateToWidth(leftLabel, width));
		// Put all items on their own lines right-aligned.
		for (const it of items) lines.push(fitRight(it, width));
		return lines;
	}

	const remaining = Math.max(0, width - leftW);
	lines.push(leftLabel + fitRight(items[0], remaining));

	for (let i = 1; i < items.length; i++) {
		lines.push(fitRight(items[i], width));
	}
	return lines;
}

function renderModelTable(range: RangeAgg, mode: MeasurementMode, maxRows = 8): string[] {
	// Keep this relatively narrow: model + selected metric + cost + share.
	const metric = graphMetricForRange(range, mode);
	const kind = metric.kind;

	let perModel: Map<ModelKey, number>;
	let total = 0;
	let label = kind;

	if (kind === "tokens") {
		perModel = range.modelTokens;
		total = range.totalTokens;
	} else if (kind === "messages") {
		perModel = range.modelMessages;
		total = range.totalMessages;
	} else {
		perModel = range.modelSessions;
		total = range.sessions;
	}

	const sorted = sortMapByValueDesc(perModel);
	const rows = sorted.slice(0, maxRows);

	const valueWidth = kind === "tokens" ? 10 : 8;
	const modelWidth = Math.min(52, Math.max("model".length, ...rows.map((r) => r.key.length)));

	const lines: string[] = [];
	lines.push(`${padRight("model", modelWidth)}  ${padLeft(label, valueWidth)}  ${padLeft("cost", 10)}  ${padLeft("share", 6)}`);
	lines.push(`${"-".repeat(modelWidth)}  ${"-".repeat(valueWidth)}  ${"-".repeat(10)}  ${"-".repeat(6)}`);

	for (const r of rows) {
		const value = perModel.get(r.key) ?? 0;
		const cost = range.modelCost.get(r.key) ?? 0;
		const share = total > 0 ? `${Math.round((value / total) * 100)}%` : "0%";
		lines.push(
			`${padRight(r.key.slice(0, modelWidth), modelWidth)}  ${padLeft(formatCount(value), valueWidth)}  ${padLeft(formatUsd(cost), 10)}  ${padLeft(share, 6)}`,
		);
	}

	if (sorted.length === 0) {
		lines.push(dim("(no model data found)"));
	}

	return lines;
}

function renderLeftRight(left: string, right: string, width: number): string {
	const leftW = visibleWidth(left);
	if (width <= 0) return "";
	if (leftW >= width) return truncateToWidth(left, width);

	const remaining = width - leftW;
	let rightText = right;
	const rightW = visibleWidth(rightText);
	if (rightW > remaining) {
		// Keep the *rightmost* part visible.
		rightText = sliceByColumn(rightText, rightW - remaining, remaining, true);
	}
	const pad = Math.max(0, remaining - visibleWidth(rightText));
	return left + " ".repeat(pad) + rightText;
}

function rangeSummary(range: RangeAgg, days: number, mode: MeasurementMode): string {
	const avg = range.sessions > 0 ? range.totalCost / range.sessions : 0;
	const costPart = range.totalCost > 0 ? `${formatUsd(range.totalCost)} · avg ${formatUsd(avg)}/session` : `
Download .txt
gitextract_76rbdv8a/

├── .gitignore
├── .gitmodules
├── Makefile
├── README.md
├── agents/
│   ├── AGENTS.md
│   ├── opencode/
│   │   └── opencode.json
│   ├── pi/
│   │   ├── extensions/
│   │   │   ├── agent-profiles.ts
│   │   │   ├── ask.ts
│   │   │   ├── composed-editor/
│   │   │   │   ├── index.ts
│   │   │   │   └── package.json
│   │   │   ├── custom-formatting.ts
│   │   │   ├── exit-command.ts
│   │   │   ├── handoff.ts
│   │   │   ├── lsp/
│   │   │   │   ├── index.ts
│   │   │   │   └── lsp-config.ts
│   │   │   ├── notify.ts
│   │   │   ├── pi-codemode/
│   │   │   │   ├── README.md
│   │   │   │   ├── executor.jsonc
│   │   │   │   ├── index.ts
│   │   │   │   ├── package.json
│   │   │   │   ├── src/
│   │   │   │   │   ├── builtins.ts
│   │   │   │   │   ├── codemode.ts
│   │   │   │   │   ├── executor-cache.ts
│   │   │   │   │   ├── fff-plugin.ts
│   │   │   │   │   ├── fff.ts
│   │   │   │   │   ├── jj-plugin.ts
│   │   │   │   │   ├── npm-plugin.ts
│   │   │   │   │   ├── pi-plugin.ts
│   │   │   │   │   ├── read.ts
│   │   │   │   │   ├── render.ts
│   │   │   │   │   ├── runtime.ts
│   │   │   │   │   ├── sandbox-cache.ts
│   │   │   │   │   ├── source-config.ts
│   │   │   │   │   ├── source-hydrate.ts
│   │   │   │   │   ├── trace.ts
│   │   │   │   │   ├── turndown.d.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   ├── util.ts
│   │   │   │   │   └── webfetch.ts
│   │   │   │   └── tsconfig.json
│   │   │   ├── prompt-timer.ts
│   │   │   ├── session-breakdown.ts
│   │   │   ├── webfetch.ts
│   │   │   └── whimsical-timer.ts
│   │   ├── mcp.json
│   │   ├── models.json
│   │   ├── package.json
│   │   ├── settings.json
│   │   ├── themes/
│   │   │   └── rose-pine-dawn.json
│   │   └── treesitter.ts
│   └── skills/
│       ├── build-feature/
│       │   └── SKILL.md
│       ├── code-review/
│       │   └── SKILL.md
│       ├── debugging/
│       │   └── SKILL.md
│       ├── deslop/
│       │   └── SKILL.md
│       ├── effect-best-practices/
│       │   ├── SKILL.md
│       │   └── references/
│       │       ├── anti-patterns.md
│       │       ├── effect-atom-patterns.md
│       │       ├── error-patterns.md
│       │       ├── layer-patterns.md
│       │       ├── observability-patterns.md
│       │       ├── rpc-cluster-patterns.md
│       │       ├── schema-patterns.md
│       │       └── service-patterns.md
│       ├── emil-design-eng/
│       │   └── SKILL.md
│       ├── frontend-design/
│       │   ├── LICENSE.txt
│       │   └── SKILL.md
│       ├── grill-me/
│       │   └── SKILL.md
│       ├── initz/
│       │   └── SKILL.md
│       ├── jj/
│       │   └── SKILL.md
│       ├── pi-improvements/
│       │   └── SKILL.md
│       ├── react-best-practices/
│       │   ├── AGENTS.md
│       │   ├── README.md
│       │   ├── SKILL.md
│       │   ├── metadata.json
│       │   └── rules/
│       │       ├── _sections.md
│       │       ├── _template.md
│       │       ├── advanced-event-handler-refs.md
│       │       ├── advanced-use-latest.md
│       │       ├── async-api-routes.md
│       │       ├── async-defer-await.md
│       │       ├── async-dependencies.md
│       │       ├── async-parallel.md
│       │       ├── async-suspense-boundaries.md
│       │       ├── bundle-barrel-imports.md
│       │       ├── bundle-conditional.md
│       │       ├── bundle-defer-third-party.md
│       │       ├── bundle-dynamic-imports.md
│       │       ├── bundle-preload.md
│       │       ├── client-event-listeners.md
│       │       ├── client-localstorage-schema.md
│       │       ├── client-passive-event-listeners.md
│       │       ├── client-swr-dedup.md
│       │       ├── js-batch-dom-css.md
│       │       ├── js-cache-function-results.md
│       │       ├── js-cache-property-access.md
│       │       ├── js-cache-storage.md
│       │       ├── js-combine-iterations.md
│       │       ├── js-early-exit.md
│       │       ├── js-hoist-regexp.md
│       │       ├── js-index-maps.md
│       │       ├── js-length-check-first.md
│       │       ├── js-min-max-loop.md
│       │       ├── js-set-map-lookups.md
│       │       ├── js-tosorted-immutable.md
│       │       ├── rendering-activity.md
│       │       ├── rendering-animate-svg-wrapper.md
│       │       ├── rendering-conditional-render.md
│       │       ├── rendering-content-visibility.md
│       │       ├── rendering-hoist-jsx.md
│       │       ├── rendering-hydration-no-flicker.md
│       │       ├── rendering-svg-precision.md
│       │       ├── rendering-usetransition-loading.md
│       │       ├── rerender-defer-reads.md
│       │       ├── rerender-dependencies.md
│       │       ├── rerender-derived-state.md
│       │       ├── rerender-functional-setstate.md
│       │       ├── rerender-lazy-state-init.md
│       │       ├── rerender-memo-with-default-value.md
│       │       ├── rerender-memo.md
│       │       ├── rerender-simple-expression-in-memo.md
│       │       ├── rerender-transitions.md
│       │       ├── server-after-nonblocking.md
│       │       ├── server-auth-actions.md
│       │       ├── server-cache-lru.md
│       │       ├── server-cache-react.md
│       │       ├── server-dedup-props.md
│       │       ├── server-parallel-fetching.md
│       │       └── server-serialization.md
│       ├── root-cause-tracing/
│       │   └── SKILL.md
│       ├── session-retrospective/
│       │   └── SKILL.md
│       ├── web-design-guidelines/
│       │   └── SKILL.md
│       └── wydt/
│           └── SKILL.md
├── direnv/
│   └── direnvrc
├── fish/
│   ├── conf.d/
│   │   ├── abbr.fish
│   │   ├── alias.fish
│   │   ├── colour.fish
│   │   ├── foreign.fish
│   │   ├── manpage.fish
│   │   └── vi-mode.fish
│   ├── config.fish
│   ├── fish_plugins
│   ├── fish_variables
│   └── functions/
│       ├── fenv.apply.fish
│       ├── fenv.fish
│       ├── fenv.main.fish
│       ├── fenv.parse.after.fish
│       ├── fenv.parse.before.fish
│       ├── fenv.parse.diff.fish
│       └── fenv.parse.divider.fish
├── flake.nix
├── ghostty/
│   └── config
├── gitconfig/
│   └── .gitconfig
├── helix/
│   ├── config.toml
│   ├── languages.toml
│   ├── runtime/
│   │   └── queries/
│   │       └── typst/
│   │           └── highlights.scm
│   └── themes/
│       └── my_rose_pine.toml
├── improvement.md
├── jjui/
│   ├── config.toml
│   └── themes/
│       └── rose-pine-dawn.toml
├── kitty/
│   ├── kitty.conf
│   ├── launch.conf
│   ├── rose-pine-dawn.conf
│   └── rose-pine.conf
├── legacy/
│   ├── awesome/
│   │   └── .config/
│   │       └── awesome/
│   │           ├── keybinds/
│   │           │   ├── bindtotags.lua
│   │           │   ├── clientbuttons.lua
│   │           │   ├── clientkeys.lua
│   │           │   ├── globalkeys.lua
│   │           │   └── mediakeys.lua
│   │           ├── main/
│   │           │   ├── autostart.lua
│   │           │   ├── error-handling.lua
│   │           │   ├── exitscreen.lua
│   │           │   ├── helpers.lua
│   │           │   ├── json.lua
│   │           │   ├── layouts.lua
│   │           │   ├── menu.lua
│   │           │   ├── rules.lua
│   │           │   ├── signals.lua
│   │           │   ├── tags.lua
│   │           │   ├── titlebar.lua
│   │           │   ├── variables.lua
│   │           │   └── volume-widget/
│   │           │       └── init.lua
│   │           ├── rc.lua
│   │           ├── statusbar/
│   │           │   ├── init.lua
│   │           │   └── modules/
│   │           │       ├── battery/
│   │           │       │   └── init.lua
│   │           │       ├── clock/
│   │           │       │   └── init.lua
│   │           │       ├── cpu/
│   │           │       │   └── init.lua
│   │           │       ├── launcher.lua
│   │           │       ├── memory/
│   │           │       │   └── init.lua
│   │           │       ├── netspeed/
│   │           │       │   └── init.lua
│   │           │       ├── systray.lua
│   │           │       ├── taglist.lua
│   │           │       ├── temp/
│   │           │       │   └── init.lua
│   │           │       ├── todo/
│   │           │       │   └── init.lua
│   │           │       └── volume/
│   │           │           └── init.lua
│   │           └── themes/
│   │               └── main/
│   │                   ├── colours.lua
│   │                   ├── elements.lua
│   │                   ├── naughty.lua
│   │                   └── theme.lua
│   ├── fcitx5/
│   │   └── .config/
│   │       └── fcitx5/
│   │           ├── conf/
│   │           │   ├── cached_layouts
│   │           │   ├── classicui.conf
│   │           │   ├── clipboard.conf
│   │           │   ├── imselector.conf
│   │           │   ├── keyboard-longpress.conf
│   │           │   ├── keyboard.conf
│   │           │   ├── mozc.conf
│   │           │   ├── notifications.conf
│   │           │   ├── xcb.conf
│   │           │   └── xim.conf
│   │           ├── config
│   │           ├── profile
│   │           └── profile_KrsNBN
│   ├── flameshot/
│   │   └── .config/
│   │       └── flameshot/
│   │           └── flameshot.ini
│   ├── kitty/
│   │   └── .config/
│   │       └── kitty/
│   │           ├── gitgud-dark.conf
│   │           ├── gruvy.conf
│   │           ├── icy.conf
│   │           ├── kitty.conf
│   │           └── visual-studio-dark.conf
│   ├── lf/
│   │   └── .config/
│   │       └── lf/
│   │           ├── lfrc
│   │           └── preview
│   ├── pages/
│   │   ├── chrome-page/
│   │   │   ├── index.html
│   │   │   ├── main.js
│   │   │   ├── manifest.json
│   │   │   └── style.css
│   │   ├── ryuko/
│   │   │   └── slim.theme
│   │   ├── startpage/
│   │   │   ├── index.html
│   │   │   ├── main.js
│   │   │   ├── manifest.json
│   │   │   └── style.css
│   │   └── startpage-v2/
│   │       ├── index.html
│   │       ├── main.js
│   │       ├── manifest.json
│   │       ├── startpage.xpi
│   │       ├── style.css
│   │       └── test.vue
│   ├── scripts/
│   │   └── .scripts/
│   │       ├── extract
│   │       ├── launcher
│   │       └── lf
│   ├── tmux/
│   │   └── .tmux.conf
│   └── vscode/
│       └── .config/
│           └── Code/
│               └── User/
│                   ├── keybindings.json
│                   └── settings.json
├── misc/
│   ├── .bashrc
│   └── .profile
├── modules/
│   ├── brews.nix
│   ├── casks.nix
│   ├── darwin-config.nix
│   ├── darwin-home.nix
│   ├── darwin-packages.nix
│   ├── git.nix
│   ├── gpg.nix
│   ├── home-common.nix
│   ├── linux-home.nix
│   ├── linux-packages.nix
│   ├── linux-terminals.nix
│   └── packages.nix
├── nushell/
│   ├── ai.nu
│   ├── alias.nu
│   ├── bash-env.nu
│   ├── config.nu
│   ├── rose-pine-dawn.nu
│   ├── rose-pine-moon.nu
│   ├── vendor/
│   │   └── autoload/
│   │       └── starship.nu
│   └── zoxide.nu
├── nvim/
│   ├── init.lua
│   ├── lazy-lock.json
│   ├── lua/
│   │   ├── config/
│   │   │   ├── autocmds.lua
│   │   │   ├── lazy.lua
│   │   │   ├── lsp.lua
│   │   │   ├── mappings.lua
│   │   │   ├── options.lua
│   │   │   └── utils.lua
│   │   └── plugins/
│   │       ├── align.lua
│   │       ├── cmp.lua
│   │       ├── colorscheme.lua
│   │       ├── conform.lua
│   │       ├── dropbar.lua
│   │       ├── fff.lua
│   │       ├── flash.lua
│   │       ├── flutter-tools.off.lua
│   │       ├── gitsigns.lua
│   │       ├── lua-ls.lua
│   │       ├── markdown.lua
│   │       ├── mason-lsp.lua
│   │       ├── mason.lua
│   │       ├── mini-ai.lua
│   │       ├── mini-surround.lua
│   │       ├── neo-tree.lua
│   │       ├── nvim-ts-autotag.lua
│   │       ├── obsidian.lua
│   │       ├── pairs.lua
│   │       ├── qf.lua
│   │       ├── snacks.lua
│   │       ├── statuscolumn.lua
│   │       ├── supermaven.lua
│   │       ├── treesitter.lua
│   │       ├── ts-comments.lua
│   │       ├── typescript.lua
│   │       ├── typst.lua
│   │       ├── ufo.lua
│   │       └── which-key.lua
│   └── queries/
│       └── blade/
│           ├── highlights.scm
│           └── injections.scm
├── wezterm/
│   └── wezterm.lua
├── yazi/
│   └── yazi.toml
└── zellij/
    ├── config.kdl
    ├── layouts/
    │   └── plain.kdl
    └── themes/
        ├── rose-pine-dawn.kdl
        └── rose-pine.kdl
Download .txt
SYMBOL INDEX (261 symbols across 30 files)

FILE: agents/pi/extensions/agent-profiles.ts
  type AgentProfile (line 46) | interface AgentProfile {
  constant DEFAULT_TOOLS (line 55) | const DEFAULT_TOOLS = ["read", "bash", "edit", "write", "grep", "find", ...
  constant DEFAULT_AGENT (line 58) | const DEFAULT_AGENT: AgentProfile = {
  function parseFrontmatter (line 69) | function parseFrontmatter(content: string): {
  function loadAgentsFromDir (line 111) | function loadAgentsFromDir(dir: string): Map<string, AgentProfile> {
  function loadAgents (line 149) | function loadAgents(cwd: string): Map<string, AgentProfile> {
  function getEffectiveTools (line 175) | function getEffectiveTools(agent: AgentProfile | undefined): string[] {
  function agentProfilesExtension (line 191) | function agentProfilesExtension(pi: ExtensionAPI) {

FILE: agents/pi/extensions/ask.ts
  type AskDetails (line 49) | interface AskDetails {
  type MultiAskDetails (line 56) | interface MultiAskDetails {
  type QuestionState (line 60) | interface QuestionState {
  function askToolExtension (line 68) | function askToolExtension(pi: ExtensionAPI): void {
  function handleSingleQuestion (line 129) | async function handleSingleQuestion(
  function handleMultipleQuestions (line 324) | async function handleMultipleQuestions(

FILE: agents/pi/extensions/composed-editor/index.ts
  function composedEditorExtension (line 24) | function composedEditorExtension(pi: ExtensionAPI) {

FILE: agents/pi/extensions/handoff.ts
  constant SYSTEM_PROMPT (line 19) | const SYSTEM_PROMPT = `You are a context transfer assistant. Given a con...

FILE: agents/pi/extensions/lsp/index.ts
  constant DIAGNOSTICS_TIMEOUT_MS (line 26) | const DIAGNOSTICS_TIMEOUT_MS = 5000;
  constant DIAGNOSTICS_DEBOUNCE_MS (line 27) | const DIAGNOSTICS_DEBOUNCE_MS = 150;
  constant LSP_CONNECTION_TIMEOUT_MS (line 28) | const LSP_CONNECTION_TIMEOUT_MS = 5000;
  type Diagnostic (line 30) | type Diagnostic = VSCodeDiagnostic;
  type LspConnection (line 32) | interface LspConnection {
  type LspStatus (line 45) | interface LspStatus {
  class LspConnectionManager (line 56) | class LspConnectionManager {
    method getOrCreateConnections (line 60) | async getOrCreateConnections(
    method createConnection (line 115) | private async createConnection(
    method initializeConnection (line 209) | private async initializeConnection(
    method touchFile (line 259) | async touchFile(
    method getDiagnostics (line 340) | getDiagnostics(conn: LspConnection, filePath: string): Diagnostic[] {
    method getAllDiagnostics (line 345) | getAllDiagnostics(filePath: string): { conn: LspConnection; diagnostic...
    method shutdown (line 357) | async shutdown(conn: LspConnection): Promise<void> {
    method shutdownAll (line 369) | async shutdownAll(): Promise<void> {
    method killConnection (line 375) | killConnection(key: string): boolean {
    method getStatus (line 390) | getStatus(): LspStatus[] {
    method normalizePath (line 403) | private normalizePath(filePath: string): string {
  function extractFileFromEvent (line 410) | function extractFileFromEvent(event: ToolResultEvent): { path: string; i...
  function formatDiagnostics (line 420) | function formatDiagnostics(diagnostics: Diagnostic[]): string {
  function formatDuration (line 435) | function formatDuration(ms: number): string {

FILE: agents/pi/extensions/lsp/lsp-config.ts
  constant MASON_BIN_PATH (line 17) | const MASON_BIN_PATH = resolve(homedir(), ".local/share/nvim/mason/bin");
  type LspHandle (line 19) | interface LspHandle {
  type RootFunction (line 24) | type RootFunction = (file: string, cwd: string) => Promise<string | unde...
  type LspServerInfo (line 26) | interface LspServerInfo {
  constant LANGUAGE_MAP (line 34) | const LANGUAGE_MAP: Record<string, string> = {
  function pathExists (line 114) | async function pathExists(path: string): Promise<boolean> {
  function which (line 126) | async function which(bin: string): Promise<string | undefined> {
  function nearestRoot (line 145) | function nearestRoot(includePatterns: string[], excludePatterns?: string...
  function createHandle (line 181) | function createHandle(
  constant LSP_SERVERS (line 195) | const LSP_SERVERS: LspServerInfo[] = [
  method spawn (line 212) | async spawn(root, cwd) {
  method spawn (line 254) | async spawn(root) {
  method spawn (line 289) | async spawn(root) {
  method spawn (line 314) | async spawn(root) {
  method spawn (line 326) | async spawn(root) {
  method spawn (line 345) | async spawn(root) {
  method spawn (line 392) | async spawn(root) {
  method spawn (line 404) | async spawn(root) {
  method spawn (line 423) | async spawn(root) {
  method spawn (line 442) | async spawn(root) {
  method spawn (line 461) | async spawn(root, cwd) {
  method spawn (line 487) | async spawn(root) {
  method spawn (line 505) | async spawn(root) {
  method spawn (line 517) | async spawn(root) {
  method spawn (line 529) | async spawn(root) {
  method spawn (line 541) | async spawn(root) {
  method spawn (line 559) | async spawn(root) {
  method spawn (line 571) | async spawn(root) {
  method spawn (line 583) | async spawn(root) {
  method spawn (line 595) | async spawn(root) {
  method spawn (line 607) | async spawn(root) {
  method spawn (line 619) | async spawn(root) {
  method spawn (line 631) | async spawn(root) {
  method spawn (line 643) | async spawn(root) {
  method spawn (line 655) | async spawn(root) {
  method spawn (line 667) | async spawn(root) {
  method spawn (line 679) | async spawn(root) {
  method spawn (line 691) | async spawn(root) {
  method spawn (line 703) | async spawn(root) {
  method spawn (line 715) | async spawn(root) {
  method spawn (line 727) | async spawn(root) {
  method spawn (line 744) | async spawn(root) {

FILE: agents/pi/extensions/notify.ts
  function windowsToastScript (line 13) | function windowsToastScript(title: string, body: string): string {
  function notifyOSC777 (line 26) | function notifyOSC777(title: string, body: string): void {
  function notifyOSC99 (line 30) | function notifyOSC99(title: string, body: string): void {
  function notifyWindows (line 36) | function notifyWindows(title: string, body: string): void {
  function notify (line 41) | function notify(title: string, body: string): void {

FILE: agents/pi/extensions/pi-codemode/index.ts
  function registerCodemode (line 7) | function registerCodemode(pi: ExtensionAPI) {

FILE: agents/pi/extensions/pi-codemode/src/builtins.ts
  type BuiltinTool (line 15) | type BuiltinTool = {
  constant BASH_COMMAND_WHITELIST (line 23) | const BASH_COMMAND_WHITELIST = new Set([
  function extractCommandName (line 49) | function extractCommandName(command: string): string | null {
  function createWhitelistedBashTool (line 62) | function createWhitelistedBashTool(cwd: string): BuiltinTool {
  type BuiltinToolset (line 117) | type BuiltinToolset = Record<BuiltinToolName, BuiltinTool>;
  constant PI_SIGNATURES (line 119) | const PI_SIGNATURES = [
  constant FFF_SIGNATURES (line 130) | const FFF_SIGNATURES = [
  constant META_APIS (line 138) | const META_APIS = ["tools.list()", "tools.schema(name)", "tools.definiti...
  function createBuiltinToolset (line 140) | function createBuiltinToolset(cwd: string) {
  function buildCodemodeApiPrompt (line 153) | function buildCodemodeApiPrompt(): string {

FILE: agents/pi/extensions/pi-codemode/src/codemode.ts
  function createCodemodeTool (line 16) | function createCodemodeTool(): ToolDefinition<typeof codemodeSchema, Cod...

FILE: agents/pi/extensions/pi-codemode/src/executor-cache.ts
  type CachedExecutor (line 11) | type CachedExecutor = {

FILE: agents/pi/extensions/pi-codemode/src/fff.ts
  function getFinder (line 10) | async function getFinder(cwd: string, searchPath?: string): Promise<File...
  function initFinder (line 22) | async function initFinder(cwd: string, searchPath?: string): Promise<voi...
  function destroyAllFinders (line 26) | function destroyAllFinders(): void {
  type FffBuiltinToolset (line 189) | type FffBuiltinToolset = Record<FffToolName, BuiltinTool>;
  function createFffBuiltinToolset (line 191) | function createFffBuiltinToolset(cwd: string): FffBuiltinToolset {

FILE: agents/pi/extensions/pi-codemode/src/read.ts
  constant CUSTOM_MAX_LINES (line 8) | const CUSTOM_MAX_LINES = 100_000;
  constant CUSTOM_MAX_BYTES (line 9) | const CUSTOM_MAX_BYTES = 10 * 1024 * 1024;
  constant IMAGE_MIME_TYPES (line 11) | const IMAGE_MIME_TYPES: Record<string, string> = {
  function isImageFile (line 19) | function isImageFile(filePath: string): string | null {
  function formatSize (line 24) | function formatSize(bytes: number): string {
  type ReadToolOptions (line 38) | interface ReadToolOptions {
  function createCustomReadTool (line 43) | function createCustomReadTool(cwd: string, options?: ReadToolOptions) {
  type TruncationResult (line 141) | interface TruncationResult {
  type TruncationOptions (line 149) | interface TruncationOptions {
  function truncateHead (line 154) | function truncateHead(content: string, options: TruncationOptions): Trun...

FILE: agents/pi/extensions/pi-codemode/src/render.ts
  function renderCodemodeCall (line 18) | function renderCodemodeCall(code: string, theme: Theme): Text {
  function renderCodemodeResult (line 29) | function renderCodemodeResult(trace: CodemodeTrace, expanded: boolean, t...

FILE: agents/pi/extensions/pi-codemode/src/runtime.ts
  constant DEFAULT_TIMEOUT_MS (line 7) | const DEFAULT_TIMEOUT_MS = 30_000;
  constant MAX_CODE_SIZE (line 8) | const MAX_CODE_SIZE = 100_000;
  type RuntimeOptions (line 10) | type RuntimeOptions = {
  type CodemodeExecutionResult (line 19) | type CodemodeExecutionResult = {
  constant CODE_PREFIX (line 93) | const CODE_PREFIX = [
  constant CODE_POSTFIX (line 130) | const CODE_POSTFIX = [

FILE: agents/pi/extensions/pi-codemode/src/sandbox-cache.ts
  type SandboxDelegates (line 5) | type SandboxDelegates = {
  type SandboxEntry (line 11) | type SandboxEntry = {

FILE: agents/pi/extensions/pi-codemode/src/source-config.ts
  constant SECRET_REF_PREFIX (line 6) | const SECRET_REF_PREFIX = "secret-public-ref:";
  type UnknownRecord (line 8) | type UnknownRecord = Record<string, unknown>;
  type HeaderSecretRef (line 10) | type HeaderSecretRef = { secretId: string; prefix?: string };
  type PluginHeaderValue (line 11) | type PluginHeaderValue = string | HeaderSecretRef;
  type OpenApiSourceConfig (line 13) | type OpenApiSourceConfig = {
  type GraphqlSourceConfig (line 21) | type GraphqlSourceConfig = {
  type McpRemoteSourceConfig (line 29) | type McpRemoteSourceConfig = {
  type McpStdioSourceConfig (line 40) | type McpStdioSourceConfig = {
  type SupportedSourceConfig (line 51) | type SupportedSourceConfig =
  type UnsupportedSourceConfig (line 57) | type UnsupportedSourceConfig = {
  type LoadedSourceConfig (line 64) | type LoadedSourceConfig = {

FILE: agents/pi/extensions/pi-codemode/src/source-hydrate.ts
  type ExecutorWithPlugins (line 4) | type ExecutorWithPlugins = Executor & {
  type HydrateOptions (line 10) | type HydrateOptions = {

FILE: agents/pi/extensions/pi-codemode/src/trace.ts
  class CodemodeTraceRecorder (line 30) | class CodemodeTraceRecorder {
    method constructor (line 35) | constructor(input: { cwd: string; code: string }) {
    method log (line 46) | log(line: string): void {
    method startStep (line 50) | startStep(input: { label: string; toolPath: string; input: unknown }):...
    method finishStep (line 65) | finishStep(id: string, output?: ToolResultSnapshot, error?: string): v...
    method finish (line 86) | finish(input: { status: CodemodeTrace["status"]; value?: unknown; erro...

FILE: agents/pi/extensions/pi-codemode/src/turndown.d.ts
  class TurndownService (line 2) | class TurndownService {

FILE: agents/pi/extensions/pi-codemode/src/types.ts
  type BuiltinToolName (line 4) | type BuiltinToolName = (typeof builtinToolNames)[number];
  type FffToolName (line 13) | type FffToolName = (typeof fffToolNames)[number];
  type ToolResultSnapshot (line 15) | type ToolResultSnapshot = {
  type TraceStep (line 22) | type TraceStep = {
  type CodemodeTrace (line 34) | type CodemodeTrace = {
  type CodemodeResultDetails (line 46) | type CodemodeResultDetails = {

FILE: agents/pi/extensions/pi-codemode/src/webfetch.ts
  type WebfetchInput (line 3) | type WebfetchInput = {
  constant MAX_RESPONSE_SIZE (line 9) | const MAX_RESPONSE_SIZE = 5 * 1024 * 1024;
  constant DEFAULT_TIMEOUT (line 10) | const DEFAULT_TIMEOUT = 30 * 1000;
  constant MAX_TIMEOUT (line 11) | const MAX_TIMEOUT = 120 * 1000;
  function htmlToText (line 16) | function htmlToText(html: string): string {
  function htmlToMarkdown (line 38) | function htmlToMarkdown(html: string): string {
  function webfetch (line 46) | async function webfetch(

FILE: agents/pi/extensions/prompt-timer.ts
  function isAssistantMessage (line 4) | function isAssistantMessage(message: unknown): message is AssistantMessa...
  function formatDuration (line 10) | function formatDuration(ms: number): string {

FILE: agents/pi/extensions/session-breakdown.ts
  type ModelKey (line 35) | type ModelKey = string;
  type ParsedSession (line 37) | interface ParsedSession {
  type DayAgg (line 50) | interface DayAgg {
  type RangeAgg (line 63) | interface RangeAgg {
  type RGB (line 76) | interface RGB {
  type BreakdownData (line 82) | interface BreakdownData {
  constant SESSION_ROOT (line 92) | const SESSION_ROOT = path.join(os.homedir(), ".pi", "agent", "sessions");
  constant RANGE_DAYS (line 93) | const RANGE_DAYS = [7, 30, 90] as const;
  type MeasurementMode (line 95) | type MeasurementMode = "sessions" | "messages" | "tokens";
  type BreakdownProgressPhase (line 97) | type BreakdownProgressPhase = "scan" | "parse" | "finalize";
  type BreakdownProgressState (line 99) | interface BreakdownProgressState {
  function setBorderedLoaderMessage (line 107) | function setBorderedLoaderMessage(loader: BorderedLoader, message: strin...
  constant DEFAULT_BG (line 117) | const DEFAULT_BG: RGB = { r: 13, g: 17, b: 23 };
  constant EMPTY_CELL_BG (line 118) | const EMPTY_CELL_BG: RGB = { r: 22, g: 27, b: 34 };
  constant PALETTE (line 121) | const PALETTE: RGB[] = [
  function clamp01 (line 129) | function clamp01(x: number): number {
  function lerp (line 133) | function lerp(a: number, b: number, t: number): number {
  function mixRgb (line 137) | function mixRgb(a: RGB, b: RGB, t: number): RGB {
  function weightedMix (line 145) | function weightedMix(colors: Array<{ color: RGB; weight: number }>): RGB {
  function ansiBg (line 161) | function ansiBg(rgb: RGB, text: string): string {
  function ansiFg (line 165) | function ansiFg(rgb: RGB, text: string): string {
  function dim (line 169) | function dim(text: string): string {
  function bold (line 173) | function bold(text: string): string {
  function formatCount (line 177) | function formatCount(n: number): string {
  function formatUsd (line 185) | function formatUsd(cost: number): string {
  function padRight (line 192) | function padRight(s: string, n: number): string {
  function padLeft (line 197) | function padLeft(s: string, n: number): string {
  function toLocalDayKey (line 202) | function toLocalDayKey(d: Date): string {
  function localMidnight (line 209) | function localMidnight(d: Date): Date {
  function addDaysLocal (line 213) | function addDaysLocal(d: Date, days: number): Date {
  function countDaysInclusiveLocal (line 219) | function countDaysInclusiveLocal(start: Date, end: Date): number {
  function mondayIndex (line 226) | function mondayIndex(date: Date): number {
  function modelKeyFromParts (line 231) | function modelKeyFromParts(provider?: unknown, model?: unknown): ModelKe...
  function parseSessionStartFromFilename (line 240) | function parseSessionStartFromFilename(name: string): Date | null {
  function extractProviderModelAndUsage (line 249) | function extractProviderModelAndUsage(obj: any): { provider?: any; model...
  function extractCostTotal (line 262) | function extractCostTotal(usage: any): number {
  function extractTokensTotal (line 279) | function extractTokensTotal(usage: any): number {
  function walkSessionFiles (line 329) | async function walkSessionFiles(
  function parseSessionFile (line 382) | async function parseSessionFile(filePath: string, signal?: AbortSignal):...
  function buildRangeAgg (line 474) | function buildRangeAgg(days: number, now: Date): RangeAgg {
  function addSessionToRange (line 513) | function addSessionToRange(range: RangeAgg, session: ParsedSession): void {
  function sortMapByValueDesc (line 551) | function sortMapByValueDesc<K extends string>(m: Map<K, number>): Array<...
  function choosePaletteFromLast30Days (line 557) | function choosePaletteFromLast30Days(range30: RangeAgg, topN = 4): {
  function dayMixedColor (line 586) | function dayMixedColor(
  function graphMetricForRange (line 613) | function graphMetricForRange(
  function weeksForRange (line 635) | function weeksForRange(range: RangeAgg): number {
  function renderGraphLines (line 645) | function renderGraphLines(
  function displayModelName (line 719) | function displayModelName(modelKey: string): string {
  function renderLegendItems (line 724) | function renderLegendItems(modelColors: Map<ModelKey, RGB>, orderedModel...
  function fitRight (line 735) | function fitRight(text: string, width: number): string {
  function renderLegendBlock (line 746) | function renderLegendBlock(leftLabel: string, items: string[], width: nu...
  function renderModelTable (line 769) | function renderModelTable(range: RangeAgg, mode: MeasurementMode, maxRow...
  function renderLeftRight (line 815) | function renderLeftRight(left: string, right: string, width: number): st...
  function rangeSummary (line 831) | function rangeSummary(range: RangeAgg, days: number, mode: MeasurementMo...
  function computeBreakdown (line 844) | async function computeBreakdown(
  class BreakdownComponent (line 894) | class BreakdownComponent implements Component {
    method constructor (line 903) | constructor(data: BreakdownData, tui: TUI, onDone: () => void) {
    method invalidate (line 909) | invalidate(): void {
    method handleInput (line 914) | handleInput(data: string): void {
    method render (line 961) | render(width: number): string[] {
  function sessionBreakdownExtension (line 1064) | function sessionBreakdownExtension(pi: ExtensionAPI) {

FILE: agents/pi/extensions/webfetch.ts
  constant MAX_RESPONSE_SIZE (line 13) | const MAX_RESPONSE_SIZE = 5 * 1024 * 1024;
  constant DEFAULT_TIMEOUT (line 14) | const DEFAULT_TIMEOUT = 30 * 1000;
  constant MAX_TIMEOUT (line 15) | const MAX_TIMEOUT = 120 * 1000;
  method execute (line 57) | async execute(_toolCallId, params, signal, _onUpdate, ctx) {
  function stripMediaTags (line 218) | function stripMediaTags(html: string): string {
  function htmlToText (line 239) | function htmlToText(html: string): string {

FILE: agents/pi/extensions/whimsical-timer.ts
  function pickRandom (line 123) | function pickRandom(): string {
  function formatDuration (line 127) | function formatDuration(ms: number): string {
  function isAssistantMessage (line 135) | function isAssistantMessage(message: unknown): message is AssistantMessa...

FILE: agents/pi/treesitter.ts
  type ParserConfig (line 10) | interface ParserConfig {
  type Symbol (line 21) | interface Symbol {
  class LRUCache (line 30) | class LRUCache<K, V> {
    method constructor (line 34) | constructor(maxSize: number) {
    method get (line 38) | get(key: K): V | undefined {
    method set (line 48) | set(key: K, value: V): void {
    method has (line 61) | has(key: K): boolean {
    method clear (line 65) | clear(): void {
    method size (line 69) | get size(): number {
  function getParsersDir (line 80) | async function getParsersDir(): Promise<string> {
  function getQueriesDir (line 88) | async function getQueriesDir(): Promise<string> {
  function downloadFile (line 96) | async function downloadFile(url: string, dest: string): Promise<boolean> {
  function ensureParser (line 121) | async function ensureParser(config: ParserConfig): Promise<string | null> {
  function walkDir (line 150) | async function walkDir(dir: string, extensions: string[], files: string[...
  function findFiles (line 173) | async function findFiles(cwd: string, extensions: string[]): Promise<str...
  function readQueryFile (line 177) | async function readQueryFile(filePath: string): Promise<string | null> {
  function isDirectory (line 186) | async function isDirectory(filePath: string): Promise<boolean> {
  function defaultDiscoverQuery (line 196) | async function defaultDiscoverQuery(
  function loadQuery (line 216) | async function loadQuery(
  function parseFileWithTreesitter (line 235) | async function parseFileWithTreesitter(
  function parseWorkspace (line 268) | async function parseWorkspace(
  function filterSymbols (line 318) | function filterSymbols(symbols: Symbol[], query: string): Symbol[] {
  function formatSymbolValue (line 325) | function formatSymbolValue(symbol: Symbol, isQuotedPrefix: boolean): str...
  type QueryDiscoveryContext (line 336) | interface QueryDiscoveryContext {
  type QueryDiscovery (line 346) | type QueryDiscovery = (ctx: QueryDiscoveryContext) => Promise<string | n...
  type TreesitterPickerOptions (line 348) | interface TreesitterPickerOptions {

FILE: legacy/pages/chrome-page/main.js
  constant INPUT (line 1) | const INPUT = document.querySelector(".input")
  constant TITLE (line 2) | const TITLE = document.querySelector(".title")

FILE: legacy/pages/startpage-v2/main.js
  constant INPUT (line 1) | const INPUT = document.querySelector(".container__search")
  constant KANA (line 71) | const KANA = document.querySelector(".word__kana")
  constant WORD (line 73) | const WORD = document.querySelector(".word__text")
  constant INFO (line 74) | const INFO = document.querySelector(".word__info")

FILE: legacy/pages/startpage/main.js
  constant INPUT (line 1) | const INPUT = document.querySelector(".category__input")
  constant TITLE (line 2) | const TITLE = document.querySelector(".title")
Condensed preview — 307 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,019K chars).
[
  {
    "path": ".gitignore",
    "chars": 81,
    "preview": "result\nconfig/fish/fish_variables\n__pycache__\n\nnushell/history*\nbin\nnode_modules\n"
  },
  {
    "path": ".gitmodules",
    "chars": 98,
    "preview": "[submodule \"dotbot\"]\n\tpath = dotbot\n\turl = https://github.com/anishathalye/dotbot\n\tignore = dirty\n"
  },
  {
    "path": "Makefile",
    "chars": 108,
    "preview": "linux:\n\tnh home switch --flake .#elianiva --print-build-logs\n\ndarwin:\n\tnh darwin switch .\n\nclean:\n\tnh clean\n"
  },
  {
    "path": "README.md",
    "chars": 610,
    "preview": "# elianiva's personal dotfiles\n\nThis is my personal dotfiles repository which has gone through many iterations.\n\nHere ar"
  },
  {
    "path": "agents/AGENTS.md",
    "chars": 569,
    "preview": "# Important Rules\n- Be extremely concise. Sacrifice grammar for the sake of concision.\n- Don't add tests for what the ty"
  },
  {
    "path": "agents/opencode/opencode.json",
    "chars": 1077,
    "preview": "{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"agent\": {\n    \"general\": {\n      \"disable\": true\n    },\n    \"explor"
  },
  {
    "path": "agents/pi/extensions/agent-profiles.ts",
    "chars": 13905,
    "preview": "/**\n * Agent Profiles Extension\n *\n * Define agent personas in markdown files with frontmatter.\n * Content is appended t"
  },
  {
    "path": "agents/pi/extensions/ask.ts",
    "chars": 19305,
    "preview": "/**\n * Ask Tool Extension\n *\n * Provides an interactive Q&A tool for the LLM to ask users questions\n * with multiple cho"
  },
  {
    "path": "agents/pi/extensions/composed-editor/index.ts",
    "chars": 1408,
    "preview": "/**\n * Composed Editor - Combines starship-prompt + pi-ckers\n *\n * This is your local extension that composes multiple e"
  },
  {
    "path": "agents/pi/extensions/composed-editor/package.json",
    "chars": 319,
    "preview": "{\n  \"name\": \"composed-editor\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"description\": \"Composed editor with starship-"
  },
  {
    "path": "agents/pi/extensions/custom-formatting.ts",
    "chars": 1003,
    "preview": "import { Theme } from \"@mariozechner/pi-coding-agent\";\nimport type { ExtensionAPI } from \"@mariozechner/pi-coding-agent\""
  },
  {
    "path": "agents/pi/extensions/exit-command.ts",
    "chars": 352,
    "preview": "import type { ExtensionAPI } from \"@mariozechner/pi-coding-agent\";\n\nexport default function (pi: ExtensionAPI) {\n  pi.on"
  },
  {
    "path": "agents/pi/extensions/handoff.ts",
    "chars": 4628,
    "preview": "/**\n * Handoff extension - transfer context to a new focused session\n *\n * Instead of compacting (which is lossy), hando"
  },
  {
    "path": "agents/pi/extensions/lsp/index.ts",
    "chars": 18130,
    "preview": "/**\n * LSP Diagnostics Extension\n *\n * Warms up LSP servers on file read, provides diagnostics on write/edit operations."
  },
  {
    "path": "agents/pi/extensions/lsp/lsp-config.ts",
    "chars": 18261,
    "preview": "/**\n * LSP Server Configurations\n *\n * Each server defines:\n * - id: Unique identifier\n * - extensions: File extensions "
  },
  {
    "path": "agents/pi/extensions/notify.ts",
    "chars": 1911,
    "preview": "/**\n * Pi Notify Extension\n *\n * Sends a native terminal notification when Pi agent is done and waiting for input.\n * Su"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/README.md",
    "chars": 874,
    "preview": "# pi-codemode\n\nExecutor plugins for codemode plus curated npm/jj commands and whitelisted bash.\n\n## Tools\n- `pi.*` built"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/executor.jsonc",
    "chars": 264,
    "preview": "{\n  \"sources\": [\n    {\n      \"kind\": \"mcp\",\n      \"transport\": \"remote\",\n      \"name\": \"mcp-typescript server on vercel\""
  },
  {
    "path": "agents/pi/extensions/pi-codemode/index.ts",
    "chars": 1199,
    "preview": "import type { ExtensionAPI } from \"@mariozechner/pi-coding-agent\";\nimport { createCodemodeTool } from \"./src/codemode.js"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/package.json",
    "chars": 871,
    "preview": "{\n  \"name\": \"pi-codemode\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"description\": \"pi codemode ex"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/builtins.ts",
    "chars": 5832,
    "preview": "import {\n  createBashTool,\n  createEditTool,\n  createFindTool,\n  createGrepTool,\n  createLsTool,\n  createReadTool,\n  cre"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/codemode.ts",
    "chars": 2524,
    "preview": "import { Type } from \"@sinclair/typebox\";\nimport { Text } from \"@mariozechner/pi-tui\";\nimport type { ExtensionContext, T"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/executor-cache.ts",
    "chars": 1938,
    "preview": "import { createExecutor, type Executor } from \"@executor-js/sdk\";\nimport { mcpPlugin } from \"@executor-js/plugin-mcp\";\ni"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/fff-plugin.ts",
    "chars": 1765,
    "preview": "import {\n  definePlugin,\n  ToolRegistration,\n  ToolId,\n  ToolInvocationResult,\n  type PluginContext,\n} from \"@executor-j"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/fff.ts",
    "chars": 7449,
    "preview": "import { FileFinder } from \"@ff-labs/fff-node\";\nimport { Type } from \"@sinclair/typebox\";\nimport { resolve } from \"node:"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/jj-plugin.ts",
    "chars": 4804,
    "preview": "import {\n  definePlugin,\n  ToolRegistration,\n  ToolId,\n  ToolInvocationResult,\n  type PluginContext,\n} from \"@executor-j"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/npm-plugin.ts",
    "chars": 4748,
    "preview": "import {\n  definePlugin,\n  ToolRegistration,\n  ToolId,\n  ToolInvocationResult,\n  type PluginContext,\n} from \"@executor-j"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/pi-plugin.ts",
    "chars": 1619,
    "preview": "import {\n  definePlugin,\n  ToolRegistration,\n  ToolId,\n  ToolInvocationResult,\n  type PluginContext,\n} from \"@executor-j"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/read.ts",
    "chars": 7178,
    "preview": "import { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\nimport { constants } from \"fs\";\nimport { extna"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/render.ts",
    "chars": 4241,
    "preview": "import { Text } from \"@mariozechner/pi-tui\";\nimport type { Theme } from \"@mariozechner/pi-coding-agent\";\nimport type { C"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/runtime.ts",
    "chars": 12629,
    "preview": "import type { Executor } from \"@executor-js/sdk\";\nimport { acquireSandbox, type SandboxDelegates } from \"./sandbox-cache"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/sandbox-cache.ts",
    "chars": 1608,
    "preview": "import { createInMemoryFileSystem, createKernel, createNodeRuntime, type Kernel } from \"secure-exec\";\n\n// Bound once int"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/source-config.ts",
    "chars": 11113,
    "preview": "import { readFile, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/source-hydrate.ts",
    "chars": 2921,
    "preview": "import type { Executor } from \"@executor-js/sdk\";\nimport type { SupportedSourceConfig, UnsupportedSourceConfig } from \"."
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/trace.ts",
    "chars": 5136,
    "preview": "import type { ImageContent } from \"@mariozechner/pi-ai\";\nimport type { CodemodeTrace, ToolResultSnapshot, TraceStep } fr"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/turndown.d.ts",
    "chars": 111,
    "preview": "declare module \"turndown\" {\n  export default class TurndownService {\n    turndown(html: string): string;\n  }\n}\n"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/types.ts",
    "chars": 1112,
    "preview": "import type { ImageContent } from \"@mariozechner/pi-ai\";\n\nexport const builtinToolNames = [\"read\", \"bash\", \"edit\", \"writ"
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/util.ts",
    "chars": 1434,
    "preview": "export const stripCodeFences = (code: string): string => {\n  const trimmed = code.trim();\n  const match = trimmed.match("
  },
  {
    "path": "agents/pi/extensions/pi-codemode/src/webfetch.ts",
    "chars": 4592,
    "preview": "import TurndownService from \"turndown\";\n\nexport type WebfetchInput = {\n  url: string;\n  format?: \"markdown\" | \"text\" | \""
  },
  {
    "path": "agents/pi/extensions/pi-codemode/tsconfig.json",
    "chars": 541,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"stri"
  },
  {
    "path": "agents/pi/extensions/prompt-timer.ts",
    "chars": 1683,
    "preview": "import type { AssistantMessage } from \"@mariozechner/pi-ai\";\nimport type { ExtensionAPI } from \"@mariozechner/pi-coding-"
  },
  {
    "path": "agents/pi/extensions/session-breakdown.ts",
    "chars": 34607,
    "preview": "/**\n * /session-breakdown\n *\n * Interactive TUI that analyzes ~/.pi/agent/sessions (recursively, *.jsonl) and shows\n * l"
  },
  {
    "path": "agents/pi/extensions/webfetch.ts",
    "chars": 8401,
    "preview": "/**\n * WebFetch Extension\n *\n * Fetches web content and converts to markdown, text, or HTML for agent consumption.\n * Us"
  },
  {
    "path": "agents/pi/extensions/whimsical-timer.ts",
    "chars": 4486,
    "preview": "import type { AssistantMessage } from \"@mariozechner/pi-ai\";\nimport type { ExtensionAPI } from \"@mariozechner/pi-coding-"
  },
  {
    "path": "agents/pi/mcp.json",
    "chars": 190,
    "preview": "{\n  \"mcpServers\": {\n    \"exa\": {\n      \"url\": \"https://mcp.exa.ai/mcp\"\n    },\n    \"fff\": {\n      \"command\": \"fff-mcp\",\n "
  },
  {
    "path": "agents/pi/models.json",
    "chars": 2189,
    "preview": "{\n  \"providers\": {\n    \"openrouter\": {\n      \"modelOverrides\": {\n        \"minimax/minimax-m2.5\": {\n          \"name\": \"Mi"
  },
  {
    "path": "agents/pi/package.json",
    "chars": 274,
    "preview": "{\n  \"name\": \"nil\",\n  \"peerDependencies\": {\n    \"@mariozechner/pi-ai\": \"*\",\n    \"@mariozechner/pi-coding-agent\": \"*\",\n   "
  },
  {
    "path": "agents/pi/settings.json",
    "chars": 518,
    "preview": "{\n  \"lastChangelogVersion\": \"0.70.6\",\n  \"defaultProvider\": \"deepseek\",\n  \"defaultModel\": \"deepseek-v4-flash\",\n  \"default"
  },
  {
    "path": "agents/pi/themes/rose-pine-dawn.json",
    "chars": 1920,
    "preview": "{\n  \"$schema\": \"https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/them"
  },
  {
    "path": "agents/pi/treesitter.ts",
    "chars": 13881,
    "preview": "import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport { createWriteStream } from \"node:fs\";\nimport os "
  },
  {
    "path": "agents/skills/build-feature/SKILL.md",
    "chars": 963,
    "preview": "---\nname: build-feature\ndescription: Use when creating or developing a feature, this contains a focused instructions for"
  },
  {
    "path": "agents/skills/code-review/SKILL.md",
    "chars": 374,
    "preview": "---\nname: code-review\nversion: 1.0.0\ndescription: Code review entire project\n---\n\n# Code Review\n\nAct as a highly critica"
  },
  {
    "path": "agents/skills/debugging/SKILL.md",
    "chars": 11211,
    "preview": "---\nname: debugging\ndescription: Use when encountering any bug, test failure, or unexpected behavior, before proposing f"
  },
  {
    "path": "agents/skills/deslop/SKILL.md",
    "chars": 595,
    "preview": "---\nname: deslop\ndescription: Remove all AI-generated slop like useless comments, try/catch blocks, and casts\n---\n\nRemov"
  },
  {
    "path": "agents/skills/effect-best-practices/SKILL.md",
    "chars": 14655,
    "preview": "---\nname: effect-best-practices\ndescription: Enforces Effect-TS patterns for services, errors, layers, and atoms. Use wh"
  },
  {
    "path": "agents/skills/effect-best-practices/references/anti-patterns.md",
    "chars": 8001,
    "preview": "# Anti-Patterns (Forbidden)\n\nThese patterns are **never acceptable** in Effect-TS code. Each is listed with rationale an"
  },
  {
    "path": "agents/skills/effect-best-practices/references/effect-atom-patterns.md",
    "chars": 13031,
    "preview": "# Effect Atom Patterns\n\nEffect Atom is a reactive state management library that integrates with Effect-TS. It provides a"
  },
  {
    "path": "agents/skills/effect-best-practices/references/error-patterns.md",
    "chars": 14937,
    "preview": "# Error Patterns\n\n## Why Explicit Error Types?\n\nGeneric errors like `BadRequestError` or `NotFoundError` seem convenient"
  },
  {
    "path": "agents/skills/effect-best-practices/references/layer-patterns.md",
    "chars": 9277,
    "preview": "# Layer Patterns\n\n## Dependencies in Effect.Service\n\n**Critical rule:** Always declare dependencies in the `dependencies"
  },
  {
    "path": "agents/skills/effect-best-practices/references/observability-patterns.md",
    "chars": 9254,
    "preview": "# Observability Patterns\n\n## Structured Logging with Effect.log\n\n**Always use Effect.log** instead of console.log. Effec"
  },
  {
    "path": "agents/skills/effect-best-practices/references/rpc-cluster-patterns.md",
    "chars": 11845,
    "preview": "# RPC & Cluster Patterns\n\n## RpcGroup for API Organization\n\n**Use `RpcGroup.make`** to organize related RPC endpoints:\n\n"
  },
  {
    "path": "agents/skills/effect-best-practices/references/schema-patterns.md",
    "chars": 9823,
    "preview": "# Schema Patterns\n\n## Branded Types for IDs\n\n**Always brand entity IDs** to prevent accidentally passing the wrong ID ty"
  },
  {
    "path": "agents/skills/effect-best-practices/references/service-patterns.md",
    "chars": 8907,
    "preview": "# Service Patterns\n\n## Effect.Service Over Context.Tag\n\n**Always prefer `Effect.Service`** for defining business logic s"
  },
  {
    "path": "agents/skills/emil-design-eng/SKILL.md",
    "chars": 26835,
    "preview": "---\nname: emil-design-eng\ndescription: This skill encodes Emil Kowalski's philosophy on UI polish, component design, ani"
  },
  {
    "path": "agents/skills/frontend-design/LICENSE.txt",
    "chars": 10174,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "agents/skills/frontend-design/SKILL.md",
    "chars": 4534,
    "preview": "---\nname: frontend-design\ndescription: \"Design and implement distinctive, production-ready frontend interfaces with stro"
  },
  {
    "path": "agents/skills/grill-me/SKILL.md",
    "chars": 635,
    "preview": "---\nname: grill-me\ndescription: Interview the user relentlessly about a plan or design until reaching shared understandi"
  },
  {
    "path": "agents/skills/initz/SKILL.md",
    "chars": 1390,
    "preview": "---\nname: initz\nversion: 1.0.0\ndescription: Initialize or improve AGENTS.md\n---\n\n# AGENTS.md Initialization\n\nAnalyze thi"
  },
  {
    "path": "agents/skills/jj/SKILL.md",
    "chars": 1020,
    "preview": "---\nname: jj\ndescription: Uses the jj (Jujutsu) version control system. Use when asked about jj commands, git push/fetch"
  },
  {
    "path": "agents/skills/pi-improvements/SKILL.md",
    "chars": 1171,
    "preview": "---\nname: pi-improvements\ndescription: When encountering pi tool limitations, propose focused extensions that solve one "
  },
  {
    "path": "agents/skills/react-best-practices/AGENTS.md",
    "chars": 75619,
    "preview": "# React Best Practices\n\n**Version 1.0.0**  \nVercel Engineering  \nJanuary 2026\n\n> **Note:**  \n> This document is mainly f"
  },
  {
    "path": "agents/skills/react-best-practices/README.md",
    "chars": 3360,
    "preview": "# React Best Practices\n\nA structured repository for creating and maintaining React Best Practices optimized for agents a"
  },
  {
    "path": "agents/skills/react-best-practices/SKILL.md",
    "chars": 5309,
    "preview": "---\nname: react-best-practices\ndescription: React and Next.js performance optimization guidelines from Vercel Engineerin"
  },
  {
    "path": "agents/skills/react-best-practices/metadata.json",
    "chars": 921,
    "preview": "{\n  \"version\": \"1.0.0\",\n  \"organization\": \"Vercel Engineering\",\n  \"date\": \"January 2026\",\n  \"abstract\": \"Comprehensive p"
  },
  {
    "path": "agents/skills/react-best-practices/rules/_sections.md",
    "chars": 1554,
    "preview": "# Sections\n\nThis file defines all sections, their ordering, impact levels, and descriptions.\nThe section ID (in parenthe"
  },
  {
    "path": "agents/skills/react-best-practices/rules/_template.md",
    "chars": 631,
    "preview": "---\ntitle: Rule Title Here\nimpact: MEDIUM\nimpactDescription: Optional description of impact (e.g., \"20-50% improvement\")"
  },
  {
    "path": "agents/skills/react-best-practices/rules/advanced-event-handler-refs.md",
    "chars": 1483,
    "preview": "---\ntitle: Store Event Handlers in Refs\nimpact: LOW\nimpactDescription: stable subscriptions\ntags: advanced, hooks, refs,"
  },
  {
    "path": "agents/skills/react-best-practices/rules/advanced-use-latest.md",
    "chars": 1072,
    "preview": "---\ntitle: useEffectEvent for Stable Callback Refs\nimpact: LOW\nimpactDescription: prevents effect re-runs\ntags: advanced"
  },
  {
    "path": "agents/skills/react-best-practices/rules/async-api-routes.md",
    "chars": 1124,
    "preview": "---\ntitle: Prevent Waterfall Chains in API Routes\nimpact: CRITICAL\nimpactDescription: 2-10× improvement\ntags: api-routes"
  },
  {
    "path": "agents/skills/react-best-practices/rules/async-defer-await.md",
    "chars": 2028,
    "preview": "---\ntitle: Defer Await Until Needed\nimpact: HIGH\nimpactDescription: avoids blocking unused code paths\ntags: async, await"
  },
  {
    "path": "agents/skills/react-best-practices/rules/async-dependencies.md",
    "chars": 1292,
    "preview": "---\ntitle: Dependency-Based Parallelization\nimpact: CRITICAL\nimpactDescription: 2-10× improvement\ntags: async, paralleli"
  },
  {
    "path": "agents/skills/react-best-practices/rules/async-parallel.md",
    "chars": 653,
    "preview": "---\ntitle: Promise.all() for Independent Operations\nimpact: CRITICAL\nimpactDescription: 2-10× improvement\ntags: async, p"
  },
  {
    "path": "agents/skills/react-best-practices/rules/async-suspense-boundaries.md",
    "chars": 2508,
    "preview": "---\ntitle: Strategic Suspense Boundaries\nimpact: HIGH\nimpactDescription: faster initial paint\ntags: async, suspense, str"
  },
  {
    "path": "agents/skills/react-best-practices/rules/bundle-barrel-imports.md",
    "chars": 2370,
    "preview": "---\ntitle: Avoid Barrel File Imports\nimpact: CRITICAL\nimpactDescription: 200-800ms import cost, slow builds\ntags: bundle"
  },
  {
    "path": "agents/skills/react-best-practices/rules/bundle-conditional.md",
    "chars": 949,
    "preview": "---\ntitle: Conditional Module Loading\nimpact: HIGH\nimpactDescription: loads large data only when needed\ntags: bundle, co"
  },
  {
    "path": "agents/skills/react-best-practices/rules/bundle-defer-third-party.md",
    "chars": 920,
    "preview": "---\ntitle: Defer Non-Critical Third-Party Libraries\nimpact: MEDIUM\nimpactDescription: loads after hydration\ntags: bundle"
  },
  {
    "path": "agents/skills/react-best-practices/rules/bundle-dynamic-imports.md",
    "chars": 791,
    "preview": "---\ntitle: Dynamic Imports for Heavy Components\nimpact: CRITICAL\nimpactDescription: directly affects TTI and LCP\ntags: b"
  },
  {
    "path": "agents/skills/react-best-practices/rules/bundle-preload.md",
    "chars": 1149,
    "preview": "---\ntitle: Preload Based on User Intent\nimpact: MEDIUM\nimpactDescription: reduces perceived latency\ntags: bundle, preloa"
  },
  {
    "path": "agents/skills/react-best-practices/rules/client-event-listeners.md",
    "chars": 1969,
    "preview": "---\ntitle: Deduplicate Global Event Listeners\nimpact: LOW\nimpactDescription: single listener for N components\ntags: clie"
  },
  {
    "path": "agents/skills/react-best-practices/rules/client-localstorage-schema.md",
    "chars": 1950,
    "preview": "---\ntitle: Version and Minimize localStorage Data\nimpact: MEDIUM\nimpactDescription: prevents schema conflicts, reduces s"
  },
  {
    "path": "agents/skills/react-best-practices/rules/client-passive-event-listeners.md",
    "chars": 1644,
    "preview": "---\ntitle: Use Passive Event Listeners for Scrolling Performance\nimpact: MEDIUM\nimpactDescription: eliminates scroll del"
  },
  {
    "path": "agents/skills/react-best-practices/rules/client-swr-dedup.md",
    "chars": 1159,
    "preview": "---\ntitle: Use SWR for Automatic Deduplication\nimpact: MEDIUM-HIGH\nimpactDescription: automatic deduplication\ntags: clie"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-batch-dom-css.md",
    "chars": 3266,
    "preview": "---\ntitle: Avoid Layout Thrashing\nimpact: MEDIUM\nimpactDescription: prevents forced synchronous layouts and reduces perf"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-cache-function-results.md",
    "chars": 1949,
    "preview": "---\ntitle: Cache Repeated Function Calls\nimpact: MEDIUM\nimpactDescription: avoid redundant computation\ntags: javascript,"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-cache-property-access.md",
    "chars": 531,
    "preview": "---\ntitle: Cache Property Access in Loops\nimpact: LOW-MEDIUM\nimpactDescription: reduces lookups\ntags: javascript, loops,"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-cache-storage.md",
    "chars": 1651,
    "preview": "---\ntitle: Cache Storage API Calls\nimpact: LOW-MEDIUM\nimpactDescription: reduces expensive I/O\ntags: javascript, localSt"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-combine-iterations.md",
    "chars": 753,
    "preview": "---\ntitle: Combine Multiple Array Iterations\nimpact: LOW-MEDIUM\nimpactDescription: reduces iterations\ntags: javascript, "
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-early-exit.md",
    "chars": 1133,
    "preview": "---\ntitle: Early Return from Functions\nimpact: LOW-MEDIUM\nimpactDescription: avoids unnecessary computation\ntags: javasc"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-hoist-regexp.md",
    "chars": 1028,
    "preview": "---\ntitle: Hoist RegExp Creation\nimpact: LOW-MEDIUM\nimpactDescription: avoids recreation\ntags: javascript, regexp, optim"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-index-maps.md",
    "chars": 834,
    "preview": "---\ntitle: Build Index Maps for Repeated Lookups\nimpact: LOW-MEDIUM\nimpactDescription: 1M ops to 2K ops\ntags: javascript"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-length-check-first.md",
    "chars": 1747,
    "preview": "---\ntitle: Early Length Check for Array Comparisons\nimpact: MEDIUM-HIGH\nimpactDescription: avoids expensive operations w"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-min-max-loop.md",
    "chars": 2290,
    "preview": "---\ntitle: Use Loop for Min/Max Instead of Sort\nimpact: LOW\nimpactDescription: O(n) instead of O(n log n)\ntags: javascri"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-set-map-lookups.md",
    "chars": 532,
    "preview": "---\ntitle: Use Set/Map for O(1) Lookups\nimpact: LOW-MEDIUM\nimpactDescription: O(n) to O(1)\ntags: javascript, set, map, d"
  },
  {
    "path": "agents/skills/react-best-practices/rules/js-tosorted-immutable.md",
    "chars": 1782,
    "preview": "---\ntitle: Use toSorted() Instead of sort() for Immutability\nimpact: MEDIUM-HIGH\nimpactDescription: prevents mutation bu"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-activity.md",
    "chars": 564,
    "preview": "---\ntitle: Use Activity Component for Show/Hide\nimpact: MEDIUM\nimpactDescription: preserves state/DOM\ntags: rendering, a"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md",
    "chars": 1185,
    "preview": "---\ntitle: Animate SVG Wrapper Instead of SVG Element\nimpact: LOW\nimpactDescription: enables hardware acceleration\ntags:"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-conditional-render.md",
    "chars": 980,
    "preview": "---\ntitle: Use Explicit Conditional Rendering\nimpact: LOW\nimpactDescription: prevents rendering 0 or NaN\ntags: rendering"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-content-visibility.md",
    "chars": 814,
    "preview": "---\ntitle: CSS content-visibility for Long Lists\nimpact: HIGH\nimpactDescription: faster initial render\ntags: rendering, "
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-hoist-jsx.md",
    "chars": 1039,
    "preview": "---\ntitle: Hoist Static JSX Elements\nimpact: LOW\nimpactDescription: avoids re-creation\ntags: rendering, jsx, static, opt"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-hydration-no-flicker.md",
    "chars": 2308,
    "preview": "---\ntitle: Prevent Hydration Mismatch Without Flickering\nimpact: MEDIUM\nimpactDescription: avoids visual flicker and hyd"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-svg-precision.md",
    "chars": 588,
    "preview": "---\ntitle: Optimize SVG Precision\nimpact: LOW\nimpactDescription: reduces file size\ntags: rendering, svg, optimization, s"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rendering-usetransition-loading.md",
    "chars": 2074,
    "preview": "---\ntitle: Use useTransition Over Manual Loading States\nimpact: LOW\nimpactDescription: reduces re-renders and improves c"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-defer-reads.md",
    "chars": 973,
    "preview": "---\ntitle: Defer State Reads to Usage Point\nimpact: MEDIUM\nimpactDescription: avoids unnecessary subscriptions\ntags: rer"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-dependencies.md",
    "chars": 824,
    "preview": "---\ntitle: Narrow Effect Dependencies\nimpact: LOW\nimpactDescription: minimizes effect re-runs\ntags: rerender, useEffect,"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-derived-state.md",
    "chars": 728,
    "preview": "---\ntitle: Subscribe to Derived State\nimpact: MEDIUM\nimpactDescription: reduces re-render frequency\ntags: rerender, deri"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-functional-setstate.md",
    "chars": 2958,
    "preview": "---\ntitle: Use Functional setState Updates\nimpact: MEDIUM\nimpactDescription: prevents stale closures and unnecessary cal"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-lazy-state-init.md",
    "chars": 2016,
    "preview": "---\ntitle: Use Lazy State Initialization\nimpact: MEDIUM\nimpactDescription: wasted computation on every render\ntags: reac"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-memo-with-default-value.md",
    "chars": 1173,
    "preview": "---\n\ntitle: Extract Default Non-primitive Parameter Value from Memoized Component to Constant\nimpact: MEDIUM\nimpactDescr"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-memo.md",
    "chars": 1148,
    "preview": "---\ntitle: Extract to Memoized Components\nimpact: MEDIUM\nimpactDescription: enables early returns\ntags: rerender, memo, "
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md",
    "chars": 1018,
    "preview": "---\ntitle: Do not wrap a simple expression with a primitive result type in useMemo\nimpact: LOW-MEDIUM\nimpactDescription:"
  },
  {
    "path": "agents/skills/react-best-practices/rules/rerender-transitions.md",
    "chars": 1055,
    "preview": "---\ntitle: Use Transitions for Non-Urgent Updates\nimpact: MEDIUM\nimpactDescription: maintains UI responsiveness\ntags: re"
  },
  {
    "path": "agents/skills/react-best-practices/rules/server-after-nonblocking.md",
    "chars": 2012,
    "preview": "---\ntitle: Use after() for Non-Blocking Operations\nimpact: MEDIUM\nimpactDescription: faster response times\ntags: server,"
  },
  {
    "path": "agents/skills/react-best-practices/rules/server-auth-actions.md",
    "chars": 2647,
    "preview": "---\ntitle: Authenticate Server Actions Like API Routes\nimpact: CRITICAL\nimpactDescription: prevents unauthorized access "
  },
  {
    "path": "agents/skills/react-best-practices/rules/server-cache-lru.md",
    "chars": 1353,
    "preview": "---\ntitle: Cross-Request LRU Caching\nimpact: HIGH\nimpactDescription: caches across requests\ntags: server, cache, lru, cr"
  },
  {
    "path": "agents/skills/react-best-practices/rules/server-cache-react.md",
    "chars": 2228,
    "preview": "---\ntitle: Per-Request Deduplication with React.cache()\nimpact: MEDIUM\nimpactDescription: deduplicates within request\nta"
  },
  {
    "path": "agents/skills/react-best-practices/rules/server-dedup-props.md",
    "chars": 2053,
    "preview": "---\ntitle: Avoid Duplicate Serialization in RSC Props\nimpact: LOW\nimpactDescription: reduces network payload by avoiding"
  },
  {
    "path": "agents/skills/react-best-practices/rules/server-parallel-fetching.md",
    "chars": 1554,
    "preview": "---\ntitle: Parallel Data Fetching with Component Composition\nimpact: CRITICAL\nimpactDescription: eliminates server-side "
  },
  {
    "path": "agents/skills/react-best-practices/rules/server-serialization.md",
    "chars": 996,
    "preview": "---\ntitle: Minimize Serialization at RSC Boundaries\nimpact: HIGH\nimpactDescription: reduces data transfer size\ntags: ser"
  },
  {
    "path": "agents/skills/root-cause-tracing/SKILL.md",
    "chars": 2260,
    "preview": "---\nname: root-cause-tracing\ndescription: Use when errors occur deep in execution and you need to trace back to find the"
  },
  {
    "path": "agents/skills/session-retrospective/SKILL.md",
    "chars": 1300,
    "preview": "---\nname: session-retrospective\ndescription: At end of difficult sessions, analyze friction points and propose concrete "
  },
  {
    "path": "agents/skills/web-design-guidelines/SKILL.md",
    "chars": 7589,
    "preview": "---\nname: web-design-guidelines\ndescription: Review UI code for Web Interface Guidelines compliance. Use when asked to \""
  },
  {
    "path": "agents/skills/wydt/SKILL.md",
    "chars": 4265,
    "preview": "---\nname: wydt\ndescription: Ask AI's opinion on code - identify improvements, code smells, anti-patterns, and quality is"
  },
  {
    "path": "direnv/direnvrc",
    "chars": 319,
    "preview": ": ${XDG_RUNTIME_DIR:=/tmp/nix-direnv/$UID}\ndeclare -A direnv_layout_dirs\ndirenv_layout_dir() {\n    local hash path\n    e"
  },
  {
    "path": "fish/conf.d/abbr.fish",
    "chars": 1134,
    "preview": "# git stuff\nabbr -a ga    \"git add\"\nabbr -a gc    \"git commit\"\nabbr -a gs    \"git status\"\nabbr -a gd    \"git diff\"\nabbr "
  },
  {
    "path": "fish/conf.d/alias.fish",
    "chars": 101,
    "preview": "alias :Q=\"exit\"\nalias :q=\"exit\"\n\nalias sail='sh $([ -f sail ] && echo sail || echo vendor/bin/sail)'\n"
  },
  {
    "path": "fish/conf.d/colour.fish",
    "chars": 1292,
    "preview": "set -U fish_color_autosuggestion      brblack\nset -U fish_color_cancel              -r\nset -U fish_color_command        "
  },
  {
    "path": "fish/conf.d/foreign.fish",
    "chars": 25,
    "preview": "fenv \"source ~/.profile\"\n"
  },
  {
    "path": "fish/conf.d/manpage.fish",
    "chars": 517,
    "preview": "# Start blinking | blue\nset -Ux LESS_TERMCAP_mb (printf '\\033[1;34m')\n# Start bold | blue\nset -Ux LESS_TERMCAP_md (print"
  },
  {
    "path": "fish/conf.d/vi-mode.fish",
    "chars": 253,
    "preview": "# vi mode\nfish_vi_key_bindings\n\n# Set the cursor shapes for the different vi modes.\nset fish_cursor_default     block   "
  },
  {
    "path": "fish/config.fish",
    "chars": 818,
    "preview": "# disable greeting\nset fish_greeting\n\nstarship init fish | source\n\nzoxide init fish --cmd cd | source\n\nset -gx PNPM_HOME"
  },
  {
    "path": "fish/fish_plugins",
    "chars": 30,
    "preview": "oh-my-fish/plugin-foreign-env\n"
  },
  {
    "path": "fish/fish_variables",
    "chars": 4662,
    "preview": "# This file contains fish universal variable definitions.\n# VERSION: 3.0\nSETUVAR --export GROFF_NO_SGR:1\nSETUVAR --expor"
  },
  {
    "path": "fish/functions/fenv.apply.fish",
    "chars": 1438,
    "preview": "# The MIT License (MIT)\n\n# Copyright (c) 2015 Derek Willian Stavis\n\n# Permission is hereby granted, free of charge, to a"
  },
  {
    "path": "fish/functions/fenv.fish",
    "chars": 1523,
    "preview": "# The MIT License (MIT)\n\n# Copyright (c) 2015 Derek Willian Stavis\n\n# Permission is hereby granted, free of charge, to a"
  },
  {
    "path": "fish/functions/fenv.main.fish",
    "chars": 2044,
    "preview": "#The MIT License (MIT)\n\n# Copyright (c) 2015 Derek Willian Stavis\n\n# Permission is hereby granted, free of charge, to an"
  },
  {
    "path": "fish/functions/fenv.parse.after.fish",
    "chars": 1319,
    "preview": "# The MIT License (MIT)\n\n# Copyright (c) 2015 Derek Willian Stavis\n\n# Permission is hereby granted, free of charge, to a"
  },
  {
    "path": "fish/functions/fenv.parse.before.fish",
    "chars": 1286,
    "preview": "# The MIT License (MIT)\n\n# Copyright (c) 2015 Derek Willian Stavis\n\n# Permission is hereby granted, free of charge, to a"
  },
  {
    "path": "fish/functions/fenv.parse.diff.fish",
    "chars": 1347,
    "preview": "# The MIT License (MIT)\n\n# Copyright (c) 2015 Derek Willian Stavis\n\n# Permission is hereby granted, free of charge, to a"
  },
  {
    "path": "fish/functions/fenv.parse.divider.fish",
    "chars": 1180,
    "preview": "# The MIT License (MIT)\n\n# Copyright (c) 2015 Derek Willian Stavis\n\n# Permission is hereby granted, free of charge, to a"
  },
  {
    "path": "flake.nix",
    "chars": 4618,
    "preview": "{\n  description = \"elianiva nix config\";\n\n  inputs = {\n    nixpkgs-stable.url = \"github:nixos/nixpkgs/release-24.11\";\n  "
  },
  {
    "path": "ghostty/config",
    "chars": 614,
    "preview": "theme = light:Rose Pine Dawn,dark:Rose Pine\nwindow-theme = ghostty\nwindow-titlebar-background = #faf4ed\nwindow-colorspac"
  },
  {
    "path": "gitconfig/.gitconfig",
    "chars": 611,
    "preview": "# vim: ft=toml\n\n[user]\n  name = elianiva\n  email = dicha.arkana03@gmail.com\n\tsigningkey = A9680245\n\n[credential]\n  helpe"
  },
  {
    "path": "helix/config.toml",
    "chars": 1068,
    "preview": "theme = \"my_rose_pine\"\n\n[editor]\nbufferline = \"multiple\"\nline-number = \"relative\"\ncursorline = true\npopup-border = \"all\""
  },
  {
    "path": "helix/languages.toml",
    "chars": 2304,
    "preview": "[language-server.tinymist]\ncommand = \"tinymist\"\n\n[language-server.tinymist.config]\npreview.background.enabled = true\npre"
  },
  {
    "path": "helix/runtime/queries/typst/highlights.scm",
    "chars": 2202,
    "preview": "; CONTROL\n(let \"let\" @keyword.storage.type)\n(branch [\"if\" \"else\"] @keyword.control.conditional)\n(while \"while\" @keyword."
  },
  {
    "path": "helix/themes/my_rose_pine.toml",
    "chars": 270,
    "preview": "inherits = \"rose_pine_dawn\"\n\n\"ui.virtual.indent-guide\" = { fg = \"overlay\" }\n\n\"ui.statusline\" = { fg = \"love\", bg = \"love"
  },
  {
    "path": "improvement.md",
    "chars": 4062,
    "preview": "# Nix Configuration Improvements\n\nThis document contains recommendations for improving the Nix configuration based on a "
  },
  {
    "path": "jjui/config.toml",
    "chars": 30,
    "preview": "[ui]\ntheme = \"rose-pine-dawn\"\n"
  },
  {
    "path": "jjui/themes/rose-pine-dawn.toml",
    "chars": 2898,
    "preview": "## tinted-jjui (https://github.com/vic/tinted-jjui)\n# Scheme name: Rosé Pine Dawn\n# Scheme author: Emilia Dunfelt &lt;ed"
  },
  {
    "path": "kitty/kitty.conf",
    "chars": 2156,
    "preview": "# include colorscheme\ninclude rose-pine-dawn.conf\n\nadjust_line_height 140%\n# jetbrains mono\n# font_size 11.5\n# monaspace"
  },
  {
    "path": "kitty/launch.conf",
    "chars": 14,
    "preview": "launch zellij\n"
  },
  {
    "path": "kitty/rose-pine-dawn.conf",
    "chars": 1005,
    "preview": "## name: Rosé Pine Dawn\n## author: mvllow\n## license: MIT\n## upstream: https://github.com/rose-pine/kitty/blob/main/dist"
  },
  {
    "path": "kitty/rose-pine.conf",
    "chars": 995,
    "preview": "## name: Rosé Pine\n## author: mvllow\n## license: MIT\n## upstream: https://github.com/rose-pine/kitty/blob/main/dist/rose"
  },
  {
    "path": "legacy/awesome/.config/awesome/keybinds/bindtotags.lua",
    "chars": 1668,
    "preview": "local gears = require(\"gears\")\nlocal awful = require(\"awful\")\nlocal modkey = require(\"main.variables\").modkey\n\nlocal M ="
  },
  {
    "path": "legacy/awesome/.config/awesome/keybinds/clientbuttons.lua",
    "chars": 626,
    "preview": "-- Standard awesome library\nlocal gears = require(\"gears\")\nlocal awful = require(\"awful\")\nlocal modkey = require(\"main.v"
  },
  {
    "path": "legacy/awesome/.config/awesome/keybinds/clientkeys.lua",
    "chars": 4754,
    "preview": "-- Standard Awesome library\nlocal gears = require(\"gears\")\nlocal awful = require(\"awful\")\nlocal beautiful = require(\"bea"
  },
  {
    "path": "legacy/awesome/.config/awesome/keybinds/globalkeys.lua",
    "chars": 3758,
    "preview": "local gears = require \"gears\"\nlocal awful = require \"awful\"\nlocal naughty = require \"naughty\"\nlocal exit_screen_show = r"
  },
  {
    "path": "legacy/awesome/.config/awesome/keybinds/mediakeys.lua",
    "chars": 2182,
    "preview": "local gears = require(\"gears\")\nlocal awful = require(\"awful\")\nlocal naughty = require(\"naughty\")\nlocal noop = require(\"m"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/autostart.lua",
    "chars": 315,
    "preview": "local awful = require(\"awful\")\n\nlocal M = {}\n\nM.setup = function()\n\tlocal cmds = {\n\t\t\"clipmenud\",\n\t\t\"flameshot\",\n\t\t\"lxpo"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/error-handling.lua",
    "chars": 837,
    "preview": "local naughty = require(\"naughty\")\n\nlocal M = {}\n\n-- Check if awesome encountered an error during startup and fell back "
  },
  {
    "path": "legacy/awesome/.config/awesome/main/exitscreen.lua",
    "chars": 4172,
    "preview": "local awful = require(\"awful\")\nlocal gears = require(\"gears\")\nlocal wibox = require(\"wibox\")\nlocal dpi = require(\"beauti"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/helpers.lua",
    "chars": 2548,
    "preview": "local awful = require(\"awful\")\nlocal gears = require(\"gears\")\nlocal wibox = require(\"wibox\")\nlocal xresources = require("
  },
  {
    "path": "legacy/awesome/.config/awesome/main/json.lua",
    "chars": 9089,
    "preview": "--\n-- json.lua\n--\n-- Copyright (c) 2020 rxi\n--\n-- Permission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "legacy/awesome/.config/awesome/main/layouts.lua",
    "chars": 213,
    "preview": "local awful = require(\"awful\")\n\n-- Table of layouts to cover with awful.layout.inc, order matters.\nlocal layouts = {\n\taw"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/menu.lua",
    "chars": 1119,
    "preview": "local menubar = require(\"menubar\")\nlocal awful = require(\"awful\")\nlocal spawn = awful.spawn.with_shell\nlocal hotkeys_pop"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/rules.lua",
    "chars": 2546,
    "preview": "local awful = require \"awful\"\nlocal beautiful = require \"beautiful\"\nlocal clientbuttons = require \"keybinds.clientbutton"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/signals.lua",
    "chars": 1380,
    "preview": "-- Standard awesome library\nlocal awful = require(\"awful\")\nlocal beautiful = require(\"beautiful\")\nlocal gears = require("
  },
  {
    "path": "legacy/awesome/.config/awesome/main/tags.lua",
    "chars": 278,
    "preview": "local awful = require(\"awful\")\nlocal layouts = require(\"main.layouts\")\n\nlocal M = {}\n\nM.setup = function()\n\tawful.screen"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/titlebar.lua",
    "chars": 2539,
    "preview": "local awful = require(\"awful\")\nlocal gears = require(\"gears\")\nlocal wibox = require(\"wibox\")\nlocal dpi = require(\"beauti"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/variables.lua",
    "chars": 539,
    "preview": "local HOME_DIR = os.getenv(\"HOME\")\nlocal EDITOR = os.getenv(\"EDITOR\")\nlocal TERMINAL = os.getenv(\"TERMINAL\")\n\nlocal vari"
  },
  {
    "path": "legacy/awesome/.config/awesome/main/volume-widget/init.lua",
    "chars": 2099,
    "preview": "local wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal gears = require(\"gears\")\nlocal beautiful = require(\""
  },
  {
    "path": "legacy/awesome/.config/awesome/rc.lua",
    "chars": 926,
    "preview": "-- If LuaRocks is installed, make sure that packages installed through it are\n-- found (e.g. lgi). If LuaRocks is not in"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/init.lua",
    "chars": 3679,
    "preview": "local gears = require(\"gears\")\nlocal wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal beautiful = require(\""
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/battery/init.lua",
    "chars": 657,
    "preview": "local wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal colorize = require(\"main.helpers\").colorize\nlocal ma"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/clock/init.lua",
    "chars": 1293,
    "preview": "local gears = require(\"gears\")\nlocal wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal colorize = require(\"m"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/cpu/init.lua",
    "chars": 586,
    "preview": "local wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal icon = os.getenv(\"HOME\") .. \"/.config/awesome/status"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/launcher.lua",
    "chars": 222,
    "preview": "local awful = require(\"awful\")\nlocal beautiful = require(\"beautiful\")\nlocal menu = require(\"main.menu\")\n\nlocal M = {}\n\nM"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/memory/init.lua",
    "chars": 591,
    "preview": "local wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal icon = os.getenv(\"HOME\") .. \"/.config/awesome/status"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/netspeed/init.lua",
    "chars": 1571,
    "preview": "local wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal markup = require(\"main.helpers\").markup\nlocal colori"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/systray.lua",
    "chars": 203,
    "preview": "local wibox = require(\"wibox\")\nlocal dpi = require(\"beautiful\").xresources.apply_dpi\n\nlocal M = {}\n\nM.widget = wibox.wid"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/taglist.lua",
    "chars": 844,
    "preview": "local gears = require(\"gears\")\nlocal awful = require(\"awful\")\nlocal modkey = require(\"main.variables\").modkey\n\nlocal M ="
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/temp/init.lua",
    "chars": 613,
    "preview": "local wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal icon = os.getenv(\"HOME\") .. \"/.config/awesome/status"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/todo/init.lua",
    "chars": 7223,
    "preview": "-------------------------------------------------\n-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/todo"
  },
  {
    "path": "legacy/awesome/.config/awesome/statusbar/modules/volume/init.lua",
    "chars": 2261,
    "preview": "local wibox = require(\"wibox\")\nlocal awful = require(\"awful\")\nlocal colorize = require(\"main.helpers\").colorize\nlocal ma"
  },
  {
    "path": "legacy/awesome/.config/awesome/themes/main/colours.lua",
    "chars": 428,
    "preview": "local xrdb = require(\"beautiful.xresources\").get_current_theme()\n\ntheme.background = xrdb.background\ntheme.foreground = "
  },
  {
    "path": "legacy/awesome/.config/awesome/themes/main/elements.lua",
    "chars": 3573,
    "preview": "local theme_assets = require(\"beautiful.theme_assets\")\nlocal dpi = require(\"beautiful.xresources\").apply_dpi\nlocal theme"
  },
  {
    "path": "legacy/awesome/.config/awesome/themes/main/naughty.lua",
    "chars": 2373,
    "preview": "local naughty = require(\"naughty\")\nlocal wibox = require(\"wibox\")\nlocal dpi = require(\"beautiful.xresources\").apply_dpi\n"
  },
  {
    "path": "legacy/awesome/.config/awesome/themes/main/theme.lua",
    "chars": 238,
    "preview": "local theme_path = os.getenv(\"HOME\") .. \"/.config/awesome/themes/main/\"\n\ntheme = {} -- global namespace for theme\n\ndofil"
  },
  {
    "path": "legacy/fcitx5/.config/fcitx5/conf/cached_layouts",
    "chars": 71314,
    "preview": "[keyboard-apl]\nDescription=\"Keyboard - APL\"\nLanguage=en\nLabel=apl\n\n[keyboard-apl-dyalog]\nDescription=\"Keyboard - APL - A"
  },
  {
    "path": "legacy/fcitx5/.config/fcitx5/conf/classicui.conf",
    "chars": 321,
    "preview": "# Vertical Candidate List\nVertical Candidate List=True\n# Use Per Screen DPI\nPerScreenDPI=True\n# Use mouse wheel to go to"
  }
]

// ... and 107 more files (download for full content)

About this extraction

This page contains the full source code of the elianiva/dotfiles GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 307 files (917.2 KB), approximately 255.4k tokens, and a symbol index with 261 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!