1st-pi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 est7
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # 1st-pi
2
+
3
+ [est7](https://github.com/est7) 的 [Pi](https://pi.dev) coding agent preset。
4
+
5
+ 这是一个 Pi Package,用来统一打包和分发常用的 **extensions / skills / prompts / themes**。安装后,Pi 会自动加载本仓库资源以及声明的 bundled Pi packages。
6
+
7
+ > **Security:** Pi packages 拥有完整系统权限。Extensions 可以执行任意代码,skills 可以指示模型执行操作。安装第三方包前请审阅源码。
8
+
9
+ ## 安装
10
+
11
+ ### GitHub
12
+
13
+ ```bash
14
+ pi install git:github.com/est7/1st-pi
15
+ # 或
16
+ pi install https://github.com/est7/1st-pi
17
+ ```
18
+
19
+ ### 本地开发
20
+
21
+ ```bash
22
+ pi install /absolute/path/to/1st-pi
23
+ # 当前目录
24
+ pi install .
25
+ ```
26
+
27
+ ### npm
28
+
29
+ ```bash
30
+ pi install npm:1st-pi
31
+ ```
32
+
33
+ 仅在当前会话试用,不写入 settings:
34
+
35
+ ```bash
36
+ pi -e .
37
+ pi -e git:github.com/est7/1st-pi
38
+ ```
39
+
40
+ 安装为项目级依赖,写入 `.pi/settings.json`:
41
+
42
+ ```bash
43
+ pi install -l .
44
+ ```
45
+
46
+ ## 管理
47
+
48
+ ```bash
49
+ pi list
50
+ pi config
51
+ pi update --extensions
52
+ pi remove git:github.com/est7/1st-pi
53
+ ```
54
+
55
+ ## 目录结构
56
+
57
+ ```text
58
+ 1st-pi/
59
+ ├── package.json # Pi package manifest
60
+ ├── extensions/ # 本地 UI 与 community package thin adapters
61
+ ├── skills/ # skills/<name>/SKILL.md
62
+ ├── prompts/ # Markdown prompt templates
63
+ └── themes/ # 从 pi-everforest-tui 同步并校验的 theme resources
64
+ ```
65
+
66
+ ## 添加自己的资源
67
+
68
+ - `extensions/*.ts`:自定义工具、命令、事件和 UI
69
+ - `skills/<name>/SKILL.md`:可自动发现或通过 `/skill:name` 调用的技能
70
+ - `prompts/*.md`:通过 `/文件名` 调用的提示词模板
71
+
72
+ 修改资源后,在 Pi 中运行 `/reload`,或重新执行:
73
+
74
+ ```bash
75
+ pi -e .
76
+ ```
77
+
78
+ ## Everforest themes
79
+
80
+ 本 preset 通过独立 package [`pi-everforest-tui`](https://github.com/est7/pi-everforest-tui) 提供两个 Ghostty Everforest Soft 风格的 Pi TUI theme:
81
+
82
+ - `everforest-tui-dark`
83
+ - `everforest-tui-light`
84
+
85
+ Preset 默认开启以下 TUI 增强,session 中持久化的个人选择优先于 preset 默认值:
86
+
87
+ - phase-aware working indicator
88
+ - 仅在工作期间出现的 status(idle 不显示,不重复 model)
89
+ - 响应式 cockpit footer 与完整 segment 的 extension statuses
90
+ - 连续 Everforest 彩虹 editor 边框与具名 session badge
91
+
92
+ 相关命令:
93
+
94
+ ```text
95
+ /everforest # 搜索全部 extension、prompt、skill commands
96
+ /everforest-tui # 打开交互式 TUI 设置
97
+ /everforest-theme-lab # 预览主题语义色、Markdown、diff、syntax 与 thinking states
98
+ ```
99
+
100
+ 也可直接执行 `/everforest-tui all on|off` 或针对 `indicator`、`status`、`footer`、`rainbow` 单独设置。
101
+
102
+ 可在 `/settings` 中手动选择 theme。要像 Ghostty 一样随终端背景自动切换,在 Pi 的 `settings.json` 中设置:
103
+
104
+ ```json
105
+ {
106
+ "theme": "everforest-tui-light/everforest-tui-dark"
107
+ }
108
+ ```
109
+
110
+ 斜杠前是 light theme,斜杠后是 dark theme。
111
+
112
+ ## Custom header
113
+
114
+ `extensions/custom-header.ts` 使用 `1st-agent` ASCII wordmark 替换 Pi 默认启动 header。需要临时恢复默认 header 时运行:
115
+
116
+ ```text
117
+ /builtin-header
118
+ ```
119
+
120
+ ## 内置依赖
121
+
122
+ | 包 | 功能 |
123
+ |---|---|
124
+ | [pi-web-access](https://www.npmjs.com/package/pi-web-access) | Web 搜索、URL/GitHub/YouTube 访问及 librarian skill |
125
+ | [pi-init](https://www.npmjs.com/package/pi-init) | 生成或更新 `AGENTS.md` 的 init skill |
126
+ | [pi-mcp-adapter](https://www.npmjs.com/package/pi-mcp-adapter) | MCP 协议适配 |
127
+ | [pi-everforest-tui](https://www.npmjs.com/package/pi-everforest-tui) | Everforest light/dark themes 与可选 TUI 增强 |
128
+ | [pi-session-name](https://www.npmjs.com/package/pi-session-name) | 自动生成会话标题并同步终端标题 |
129
+ | [@juicesharp/rpiv-ask-user-question](https://www.npmjs.com/package/@juicesharp/rpiv-ask-user-question) | 多问题、选项预览和自由输入的结构化提问 UI |
130
+ | [@narumitw/pi-goal](https://www.npmjs.com/package/@narumitw/pi-goal) | Session-scoped `/goal` 持续执行与完成/阻塞门禁 |
131
+ | [pi-observational-memory](https://www.npmjs.com/package/pi-observational-memory) | 跨压缩保留 observations/reflections 的长会话记忆 |
132
+ | [@ff-labs/pi-fff](https://www.npmjs.com/package/@ff-labs/pi-fff) | 本地 Rust 模糊文件/内容搜索与 `@` 自动补全 |
133
+ | [pi-readseek](https://www.npmjs.com/package/pi-readseek) | Parser-backed code map/search、definition/reference、hashline edit 与 workspace rename;其 edit 可进行带警告的 fuzzy anchor relocation,不等同于严格 stale rejection |
134
+ | [pi-btw](https://www.npmjs.com/package/pi-btw) | 不污染主上下文的并行 `/btw` 旁路对话 |
135
+ | [@mrclrchtr/supi-context](https://www.npmjs.com/package/@mrclrchtr/supi-context) | `/supi-context` 上下文组成与 token 占用报告 |
136
+ | [@tintinweb/pi-subagents](https://www.npmjs.com/package/@tintinweb/pi-subagents) | Claude Code 风格 sub-agents |
137
+ | [@tintinweb/pi-tasks](https://www.npmjs.com/package/@tintinweb/pi-tasks) | Task tracking 与协作 |
138
+ | [@quintinshaw/pi-dynamic-workflows](https://www.npmjs.com/package/@quintinshaw/pi-dynamic-workflows) | 动态 workflows |
139
+
140
+ 这些包位于普通 npm `dependencies`,安装 preset 时由 npm 获取,不会塞入 `1st-pi` tarball。`extensions/packages/*.ts` 是只负责调用 dependency extension entrypoint 的 thin adapters;因此依赖可以正常 hoist,同时 Pi manifest 只引用本包内稳定路径。FFF 也会由 npm 在 macOS、Linux 和 Windows 上选择正确的原生 binary。
141
+
142
+ Themes 以及 `pi-init` / `pi-web-access` skills 是发布所需的静态资源,会从锁定依赖同步到本包。更新 dependencies 后运行:
143
+
144
+ ```bash
145
+ npm run sync:resources
146
+ npm run check:resources
147
+ ```
148
+
149
+ `prepack` 会执行相同校验,防止静态副本与依赖版本漂移。
150
+
151
+ TUI 与 tool ownership:
152
+
153
+ - `pi-everforest-tui`:全局主题、editor chrome、working/status/footer、Command Center 与 Theme Lab
154
+ - `@ff-labs/pi-fff`:preset 默认使用 `override` mode,由 FFF 接管 `find`、`grep` 与 `@` autocomplete
155
+ - `pi-readseek`:通过 `readseek.replacedTools` 接管 `read`、`edit`、`write`;结构导航和 hashline 工具继续使用 `readSeek_*` 名称,不与 FFF 争夺 `grep`
156
+ - Pi built-ins:继续负责 `bash`、`ls` 及其原生渲染
157
+ - `pi-mcp-adapter`:负责 MCP 工具与渲染
158
+ - Tasks、Subagents、Workflows、Goal、BTW、Context 与 Memory:继续使用各 package 自己的领域 UI
159
+
160
+ `pi-tool-display` 已移除,因为它会注册同名的 `read/edit/write/find/grep` overrides,与 Readseek/FFF 形成双重 owner。
161
+
162
+ 要启用上述 Readseek ownership,在 `~/.pi/agent/settings.json` 中加入:
163
+
164
+ ```json
165
+ {
166
+ "readseek": {
167
+ "replacedTools": ["read", "edit", "write"]
168
+ }
169
+ }
170
+ ```
171
+
172
+ `grep` 不加入该数组,因为它由 FFF 接管。修改后运行 `/reload`。
173
+
174
+ ## Preset maintenance skill
175
+
176
+ 添加或移除 community extension 时使用:
177
+
178
+ ```text
179
+ /skill:add-extension-to-1st-agent
180
+ ```
181
+
182
+ 该 SOP 覆盖 license/compatibility/ownership gate、thin adapter、README 同步、hoisted npm 安装、native binary、tarball size 与 clean-room smoke tests。
183
+
184
+ ## 发布
185
+
186
+ ```bash
187
+ npm login
188
+ npm publish
189
+ ```
190
+
191
+ 发布前建议检查包内容:
192
+
193
+ ```bash
194
+ npm pack --dry-run
195
+ ```
196
+
197
+ ## License
198
+
199
+ MIT
@@ -0,0 +1,157 @@
1
+ /**
2
+ * 1st Agent Header
3
+ *
4
+ * Replaces Pi's built-in header with a branded welcome panel.
5
+ */
6
+
7
+ import { basename } from "node:path";
8
+ import { VERSION, type ExtensionAPI, type Theme } from "@earendil-works/pi-coding-agent";
9
+ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
10
+
11
+ const WORDMARK = [
12
+ " ___ __ __ ",
13
+ " < /____/ /_ ____ _____ ____ ____ / /_",
14
+ " / / ___/ __/_____/ __ `/ __ `/ _ \\/ __ \\/ __/",
15
+ " / (__ ) /_/_____/ /_/ / /_/ / __/ / / / /_ ",
16
+ "/_/____/\\__/ \\__,_/\\__, /\\___/_/ /_/\\__/ ",
17
+ " /____/",
18
+ ];
19
+
20
+ const MASCOT = [
21
+ " ▄▄▄ ",
22
+ " ▄█████▄ ",
23
+ " ▐██ ◉ ██▌ ",
24
+ " ▀█████▀ ",
25
+ " ▀█ █▀ ",
26
+ " ▀ ▀ ",
27
+ ];
28
+
29
+ const MAX_PANEL_WIDTH = 110;
30
+ const WORDMARK_WIDTH = Math.max(...WORDMARK.map((line) => visibleWidth(line)));
31
+ const MASCOT_WIDTH = Math.max(...MASCOT.map((line) => visibleWidth(line)));
32
+
33
+ type Alignment = "left" | "center";
34
+
35
+ interface HeaderMeta {
36
+ cwd: string;
37
+ model: string;
38
+ thinking: string;
39
+ }
40
+
41
+ function colorizeWordmark(theme: Theme, line: string): string {
42
+ const paddedLine = line.padEnd(WORDMARK_WIDTH);
43
+ const firstBreak = Math.min(18, paddedLine.length);
44
+ const secondBreak = Math.min(36, paddedLine.length);
45
+
46
+ return [
47
+ theme.fg("warning", paddedLine.slice(0, firstBreak)),
48
+ theme.fg("accent", paddedLine.slice(firstBreak, secondBreak)),
49
+ theme.fg("success", paddedLine.slice(secondBreak)),
50
+ ].join("");
51
+ }
52
+
53
+ function colorizeMascot(theme: Theme, line: string, row: number): string {
54
+ const colors = ["warning", "warning", "accent", "accent", "success", "success"] as const;
55
+ return theme.bold(theme.fg(colors[row], line.padEnd(MASCOT_WIDTH)));
56
+ }
57
+
58
+ function panelLine(theme: Theme, content: string, innerWidth: number, alignment: Alignment = "left"): string {
59
+ const clipped = truncateToWidth(content, innerWidth, "");
60
+ const padding = Math.max(0, innerWidth - visibleWidth(clipped));
61
+ const leftPadding = alignment === "center" ? Math.floor(padding / 2) : Math.min(1, padding);
62
+ const rightPadding = padding - leftPadding;
63
+
64
+ return [
65
+ theme.fg("borderAccent", "│"),
66
+ " ".repeat(leftPadding),
67
+ clipped,
68
+ " ".repeat(rightPadding),
69
+ theme.fg("borderAccent", "│"),
70
+ ].join("");
71
+ }
72
+
73
+ function topBorder(theme: Theme, innerWidth: number): string {
74
+ const title = " 1ST AGENT ";
75
+ const prefix = "╭───";
76
+ const suffix = "╮";
77
+ const fill = Math.max(0, innerWidth + 2 - visibleWidth(prefix) - visibleWidth(title) - visibleWidth(suffix));
78
+
79
+ if (fill === 0) return theme.fg("borderAccent", `╭${"─".repeat(innerWidth)}╮`);
80
+
81
+ return [
82
+ theme.fg("borderAccent", prefix),
83
+ theme.bold(theme.fg("warning", title)),
84
+ theme.fg("borderAccent", `${"─".repeat(fill)}${suffix}`),
85
+ ].join("");
86
+ }
87
+
88
+ function divider(theme: Theme, innerWidth: number): string {
89
+ return theme.fg("borderAccent", `├${"─".repeat(innerWidth)}┤`);
90
+ }
91
+
92
+ function bottomBorder(theme: Theme, innerWidth: number): string {
93
+ return theme.fg("borderAccent", `╰${"─".repeat(innerWidth)}╯`);
94
+ }
95
+
96
+ function buildHeader(theme: Theme, width: number, meta: HeaderMeta): string[] {
97
+ if (width < 2) return [];
98
+
99
+ const panelWidth = Math.min(width, MAX_PANEL_WIDTH);
100
+ const innerWidth = panelWidth - 2;
101
+ const lockupWidth = MASCOT_WIDTH + 3 + WORDMARK_WIDTH;
102
+ const showMascot = innerWidth >= lockupWidth + 4;
103
+ const lines = ["", topBorder(theme, innerWidth), panelLine(theme, "", innerWidth)];
104
+
105
+ for (let row = 0; row < WORDMARK.length; row++) {
106
+ const wordmark = colorizeWordmark(theme, WORDMARK[row]);
107
+ const lockup = showMascot ? `${colorizeMascot(theme, MASCOT[row], row)} ${wordmark}` : wordmark;
108
+ lines.push(panelLine(theme, lockup, innerWidth, "center"));
109
+ }
110
+
111
+ lines.push(panelLine(theme, "", innerWidth));
112
+ lines.push(divider(theme, innerWidth));
113
+ lines.push(
114
+ panelLine(
115
+ theme,
116
+ `${theme.bold(theme.fg("accent", "EST7"))}${theme.fg("dim", " // FIELD UNIT 01 // FIRST IN, LAST OUT")}`,
117
+ innerWidth,
118
+ "center",
119
+ ),
120
+ );
121
+ lines.push(
122
+ panelLine(
123
+ theme,
124
+ theme.fg("muted", `${meta.cwd} · ${meta.model} · thinking ${meta.thinking} · π v${VERSION}`),
125
+ innerWidth,
126
+ "center",
127
+ ),
128
+ );
129
+ lines.push(bottomBorder(theme, innerWidth), "");
130
+
131
+ return lines;
132
+ }
133
+
134
+ export default function customHeader(pi: ExtensionAPI) {
135
+ pi.on("session_start", async (_event, ctx) => {
136
+ if (ctx.mode !== "tui") return;
137
+
138
+ const meta: HeaderMeta = {
139
+ cwd: basename(ctx.cwd) || ctx.cwd,
140
+ model: ctx.model?.id ?? "no model",
141
+ thinking: pi.getThinkingLevel(),
142
+ };
143
+
144
+ ctx.ui.setHeader((_tui, theme) => ({
145
+ render: (width: number) => buildHeader(theme, width, meta),
146
+ invalidate() {},
147
+ }));
148
+ });
149
+
150
+ pi.registerCommand("builtin-header", {
151
+ description: "Restore Pi's built-in header",
152
+ handler: async (_args, ctx) => {
153
+ ctx.ui.setHeader(undefined);
154
+ ctx.ui.notify("Built-in header restored", "info");
155
+ },
156
+ });
157
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 1st-pi defaults for the bundled pi-everforest-tui package.
3
+ *
4
+ * Standalone installs stay opt-in. Fresh 1st-pi sessions start with the full
5
+ * Everforest TUI experience, while session-persisted user choices still win.
6
+ */
7
+
8
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
+
10
+ export default function everforestDefaults(pi: ExtensionAPI) {
11
+ pi.events.emit("everforest-tui:defaults", {
12
+ indicator: true,
13
+ status: true,
14
+ footer: true,
15
+ rainbow: true,
16
+ });
17
+ }
@@ -0,0 +1 @@
1
+ export { default } from "@juicesharp/rpiv-ask-user-question";
@@ -0,0 +1 @@
1
+ export { default } from "pi-btw/extensions/btw.ts";
@@ -0,0 +1 @@
1
+ export { default } from "pi-everforest-tui/extensions/everforest-tui.ts";
@@ -0,0 +1,12 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import registerFff from "@ff-labs/pi-fff/src/index.ts";
3
+
4
+ export default function fffAdapter(pi: ExtensionAPI): void {
5
+ const configuredMode = process.env.PI_FFF_MODE;
6
+ if (!configuredMode) process.env.PI_FFF_MODE = "override";
7
+ try {
8
+ registerFff(pi);
9
+ } finally {
10
+ if (!configuredMode) delete process.env.PI_FFF_MODE;
11
+ }
12
+ }
@@ -0,0 +1 @@
1
+ export { default } from "@narumitw/pi-goal/src/goal.ts";
@@ -0,0 +1 @@
1
+ export { default } from "pi-mcp-adapter/index.ts";
@@ -0,0 +1 @@
1
+ export { default } from "pi-observational-memory/src/index.ts";
@@ -0,0 +1 @@
1
+ export { default } from "pi-readseek";
@@ -0,0 +1 @@
1
+ export { default } from "pi-session-name/src/index.ts";
@@ -0,0 +1 @@
1
+ export { default } from "@tintinweb/pi-subagents/src/index.ts";
@@ -0,0 +1 @@
1
+ export { default } from "@mrclrchtr/supi-context/extension";
@@ -0,0 +1 @@
1
+ export { default } from "@tintinweb/pi-tasks/src/index.ts";
@@ -0,0 +1 @@
1
+ export { default } from "pi-web-access/index.ts";
@@ -0,0 +1,8 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+
3
+ export default async function workflowAdapter(pi: ExtensionAPI): Promise<void> {
4
+ const packageEntry = import.meta.resolve("@quintinshaw/pi-dynamic-workflows");
5
+ const extensionUrl = new URL("../extensions/workflow.ts", packageEntry);
6
+ const { default: registerWorkflow } = await import(extensionUrl.href);
7
+ registerWorkflow(pi);
8
+ }
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "1st-pi",
3
+ "version": "0.1.0",
4
+ "description": "est7's Pi coding agent preset — skills, extensions, prompts, and themes.",
5
+ "license": "MIT",
6
+ "author": "est7",
7
+ "type": "module",
8
+ "keywords": [
9
+ "pi-package",
10
+ "pi",
11
+ "pi-agent",
12
+ "preset",
13
+ "skills",
14
+ "extensions",
15
+ "prompts",
16
+ "themes"
17
+ ],
18
+ "files": [
19
+ "extensions",
20
+ "skills",
21
+ "prompts",
22
+ "themes",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/est7/1st-pi.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/est7/1st-pi/issues"
32
+ },
33
+ "homepage": "https://github.com/est7/1st-pi#readme",
34
+ "dependencies": {
35
+ "@ff-labs/pi-fff": "^0.9.6",
36
+ "@juicesharp/rpiv-ask-user-question": "^1.20.0",
37
+ "@mrclrchtr/supi-context": "^2.4.0",
38
+ "@narumitw/pi-goal": "^0.15.1",
39
+ "@quintinshaw/pi-dynamic-workflows": "^2.13.1",
40
+ "@tintinweb/pi-subagents": "^0.14.1",
41
+ "@tintinweb/pi-tasks": "^0.7.1",
42
+ "pi-btw": "^0.4.1",
43
+ "pi-everforest-tui": "^0.2.0",
44
+ "pi-init": "^1.0.0",
45
+ "pi-mcp-adapter": "^2.11.0",
46
+ "pi-observational-memory": "^3.0.3",
47
+ "pi-readseek": "^0.6.6",
48
+ "pi-session-name": "^0.1.2",
49
+ "pi-web-access": "^0.13.0"
50
+ },
51
+ "scripts": {
52
+ "sync:resources": "node scripts/sync-package-resources.mjs",
53
+ "check:resources": "node scripts/sync-package-resources.mjs --check",
54
+ "prepack": "npm run check:resources",
55
+ "pack:dry-run": "npm pack --dry-run --json"
56
+ },
57
+ "peerDependencies": {
58
+ "@earendil-works/pi-coding-agent": "*",
59
+ "@earendil-works/pi-tui": "*"
60
+ },
61
+ "pi": {
62
+ "extensions": [
63
+ "./extensions/packages/workflow.ts",
64
+ "./extensions/packages/everforest.ts",
65
+ "./extensions/everforest-defaults.ts",
66
+ "./extensions/custom-header.ts",
67
+ "./extensions/packages/ask-user.ts",
68
+ "./extensions/packages/goal.ts",
69
+ "./extensions/packages/observational-memory.ts",
70
+ "./extensions/packages/fff.ts",
71
+ "./extensions/packages/readseek.ts",
72
+ "./extensions/packages/btw.ts",
73
+ "./extensions/packages/supi-context.ts",
74
+ "./extensions/packages/web-access.ts",
75
+ "./extensions/packages/mcp-adapter.ts",
76
+ "./extensions/packages/session-name.ts",
77
+ "./extensions/packages/tasks.ts",
78
+ "./extensions/packages/subagents.ts"
79
+ ],
80
+ "skills": [
81
+ "./skills"
82
+ ],
83
+ "prompts": [
84
+ "./prompts"
85
+ ],
86
+ "themes": [
87
+ "./themes"
88
+ ]
89
+ }
90
+ }
File without changes
File without changes
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: add-extension-to-1st-agent
3
+ description: Add, update, trial, or remove a community Pi extension in the 1st-pi preset without creating duplicate owners, bloating the tarball, breaking hoisted npm installs, or drifting the README. Use whenever changing 1st-pi package dependencies or extension inventory.
4
+ ---
5
+
6
+ # Add an extension to 1st-pi
7
+
8
+ Follow this SOP; do not add a package from its README alone.
9
+
10
+ ## 1. Gate the candidate
11
+
12
+ Check the published package and primary source:
13
+
14
+ - npm version, license, repository, engines, peer dependencies, install scripts
15
+ - upstream Pi/Node compatibility and native platform coverage
16
+ - maintenance and release recency
17
+ - tool, command, editor, footer, renderer, persistence, and domain ownership overlap
18
+
19
+ Reject duplicate owners unless the user explicitly chooses which existing owner to remove or disable.
20
+
21
+ ## 2. Install as a normal dependency
22
+
23
+ ```bash
24
+ npm install <package>@<version>
25
+ ```
26
+
27
+ Do **not** add `bundledDependencies`. npm installs runtime dependencies; bundling their transitive graph bloats the preset.
28
+
29
+ ## 3. Add a thin adapter
30
+
31
+ Create `extensions/packages/<name>.ts`:
32
+
33
+ ```ts
34
+ export { default } from "<package-or-exported-subpath>";
35
+ ```
36
+
37
+ Reference that local adapter explicitly in `package.json#pi.extensions`. Keep owner-sensitive ordering explicit. If package exports block its extension subpath, resolve its public entry and use the smallest documented dynamic adapter; do not copy the package implementation.
38
+
39
+ Static skills/themes needed by Pi must live inside this package. Add them to `scripts/sync-package-resources.mjs` so `npm run check:resources` prevents dependency drift.
40
+
41
+ ## 4. Resolve ownership before testing
42
+
43
+ For every built-in or shared surface, record one owner only:
44
+
45
+ - tool names such as `read`, `edit`, `write`, `find`, `grep`
46
+ - tool/diff renderers
47
+ - editor factory, footer, status, and overlays
48
+ - memory, tasks, subagents, workflows, goals, and context analysis
49
+
50
+ Never rely on load order to hide a registration conflict. Remove, disable, or configure the losing owner deliberately.
51
+
52
+ ## 5. Keep documentation synchronized
53
+
54
+ Update `README.md` in the same change:
55
+
56
+ - dependency inventory and purpose
57
+ - defaults and commands/tools
58
+ - ownership and overlap decisions
59
+ - native, license, fuzzy/stale, telemetry, or external-process caveats
60
+ - removal instructions when configuration persists outside the package
61
+
62
+ Update relevant audits when a prior recommendation or ownership baseline changed.
63
+
64
+ ## 6. Verify both layouts
65
+
66
+ Run:
67
+
68
+ ```bash
69
+ npm run check:resources
70
+ npm audit --omit=dev
71
+ npm pack --dry-run --json
72
+ git diff --check
73
+ ```
74
+
75
+ Then verify:
76
+
77
+ 1. local source: `pi --no-extensions -e .`
78
+ 2. packed tarball installed into a fresh npm project with dependencies hoisted beside `1st-pi`
79
+ 3. Pi loading the installed `node_modules/1st-pi`
80
+ 4. no extension/tool/command conflicts
81
+ 5. native binary availability on the current platform
82
+ 6. package size remains within the small preset budget
83
+ 7. `/reload` and the candidate's primary command/tool path
84
+
85
+ A startup-only test is insufficient for mutating, native, persistence, or network behavior; exercise its risky path in a disposable fixture.
86
+
87
+ ## 7. Finish or revert
88
+
89
+ If verification passes, commit dependency, lockfile, adapter, resources, tests, and README together. If it fails, remove the package and adapter completely; do not leave disabled or undocumented inventory behind.
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: init
3
+ description: Initialize or update AGENTS.md. Guides the agent to autonomously analyze the codebase and generate a high-quality context file.
4
+ ---
5
+
6
+ # Init Skill
7
+
8
+ This skill defines the standard for creating an `AGENTS.md` file. Instead of following a rigid script, use your judgment and exploration tools to understand the project deeply before documenting it.
9
+
10
+ ## Objective
11
+ Create a "readme for robots" (`AGENTS.md`) that accelerates understanding for future AI sessions. It must include the project's stack, structure, workflows, and coding standards.
12
+
13
+ ## Workflow
14
+
15
+ ### 1. Autonomous Discovery
16
+ Explore the repository to build a mental model of the project. You determine which files to read.
17
+
18
+ * **Identify Stack**: Determine the languages, frameworks, and build tools in use.
19
+ * **Extract Workflows**: Find the commands for **installing dependencies**, **running tests**, **building**, and **starting** the project.
20
+ * **Map Structure**: Understand the layout. identify source roots, test directories, and documentation.
21
+ * **Infer Conventions**: Read sample source files to identify coding styles, formatting rules (prettier/eslint/ruff), and architectural patterns (e.g., "functional components", "repository pattern").
22
+
23
+ ### 2. Synthesize & Generate
24
+ Create or update `AGENTS.md` with your findings.
25
+
26
+ #### Target Structure (Template)
27
+ Use this structure as a baseline, but adapt it if the project has unique needs.
28
+
29
+ ```markdown
30
+ # PROJECT KNOWLEDGE BASE
31
+
32
+ **Generated:** {CURRENT_DATE}
33
+
34
+ ## OVERVIEW
35
+ Project: **{PROJECT_NAME}**
36
+ Stack: {TECHNOLOGIES_AND_VERSIONS}
37
+
38
+ ## STRUCTURE
39
+ {TREE_VIEW_OR_KEY_DIRECTORIES_LIST}
40
+ * `{DIR}`: {DESCRIPTION}
41
+
42
+ ## COMMANDS
43
+ | Action | Command |
44
+ |--------|---------|
45
+ | Install| `{CMD}` |
46
+ | Test | `{CMD}` |
47
+ | Build | `{CMD}` |
48
+ | Run | `{CMD}` |
49
+
50
+ ## CODING STANDARDS
51
+ * **Language**: {LANGUAGE_DETAILS}
52
+ * **Style**: {OBSERVED_PATTERNS}
53
+ * **Rules**: {LINTER_OR_FORMATTER_INFO}
54
+
55
+ ## WHERE TO LOOK
56
+ * **Source**: `{PATH}`
57
+ * **Tests**: `{PATH}`
58
+ * **Docs**: `{PATH}`
59
+
60
+ ## NOTES
61
+ * {CRITICAL_CONTEXT_OR_GOTCHAS}
62
+ ```
63
+
64
+ ### 3. Integration
65
+ * **Update intelligently**: If `AGENTS.md` exists, read it first. Merge new insights without overwriting human-authored context.
66
+ * **Context sharing**: If meaningful, mention other context files found (e.g., `.cursorrules`, `CLAUDE.md`).
@@ -0,0 +1,195 @@
1
+ ---
2
+ name: librarian
3
+ description: Research open-source libraries with evidence-backed answers and GitHub permalinks. Use when the user asks about library internals, needs implementation details with source code references, wants to understand why something was changed, or needs authoritative answers backed by actual code. Excels at navigating large open-source repos and providing citations to exact lines of code.
4
+ ---
5
+
6
+ # Librarian
7
+
8
+ Answer questions about open-source libraries by finding evidence with GitHub permalinks. Every claim backed by actual code.
9
+
10
+ ## Execution Model
11
+
12
+ Pi executes tool calls sequentially, even when you emit multiple calls in one turn. But batching independent calls in a single turn still saves LLM round-trips (~5-10s each). Use these patterns:
13
+
14
+ | Pattern | When | Actually parallel? |
15
+ |---------|------|-------------------|
16
+ | Batch tool calls in one turn | Independent ops (web_search + fetch_content + read) | No, but saves round-trips |
17
+ | `fetch_content({ urls: [...] })` | Multiple URLs to fetch | Yes (3 concurrent) |
18
+ | Bash with `&` + `wait` | Multiple git/gh commands | Yes (OS-level) |
19
+
20
+ ## Step 1: Classify the Request
21
+
22
+ Before doing anything, classify the request to pick the right research strategy.
23
+
24
+ | Type | Trigger | Primary Approach |
25
+ |------|---------|-----------------|
26
+ | **Conceptual** | "How do I use X?", "Best practice for Y?" | web_search + fetch_content (README/docs) |
27
+ | **Implementation** | "How does X implement Y?", "Show me the source" | fetch_content (clone) + code search |
28
+ | **Context/History** | "Why was this changed?", "History of X?" | git log + git blame + issue/PR search |
29
+ | **Comprehensive** | Complex or ambiguous requests, "deep dive" | All of the above |
30
+
31
+ ## Step 2: Research by Type
32
+
33
+ ### Conceptual Questions
34
+
35
+ Batch these in one turn:
36
+
37
+ 1. **web_search**: `"library-name topic"` via Perplexity for recent articles and discussions
38
+ 2. **fetch_content**: the library's GitHub repo URL to clone and check README, docs, or examples
39
+
40
+ Synthesize web results + repo docs. Cite official documentation and link to relevant source files.
41
+
42
+ ### Implementation Questions
43
+
44
+ The core workflow -- clone, find, permalink:
45
+
46
+ 1. **fetch_content** the GitHub repo URL -- this clones it locally and returns the file tree
47
+ 2. Use **bash** to search the cloned repo: `grep -rn "function_name"`, `find . -name "*.ts"`
48
+ 3. Use **read** to examine specific files once you've located them
49
+ 4. Get the commit SHA: `cd /tmp/pi-github-repos/owner/repo && git rev-parse HEAD`
50
+ 5. Construct permalink: `https://github.com/owner/repo/blob/<sha>/path/to/file#L10-L20`
51
+
52
+ Batch the initial calls: fetch_content (clone) + web_search (recent discussions) in one turn. Then dig into the clone with grep/read once it's available.
53
+
54
+ ### Context/History Questions
55
+
56
+ Use git operations on the cloned repo:
57
+
58
+ ```bash
59
+ cd /tmp/pi-github-repos/owner/repo
60
+
61
+ # Recent changes to a specific file
62
+ git log --oneline -n 20 -- path/to/file.ts
63
+
64
+ # Who changed what and when
65
+ git blame -L 10,30 path/to/file.ts
66
+
67
+ # Full diff for a specific commit
68
+ git show <sha> -- path/to/file.ts
69
+
70
+ # Search commit messages
71
+ git log --oneline --grep="keyword" -n 10
72
+ ```
73
+
74
+ For issues and PRs, use bash:
75
+
76
+ ```bash
77
+ # Search issues
78
+ gh search issues "keyword" --repo owner/repo --state all --limit 10
79
+
80
+ # Search merged PRs
81
+ gh search prs "keyword" --repo owner/repo --state merged --limit 10
82
+
83
+ # View specific issue/PR with comments
84
+ gh issue view <number> --repo owner/repo --comments
85
+ gh pr view <number> --repo owner/repo --comments
86
+
87
+ # Release notes
88
+ gh api repos/owner/repo/releases --jq '.[0:5] | .[].tag_name'
89
+ ```
90
+
91
+ ### Comprehensive Research
92
+
93
+ Combine everything. Batch these in one turn:
94
+
95
+ 1. **web_search**: recent articles and discussions
96
+ 2. **fetch_content**: clone the repo (or multiple repos if comparing)
97
+ 3. **bash**: `gh search issues "keyword" --repo owner/repo --limit 10 & gh search prs "keyword" --repo owner/repo --state merged --limit 10 & wait`
98
+
99
+ Then dig into the clone with grep, read, git blame, git log as needed.
100
+
101
+ ## Step 3: Construct Permalinks
102
+
103
+ Permalinks are the whole point. They make your answers citable and verifiable.
104
+
105
+ ```
106
+ https://github.com/<owner>/<repo>/blob/<commit-sha>/<filepath>#L<start>-L<end>
107
+ ```
108
+
109
+ Getting the SHA from a cloned repo:
110
+
111
+ ```bash
112
+ cd /tmp/pi-github-repos/owner/repo && git rev-parse HEAD
113
+ ```
114
+
115
+ Getting the SHA from a tag:
116
+
117
+ ```bash
118
+ gh api repos/owner/repo/git/refs/tags/v1.0.0 --jq '.object.sha'
119
+ ```
120
+
121
+ Always use full commit SHAs, not branch names. Branch links break when code changes. Permalinks don't.
122
+
123
+ ## Step 4: Cite Everything
124
+
125
+ Every code-related claim needs a permalink. Format:
126
+
127
+ ```markdown
128
+ The stale time check happens in [`notifyManager.ts`](https://github.com/TanStack/query/blob/abc123/packages/query-core/src/notifyManager.ts#L42-L50):
129
+
130
+ \`\`\`typescript
131
+ function isStale(query: Query, staleTime: number): boolean {
132
+ return query.state.dataUpdatedAt + staleTime < Date.now()
133
+ }
134
+ \`\`\`
135
+ ```
136
+
137
+ For conceptual answers, link to official docs and relevant source files. For implementation answers, every function/class reference should have a permalink.
138
+
139
+ ## Video Analysis
140
+
141
+ For questions about video tutorials, conference talks, or screen recordings:
142
+
143
+ ```typescript
144
+ // Full extraction (transcript + visual descriptions)
145
+ fetch_content({ url: "https://youtube.com/watch?v=abc" })
146
+
147
+ // Ask a specific question about a video
148
+ fetch_content({ url: "https://youtube.com/watch?v=abc", prompt: "What libraries are imported in this tutorial?" })
149
+
150
+ // Single frame at a known moment
151
+ fetch_content({ url: "https://youtube.com/watch?v=abc", timestamp: "23:41" })
152
+
153
+ // Range scan for visual discovery
154
+ fetch_content({ url: "https://youtube.com/watch?v=abc", timestamp: "23:41-25:00" })
155
+
156
+ // Custom density across a range
157
+ fetch_content({ url: "https://youtube.com/watch?v=abc", timestamp: "23:41-25:00", frames: 3 })
158
+
159
+ // Whole-video sampling
160
+ fetch_content({ url: "https://youtube.com/watch?v=abc", frames: 6 })
161
+
162
+ // Analyze a local recording
163
+ fetch_content({ url: "/path/to/demo.mp4", prompt: "What error message appears on screen?" })
164
+
165
+ // Batch multiple videos with the same question
166
+ fetch_content({
167
+ urls: ["https://youtube.com/watch?v=abc", "https://youtube.com/watch?v=def"],
168
+ prompt: "What packages are installed?"
169
+ })
170
+ ```
171
+
172
+ Use single timestamps for known moments, ranges for visual scanning, and frames-alone for a quick overview of the whole video.
173
+
174
+ The `prompt` parameter only applies to video content (YouTube URLs and local video files). For non-video URLs, it's ignored.
175
+
176
+ ## Failure Recovery
177
+
178
+ | Failure | Recovery |
179
+ |---------|----------|
180
+ | grep finds nothing | Broaden the query, try concept names instead of exact function names |
181
+ | gh CLI rate limited | Use the already-cloned repo in /tmp/pi-github-repos/ for git operations |
182
+ | Repo too large to clone | fetch_content returns an API-only view automatically; use that or add `forceClone: true` |
183
+ | File not found in clone | Branch name with slashes may have misresolved; list the repo tree and navigate manually |
184
+ | Uncertain about implementation | State your uncertainty explicitly, propose a hypothesis, show what evidence you did find |
185
+ | Video extraction fails | Ensure Chrome is signed into gemini.google.com (free) or set GEMINI_API_KEY |
186
+ | Page returns 403/bot block | Gemini fallback triggers automatically; no action needed if Gemini is configured |
187
+ | web_search fails | Check provider config; try explicit `provider: "gemini"` if Perplexity key is missing |
188
+
189
+ ## Guidelines
190
+
191
+ - Vary search queries when running multiple searches -- different angles, not the same pattern repeated
192
+ - Prefer recent sources; filter out outdated results when they conflict with newer information
193
+ - For version-specific questions, clone the tagged version: `fetch_content("https://github.com/owner/repo/tree/v1.0.0")`
194
+ - When the repo is already cloned from a previous fetch_content call, reuse it -- check the path before cloning again
195
+ - Answer directly. Skip preamble like "I'll help you with..." -- go straight to findings
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
+ "name": "everforest-tui-dark",
4
+ "vars": {
5
+ "base": "#323d43",
6
+ "mantle": "#2d353b",
7
+ "surface0": "#3a464c",
8
+ "surface1": "#434f55",
9
+ "surface2": "#4b565c",
10
+ "text": "#d3c6aa",
11
+ "subtext1": "#c3bea9",
12
+ "subtext0": "#b0b5a4",
13
+ "overlay": "#a7afa3",
14
+ "red": "#e67e80",
15
+ "orange": "#e69875",
16
+ "yellow": "#dbbc7f",
17
+ "green": "#a7c080",
18
+ "aqua": "#83c092",
19
+ "blue": "#7fbbb3",
20
+ "purple": "#d699b6",
21
+ "redBg": "#4b3f42",
22
+ "greenBg": "#3f4b43",
23
+ "blueBg": "#39464c"
24
+ },
25
+ "colors": {
26
+ "accent": "aqua",
27
+ "border": "blue",
28
+ "borderAccent": "aqua",
29
+ "borderMuted": "surface2",
30
+ "success": "green",
31
+ "error": "red",
32
+ "warning": "yellow",
33
+ "muted": "subtext0",
34
+ "dim": "overlay",
35
+ "text": "text",
36
+ "thinkingText": "subtext1",
37
+ "selectedBg": "surface1",
38
+ "userMessageBg": "surface0",
39
+ "userMessageText": "text",
40
+ "customMessageBg": "mantle",
41
+ "customMessageText": "text",
42
+ "customMessageLabel": "purple",
43
+ "toolPendingBg": "blueBg",
44
+ "toolSuccessBg": "greenBg",
45
+ "toolErrorBg": "redBg",
46
+ "toolTitle": "blue",
47
+ "toolOutput": "subtext1",
48
+ "mdHeading": "yellow",
49
+ "mdLink": "blue",
50
+ "mdLinkUrl": "subtext0",
51
+ "mdCode": "aqua",
52
+ "mdCodeBlock": "green",
53
+ "mdCodeBlockBorder": "surface2",
54
+ "mdQuote": "subtext0",
55
+ "mdQuoteBorder": "surface2",
56
+ "mdHr": "surface2",
57
+ "mdListBullet": "aqua",
58
+ "toolDiffAdded": "green",
59
+ "toolDiffRemoved": "red",
60
+ "toolDiffContext": "subtext0",
61
+ "syntaxComment": "subtext0",
62
+ "syntaxKeyword": "red",
63
+ "syntaxFunction": "green",
64
+ "syntaxVariable": "blue",
65
+ "syntaxString": "aqua",
66
+ "syntaxNumber": "purple",
67
+ "syntaxType": "yellow",
68
+ "syntaxOperator": "orange",
69
+ "syntaxPunctuation": "text",
70
+ "thinkingOff": "surface2",
71
+ "thinkingMinimal": "overlay",
72
+ "thinkingLow": "blue",
73
+ "thinkingMedium": "aqua",
74
+ "thinkingHigh": "purple",
75
+ "thinkingXhigh": "red",
76
+ "thinkingMax": "orange",
77
+ "bashMode": "green"
78
+ },
79
+ "export": {
80
+ "pageBg": "#323d43",
81
+ "cardBg": "#2d353b",
82
+ "infoBg": "#3a464c"
83
+ }
84
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
+ "name": "everforest-tui-light",
4
+ "vars": {
5
+ "base": "#f8f0dc",
6
+ "mantle": "#f3ead3",
7
+ "surface0": "#eee7d2",
8
+ "surface1": "#e5dfc5",
9
+ "surface2": "#dfddc8",
10
+ "text": "#5c6a72",
11
+ "subtext1": "#5c6a72",
12
+ "subtext0": "#596a66",
13
+ "overlay": "#65756f",
14
+ "red": "#f85552",
15
+ "orange": "#f57d26",
16
+ "yellow": "#dfa000",
17
+ "green": "#8da101",
18
+ "aqua": "#35a77c",
19
+ "blue": "#3a94c5",
20
+ "purple": "#df69ba",
21
+ "redBg": "#f4e3df",
22
+ "greenBg": "#edf0df",
23
+ "blueBg": "#e7edf0"
24
+ },
25
+ "colors": {
26
+ "accent": "aqua",
27
+ "border": "blue",
28
+ "borderAccent": "aqua",
29
+ "borderMuted": "surface2",
30
+ "success": "green",
31
+ "error": "red",
32
+ "warning": "yellow",
33
+ "muted": "subtext0",
34
+ "dim": "overlay",
35
+ "text": "text",
36
+ "thinkingText": "subtext1",
37
+ "selectedBg": "surface1",
38
+ "userMessageBg": "surface0",
39
+ "userMessageText": "text",
40
+ "customMessageBg": "mantle",
41
+ "customMessageText": "text",
42
+ "customMessageLabel": "purple",
43
+ "toolPendingBg": "blueBg",
44
+ "toolSuccessBg": "greenBg",
45
+ "toolErrorBg": "redBg",
46
+ "toolTitle": "blue",
47
+ "toolOutput": "subtext1",
48
+ "mdHeading": "yellow",
49
+ "mdLink": "blue",
50
+ "mdLinkUrl": "subtext0",
51
+ "mdCode": "aqua",
52
+ "mdCodeBlock": "green",
53
+ "mdCodeBlockBorder": "surface2",
54
+ "mdQuote": "subtext0",
55
+ "mdQuoteBorder": "surface2",
56
+ "mdHr": "surface2",
57
+ "mdListBullet": "aqua",
58
+ "toolDiffAdded": "green",
59
+ "toolDiffRemoved": "red",
60
+ "toolDiffContext": "subtext0",
61
+ "syntaxComment": "subtext0",
62
+ "syntaxKeyword": "red",
63
+ "syntaxFunction": "green",
64
+ "syntaxVariable": "blue",
65
+ "syntaxString": "aqua",
66
+ "syntaxNumber": "purple",
67
+ "syntaxType": "yellow",
68
+ "syntaxOperator": "orange",
69
+ "syntaxPunctuation": "text",
70
+ "thinkingOff": "surface2",
71
+ "thinkingMinimal": "overlay",
72
+ "thinkingLow": "blue",
73
+ "thinkingMedium": "aqua",
74
+ "thinkingHigh": "purple",
75
+ "thinkingXhigh": "red",
76
+ "thinkingMax": "orange",
77
+ "bashMode": "green"
78
+ },
79
+ "export": {
80
+ "pageBg": "#f8f0dc",
81
+ "cardBg": "#f3ead3",
82
+ "infoBg": "#eee7d2"
83
+ }
84
+ }