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 +21 -0
- package/README.md +199 -0
- package/extensions/custom-header.ts +157 -0
- package/extensions/everforest-defaults.ts +17 -0
- package/extensions/packages/ask-user.ts +1 -0
- package/extensions/packages/btw.ts +1 -0
- package/extensions/packages/everforest.ts +1 -0
- package/extensions/packages/fff.ts +12 -0
- package/extensions/packages/goal.ts +1 -0
- package/extensions/packages/mcp-adapter.ts +1 -0
- package/extensions/packages/observational-memory.ts +1 -0
- package/extensions/packages/readseek.ts +1 -0
- package/extensions/packages/session-name.ts +1 -0
- package/extensions/packages/subagents.ts +1 -0
- package/extensions/packages/supi-context.ts +1 -0
- package/extensions/packages/tasks.ts +1 -0
- package/extensions/packages/web-access.ts +1 -0
- package/extensions/packages/workflow.ts +8 -0
- package/package.json +90 -0
- package/prompts/.gitkeep +0 -0
- package/skills/.gitkeep +0 -0
- package/skills/add-extension-to-1st-agent/SKILL.md +89 -0
- package/skills/init/SKILL.md +66 -0
- package/skills/librarian/SKILL.md +195 -0
- package/themes/everforest-tui-dark.json +84 -0
- package/themes/everforest-tui-light.json +84 -0
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
|
+
}
|
package/prompts/.gitkeep
ADDED
|
File without changes
|
package/skills/.gitkeep
ADDED
|
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
|
+
}
|