@vs4vijay/piverse 0.1.0 → 0.6.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/.agents/skills/pi-extension/SKILL.md +229 -0
- package/.github/workflows/ci.yml +18 -0
- package/.github/workflows/release.yml +106 -0
- package/LICENSE +21 -0
- package/README.md +70 -27
- package/extensions/pi-notes/README.md +152 -0
- package/extensions/pi-notes/package.json +31 -0
- package/extensions/pi-notes/plan.md +151 -0
- package/extensions/pi-notes/src/index.ts +369 -0
- package/extensions/pi-notes/src/store.ts +229 -0
- package/extensions/pi-notes/src/tui.ts +426 -0
- package/extensions/pi-notes/src/types.ts +60 -0
- package/extensions/pi-queue/README.md +178 -0
- package/extensions/pi-queue/package.json +14 -1
- package/extensions/pi-queue/plan.md +79 -0
- package/extensions/pi-queue/src/index.ts +136 -28
- package/package.json +21 -5
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pi-extension
|
|
3
|
+
description: Scaffold a new Pi coding-agent extension in the piverse monorepo following the established project structure, naming, and code conventions. Use when adding a new extension (a `pi-<name>` package under `extensions/`), creating its src/index.ts entry, README, and package.json, or when asked to "add another extension", "onboard a new extension", or "create a pi extension".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Creating a Pi extension in piverse
|
|
7
|
+
|
|
8
|
+
This skill encodes the conventions used by the existing extensions in this repo
|
|
9
|
+
(`pi-queue`, `pi-notes`). Follow them exactly so new extensions are consistent,
|
|
10
|
+
publishable to npm, and discoverable on the [pi.dev gallery](https://pi.dev/packages).
|
|
11
|
+
|
|
12
|
+
Read `extensions/pi-queue/` and `extensions/pi-notes/` as living references before
|
|
13
|
+
and while you scaffold.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. Project structure & naming
|
|
18
|
+
|
|
19
|
+
Each extension is its own npm package inside the monorepo root:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
extensions/
|
|
23
|
+
├── pi-queue/ # /queue — message queueing
|
|
24
|
+
├── pi-notes/ # /notes — project notes (CLI + TUI)
|
|
25
|
+
└── pi-<name>/ # <-- NEW extension lives here
|
|
26
|
+
├── src/
|
|
27
|
+
│ └── index.ts # required extension entry point
|
|
28
|
+
├── README.md # required
|
|
29
|
+
├── package.json # required
|
|
30
|
+
└── plan.md # optional (planning notes; tracked like others)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Naming rules
|
|
34
|
+
|
|
35
|
+
- Folder: `extensions/pi-<name>/` — always the `pi-` prefix, lowercase, hyphenated.
|
|
36
|
+
- npm name: `@vs4vijay/pi-<name>` — **always the `@vs4vijay` scope**.
|
|
37
|
+
- Default export registers one or more `/` slash commands. Pick clear, short command
|
|
38
|
+
names. If the extension has several related commands, prefix them (e.g. `pi-queue`
|
|
39
|
+
registers `/queue-*` and `/q-*` aliases).
|
|
40
|
+
- `keywords` must include `"pi-package"` for pi.dev gallery discovery.
|
|
41
|
+
|
|
42
|
+
### tsconfig conventions (repo root, no per-extension change needed)
|
|
43
|
+
|
|
44
|
+
`strict: true`, `module: ESNext`, `moduleResolution: bundler`, `noEmit: true`,
|
|
45
|
+
`verbatimModuleSyntax: true`, `isolatedModules: true`. The root tsconfig includes
|
|
46
|
+
`extensions/*/src/**/*.ts`.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 2. package.json template
|
|
51
|
+
|
|
52
|
+
Copy this shape exactly (values change per extension). Match the existing files'
|
|
53
|
+
field ordering for consistency:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"name": "@vs4vijay/pi-<name>",
|
|
58
|
+
"version": "0.1.0",
|
|
59
|
+
"description": "<one-line: what the /<command> does>",
|
|
60
|
+
"type": "module",
|
|
61
|
+
"keywords": ["pi-package"],
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"repository": {
|
|
64
|
+
"type": "git",
|
|
65
|
+
"url": "git+https://github.com/vs4vijay/piverse.git"
|
|
66
|
+
},
|
|
67
|
+
"author": "vs4vijay",
|
|
68
|
+
"homepage": "https://github.com/vs4vijay/piverse",
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/vs4vijay/piverse/issues"
|
|
71
|
+
},
|
|
72
|
+
"pi": {
|
|
73
|
+
"extensions": ["./src/index.ts"]
|
|
74
|
+
},
|
|
75
|
+
"scripts": {
|
|
76
|
+
"typecheck": "tsc --noEmit"
|
|
77
|
+
},
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
80
|
+
"@earendil-works/pi-tui": "*",
|
|
81
|
+
"typebox": "*"
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"typescript": "^5.0.0"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- The `pi` manifest tells Pi where the resources live: `"extensions": ["./src/index.ts"]`.
|
|
90
|
+
- `peerDependencies` **must** use `"*"` ranges for the bundled Pi core packages
|
|
91
|
+
(`@earendil-works/pi-coding-agent`, `@earendil-works/pi-tui`, `typebox`) — Pi provides
|
|
92
|
+
them at runtime; do not bundle them.
|
|
93
|
+
- If the extension only ships as part of the parent `@vs4vijay/piverse` package, list
|
|
94
|
+
the same resource path in the root `package.json` `pi.extensions` array. Each
|
|
95
|
+
extension normally also ships standalone via its own package (the repo's
|
|
96
|
+
`.github/workflows/release.yml` publishes every `extensions/*/` sub-package).
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3. src/index.ts — extension entry point
|
|
101
|
+
|
|
102
|
+
Use the `ExtensionAPI` type and a default export. This is the canonical structure
|
|
103
|
+
(see `extensions/pi-queue/src/index.ts` and `extensions/pi-notes/src/index.ts`):
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
107
|
+
|
|
108
|
+
export default async function (pi: ExtensionAPI) {
|
|
109
|
+
// Register /<command>
|
|
110
|
+
pi.registerCommand("<command>", {
|
|
111
|
+
description: "<one line: what it does and how to use it>",
|
|
112
|
+
handler: async (args: string, ctx: ExtensionCommandContext) => {
|
|
113
|
+
// args: the raw string after the command name
|
|
114
|
+
// ctx.ui.notify(message, level) — levels: "info" | "warning" | "error"
|
|
115
|
+
ctx.ui.notify(`Hello: ${args}`, "info");
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Key rules
|
|
122
|
+
|
|
123
|
+
- **`import type` for types**: with `verbatimModuleSyntax`, use `import type` when
|
|
124
|
+
importing only types (e.g. `ExtensionAPI`, `ExtensionCommandContext`).
|
|
125
|
+
- **`.js` extensions on relative imports**: ESM/NodeNext-style — `from "./store.js"`,
|
|
126
|
+
not `"./store"`.
|
|
127
|
+
- **No build step**: Pi loads TypeScript extensions directly (via jiti). No compile.
|
|
128
|
+
- **State in closure scope**: keep per-extension state as module/closure variables
|
|
129
|
+
inside the default export (see `pi-queue`'s `let queue`).
|
|
130
|
+
|
|
131
|
+
### Lifecycle hooks
|
|
132
|
+
|
|
133
|
+
Use `pi.on("<event>", handler)` for session lifecycle (see both extensions):
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
pi.on("session_start", async (_event, ctx) => { /* reset/load state */ });
|
|
137
|
+
pi.on("session_shutdown", async () => { /* flush/persist */ });
|
|
138
|
+
pi.on("agent_settled", async (_event, ctx) => { /* run after each turn */ });
|
|
139
|
+
pi.on("tool_result", async (event) => { /* observe tool outcomes */ });
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
When you need state to survive across turns, persist it — either to a file (see the
|
|
143
|
+
store pattern) or to the session (`pi.appendEntry(type, data)` and read it back in
|
|
144
|
+
`session_start` via `ctx.sessionManager.getEntries()` — see `pi-queue`).
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 4. Persistence store pattern (file-backed)
|
|
149
|
+
|
|
150
|
+
For persisted data, create a small `src/store.ts` following `pi-notes/src/store.ts`:
|
|
151
|
+
|
|
152
|
+
- A `class` that wraps read/write, with `load()`, `save()`, `getAll()`, `getById()`,
|
|
153
|
+
`create()`, `update()`, `delete()`, and any domain methods.
|
|
154
|
+
- **Atomic writes**: write to a temp path then `fs.rename` (never write in place).
|
|
155
|
+
- A module-level singleton (`getNoteStore`) with a `reset` function so a fresh
|
|
156
|
+
instance is created per session.
|
|
157
|
+
- **Lifecycle ordering matters**: on `session_start`, `reset()` the store **first**,
|
|
158
|
+
then `getStore(cwd)` and `await store.load()`, so the same loaded instance is used
|
|
159
|
+
all session and the `session_shutdown` flush writes real data (not an emptied one).
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 5. CLI UX
|
|
164
|
+
|
|
165
|
+
- Use `ctx.ui.notify(message, level)` for all user feedback (`info | warning | error`).
|
|
166
|
+
- Use `ctx.ui.confirm(title, message)` for destructive actions that need confirmation.
|
|
167
|
+
- Use `ctx.ui.editor(title, initial)` to open the external editor for multi-line content.
|
|
168
|
+
- Validate input and return early with a usage/error message:
|
|
169
|
+
`ctx.ui.notify("Usage: /<command> <arg>", "error")`.
|
|
170
|
+
- For slash-command dispatch helpers, see `pi-queue/src/index.ts`.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 6. TUI (optional)
|
|
175
|
+
|
|
176
|
+
For interactive full-screen UI, follow `pi-notes/src/tui.ts`:
|
|
177
|
+
|
|
178
|
+
- Build a component class implementing `Focusable` using primitives from
|
|
179
|
+
`@earendil-works/pi-tui` (`VStack`, `HStack`, `Box`, `Text`, `ScrollView`,
|
|
180
|
+
`Markdown`, `SelectList`).
|
|
181
|
+
- Export a factory function (e.g. `create<Name>TUI`) returning `Component & Focusable`.
|
|
182
|
+
- Show it from the extension via `ctx.ui.custom(fn, { overlay: true, overlayOptions })`.
|
|
183
|
+
Note: `OverlayOptions` supports `width`/`maxHeight` (percentages), **not** `height`.
|
|
184
|
+
- Keep a module-level `tuiHandle` you can call to programmatically close/reopen it.
|
|
185
|
+
- Keep TUI state in the component; persist via the store.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 7. README.md
|
|
190
|
+
|
|
191
|
+
Include, in this order (match `pi-queue/README.md` and `pi-notes/README.md`):
|
|
192
|
+
|
|
193
|
+
1. `# @vs4vijay/pi-<name>` heading
|
|
194
|
+
2. One-paragraph description
|
|
195
|
+
3. **Install** — `pi install npm:@vs4vijay/pi-<name>`
|
|
196
|
+
4. **Commands** table (command → description)
|
|
197
|
+
5. **Usage / Examples** — transcript-style examples with realistic output
|
|
198
|
+
6. Any additional sections (How it works, Features, Persistence, TUI, etc.)
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 8. Verification
|
|
203
|
+
|
|
204
|
+
Before finishing:
|
|
205
|
+
|
|
206
|
+
1. Run the typecheck from the repo root and confirm it passes:
|
|
207
|
+
```bash
|
|
208
|
+
npm run typecheck
|
|
209
|
+
```
|
|
210
|
+
2. Quick-test without installing:
|
|
211
|
+
```bash
|
|
212
|
+
pi -e ./extensions/pi-<name>/src/index.ts
|
|
213
|
+
```
|
|
214
|
+
3. Confirm the `package.json` has all required fields (name scope, `pi-package`
|
|
215
|
+
keyword, `pi` manifest, repository, license, peerDependencies with `"*"`).
|
|
216
|
+
4. Add the new extension under `extensions/` and, if it should ship with the parent
|
|
217
|
+
ecosystem package, register it in the root `package.json` `pi.extensions`.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Checklist
|
|
222
|
+
|
|
223
|
+
- [ ] Folder named `extensions/pi-<name>/`
|
|
224
|
+
- [ ] npm name `@vs4vijay/pi-<name>`
|
|
225
|
+
- [ ] `src/index.ts` with default `export default function(pi)` and `registerCommand`
|
|
226
|
+
- [ ] `package.json` with `pi-package` keyword, `pi` manifest, repository/license, peerDeps `"*"`
|
|
227
|
+
- [ ] `README.md` with install + commands + usage examples
|
|
228
|
+
- [ ] `npm run typecheck` passes
|
|
229
|
+
- [ ] Tested with `pi -e`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
validate:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- uses: actions/setup-node@v4
|
|
14
|
+
with:
|
|
15
|
+
node-version: 20
|
|
16
|
+
|
|
17
|
+
- name: Typecheck
|
|
18
|
+
run: npx tsc --noEmit
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
version:
|
|
10
|
+
description: "Release version (e.g., v1.0.0)"
|
|
11
|
+
required: true
|
|
12
|
+
type: string
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
id-token: write
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
validate:
|
|
20
|
+
name: Validate
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- uses: actions/setup-node@v4
|
|
28
|
+
with:
|
|
29
|
+
node-version: 20
|
|
30
|
+
|
|
31
|
+
- name: Validate version consistency
|
|
32
|
+
run: |
|
|
33
|
+
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
|
34
|
+
TAG_VERSION=${GITHUB_REF#refs/tags/v}
|
|
35
|
+
PKG_VERSION=$(node -p "require('./package.json').version")
|
|
36
|
+
if [[ "$TAG_VERSION" != "$PKG_VERSION" ]]; then
|
|
37
|
+
echo "Error: Tag version ($TAG_VERSION) doesn't match package.json version ($PKG_VERSION)"
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
- name: Install dependencies
|
|
43
|
+
run: npm ci
|
|
44
|
+
|
|
45
|
+
- name: Typecheck
|
|
46
|
+
run: npm run typecheck
|
|
47
|
+
|
|
48
|
+
create-release:
|
|
49
|
+
name: Create GitHub Release
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
needs: validate
|
|
52
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
with:
|
|
56
|
+
fetch-depth: 0
|
|
57
|
+
|
|
58
|
+
- name: Generate changelog
|
|
59
|
+
id: changelog
|
|
60
|
+
run: |
|
|
61
|
+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
|
|
62
|
+
CURRENT_TAG=${GITHUB_REF#refs/tags/}
|
|
63
|
+
|
|
64
|
+
if [[ -n "$PREV_TAG" ]]; then
|
|
65
|
+
echo "## Changes since $PREV_TAG" > CHANGELOG.md
|
|
66
|
+
git log --pretty=format:"- %s (%h)" $PREV_TAG..HEAD >> CHANGELOG.md
|
|
67
|
+
else
|
|
68
|
+
echo "## Initial Release" > CHANGELOG.md
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
- name: Create Release
|
|
72
|
+
uses: softprops/action-gh-release@v2
|
|
73
|
+
with:
|
|
74
|
+
tag_name: ${{ github.ref_name }}
|
|
75
|
+
name: Release ${{ github.ref_name }}
|
|
76
|
+
body_path: CHANGELOG.md
|
|
77
|
+
draft: false
|
|
78
|
+
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc') }}
|
|
79
|
+
|
|
80
|
+
publish-npm:
|
|
81
|
+
name: Publish to npm
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
needs: [validate, create-release]
|
|
84
|
+
if: startsWith(github.ref, 'refs/tags/') && !contains(github.ref_name, 'alpha') && !contains(github.ref_name, 'beta')
|
|
85
|
+
steps:
|
|
86
|
+
- uses: actions/checkout@v4
|
|
87
|
+
|
|
88
|
+
- uses: actions/setup-node@v4
|
|
89
|
+
with:
|
|
90
|
+
# npm trusted publishing (OIDC) requires npm >= 11.5.1 / Node >= 22.14
|
|
91
|
+
node-version: 24
|
|
92
|
+
registry-url: https://registry.npmjs.org
|
|
93
|
+
|
|
94
|
+
- name: Publish root package
|
|
95
|
+
run: npm publish --access public --provenance
|
|
96
|
+
|
|
97
|
+
- name: Publish sub-packages
|
|
98
|
+
run: |
|
|
99
|
+
for dir in extensions/*/; do
|
|
100
|
+
if [ -f "$dir/package.json" ]; then
|
|
101
|
+
echo "Publishing $dir"
|
|
102
|
+
cd "$dir"
|
|
103
|
+
npm publish --access public --provenance
|
|
104
|
+
cd -
|
|
105
|
+
fi
|
|
106
|
+
done
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Vijay
|
|
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
CHANGED
|
@@ -1,64 +1,107 @@
|
|
|
1
|
-
# Piverse
|
|
1
|
+
# Piverse 🌌
|
|
2
2
|
|
|
3
|
-
A multi-extension ecosystem for the [Pi coding agent](https://
|
|
3
|
+
A multi-extension ecosystem for the [Pi coding agent](https://pi.dev).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Extensions
|
|
6
|
+
|
|
7
|
+
| Extension | Command | Description |
|
|
8
|
+
|-----------|---------|-------------|
|
|
9
|
+
| [pi-queue](./extensions/pi-queue) | `/queue` | Queue messages to run after the current agent turn settles |
|
|
10
|
+
| [pi-notes](./extensions/pi-notes) | `/notes` | Project-level notes with TUI, tags, search, and pinning |
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
## Install
|
|
8
13
|
|
|
9
14
|
```bash
|
|
10
15
|
pi install npm:@vs4vijay/piverse
|
|
11
16
|
```
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
## Usage
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
pi install npm:@vs4vijay/pi-queue
|
|
17
|
-
```
|
|
20
|
+
### `/queue <message>`
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
Queue a message that automatically sends after the current turn finishes.
|
|
20
23
|
|
|
21
|
-
```
|
|
22
|
-
|
|
24
|
+
```
|
|
25
|
+
/queue refactor the auth module next
|
|
26
|
+
/queue run the test suite
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
- `/queue` (no args) — show pending messages
|
|
30
|
+
- `/queue-clear` — empty the queue
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|-----------|---------|-------------|
|
|
29
|
-
| [pi-queue](./extensions/pi-queue) | `@vs4vijay/pi-queue` | Queue messages to run after the current turn settles |
|
|
32
|
+
Messages fire one at a time, in order, after each `agent_settled` event.
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
### `/notes`
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
Project-level notes persisted in `.pi/notes/notes.json` (committed to git, team-shared).
|
|
34
37
|
|
|
35
|
-
```
|
|
36
|
-
|
|
38
|
+
```
|
|
39
|
+
/notes # Open the full-screen TUI (list, view, create, edit, delete)
|
|
40
|
+
/notes "API contract" # Quick-add a note with that title (opens editor for content)
|
|
41
|
+
/notes list # List all notes in the CLI
|
|
42
|
+
/notes show <id> # Show a note's full content
|
|
43
|
+
/notes edit <id> # Edit a note's title/content via external editor
|
|
44
|
+
/notes search <query> # Search notes by title/content
|
|
45
|
+
/notes tag <id> <tag> # Add a tag to a note
|
|
46
|
+
/notes pin <id> # Pin a note to the top of the list
|
|
47
|
+
/notes rm <id> # Delete a note (with confirmation)
|
|
48
|
+
/notes export [path] # Export all notes to a JSON file
|
|
49
|
+
/notes import <path> # Import and merge notes from a JSON file
|
|
37
50
|
```
|
|
38
51
|
|
|
39
|
-
|
|
52
|
+
- Persists as JSON, auto-saves on every mutation
|
|
53
|
+
- Loads on `session_start`, flushes on `session_shutdown`
|
|
54
|
+
- TUI keys: `↑/↓` or `j/k` to navigate, `Enter` to view, `n` new, `e` edit, `d` delete, `p` pin, `/` to filter by typing, `q`/`Esc` to quit
|
|
40
55
|
|
|
41
|
-
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone git@github.com:vs4vijay/piverse.git ~/GitHub/piverse
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Hot-reload (symlink into Pi)
|
|
42
63
|
|
|
43
64
|
```bash
|
|
44
65
|
ln -sf ~/GitHub/piverse/extensions/pi-queue ~/.pi/agent/extensions/pi-queue
|
|
45
66
|
```
|
|
46
67
|
|
|
47
|
-
|
|
68
|
+
Edit source → `/reload` in Pi → changes are live. No build step.
|
|
69
|
+
|
|
70
|
+
### Quick test (no install)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pi -e ./extensions/pi-queue/src/index.ts
|
|
74
|
+
```
|
|
48
75
|
|
|
49
76
|
### Type checking
|
|
50
77
|
|
|
51
78
|
```bash
|
|
79
|
+
npm install
|
|
52
80
|
npm run typecheck
|
|
53
81
|
```
|
|
54
82
|
|
|
55
|
-
## Structure
|
|
83
|
+
## Project Structure
|
|
56
84
|
|
|
57
85
|
```
|
|
58
86
|
piverse/
|
|
59
87
|
├── extensions/
|
|
60
|
-
│ ├── pi-queue/
|
|
61
|
-
│
|
|
62
|
-
|
|
63
|
-
|
|
88
|
+
│ ├── pi-queue/ # /queue - message queueing
|
|
89
|
+
│ ├── pi-notes/ # /notes - project notes
|
|
90
|
+
│ └── ... # more extensions coming
|
|
91
|
+
├── package.json # workspace root
|
|
92
|
+
├── tsconfig.json # shared type checking
|
|
93
|
+
└── README.md
|
|
64
94
|
```
|
|
95
|
+
|
|
96
|
+
## Contributing
|
|
97
|
+
|
|
98
|
+
1. Fork & clone
|
|
99
|
+
2. `mkdir extensions/pi-<name>/src`
|
|
100
|
+
3. Add `package.json` with `"pi": { "extensions": ["./src/index.ts"] }`
|
|
101
|
+
4. Implement in `src/index.ts`
|
|
102
|
+
5. Test with `pi -e ./extensions/pi-<name>/src/index.ts`
|
|
103
|
+
6. PR
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# @vs4vijay/pi-notes
|
|
2
|
+
|
|
3
|
+
Project-level notes for the Pi coding agent. Persists notes as JSON in `.pi/notes/notes.json` (committed to git, team-shared).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pi install npm:@vs4vijay/pi-notes
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or add to your Pi config:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"pi": {
|
|
16
|
+
"extensions": [
|
|
17
|
+
"./extensions/pi-queue/src/index.ts",
|
|
18
|
+
"./extensions/pi-notes/src/index.ts"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
| Command | Description |
|
|
27
|
+
|---------|-------------|
|
|
28
|
+
| `/notes` | Open TUI (list, view, create, edit, delete) |
|
|
29
|
+
| `/notes <title>` | Quick-add note with title (opens editor for content) |
|
|
30
|
+
| `/notes list` | List all notes in CLI |
|
|
31
|
+
| `/notes show <id>` | Show full note content |
|
|
32
|
+
| `/notes edit <id>` | Edit a note's title/content via external editor |
|
|
33
|
+
| `/notes rm <id>` | Delete note (with confirmation) |
|
|
34
|
+
| `/notes search <query>` | Search notes by title/content |
|
|
35
|
+
| `/notes tag <id> <tag>` | Add tag to note |
|
|
36
|
+
| `/notes untag <id> <tag>` | Remove tag from note |
|
|
37
|
+
| `/notes pin <id>` | Pin note to top of list |
|
|
38
|
+
| `/notes unpin <id>` | Unpin note |
|
|
39
|
+
| `/notes export [path]` | Export all notes to a JSON file (default: `./notes.json`) |
|
|
40
|
+
| `/notes import <path>` | Import and merge notes from a JSON file |
|
|
41
|
+
|
|
42
|
+
## TUI Interface
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
/notes
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Opens full-screen TUI with:
|
|
49
|
+
|
|
50
|
+
- **Left pane**: Note list (title + preview, live filter as you type)
|
|
51
|
+
- **Right pane**: Markdown preview of selected note
|
|
52
|
+
- **Keys**:
|
|
53
|
+
- `↑/↓` / `j/k` — navigate
|
|
54
|
+
- `Enter` — view full note
|
|
55
|
+
- `n` — new note
|
|
56
|
+
- `e` — edit selected
|
|
57
|
+
- `d` — delete selected (with confirmation)
|
|
58
|
+
- `p` — toggle pin
|
|
59
|
+
- `/` — start filtering: type to filter the list live, `Esc`/`Enter` to finish
|
|
60
|
+
- `q` / `Esc` — quit (or back from view/edit)
|
|
61
|
+
|
|
62
|
+
### View Mode
|
|
63
|
+
Full markdown render. Keys: `e` to edit, `q`/`Esc` back to list.
|
|
64
|
+
|
|
65
|
+
### Create/Edit Mode
|
|
66
|
+
Opens external editor via `ctx.ui.editor()` for title and content. On save, persists and returns to list.
|
|
67
|
+
|
|
68
|
+
## Persistence
|
|
69
|
+
|
|
70
|
+
- File: `.pi/notes/notes.json` in project root
|
|
71
|
+
- Format:
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"notes": [
|
|
75
|
+
{
|
|
76
|
+
"id": "uuid",
|
|
77
|
+
"title": "Architecture decisions",
|
|
78
|
+
"content": "# Architecture decisions\n\nKey choices...",
|
|
79
|
+
"createdAt": "2025-01-15T10:30:00.000Z",
|
|
80
|
+
"updatedAt": "2025-01-15T10:30:00.000Z",
|
|
81
|
+
"tags": ["architecture", "decision"],
|
|
82
|
+
"pinned": false
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"version": 1
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
- Auto-saves on every mutation
|
|
89
|
+
- Loads on `session_start`, flushes on `session_shutdown`
|
|
90
|
+
|
|
91
|
+
## Usage / Examples
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
> /notes
|
|
95
|
+
# Opens the full-screen TUI (list, view, create, edit, delete)
|
|
96
|
+
|
|
97
|
+
> /notes "API contract"
|
|
98
|
+
# Quick-add: title is "API contract" (quotes stripped), opens editor for content
|
|
99
|
+
|
|
100
|
+
> /notes list
|
|
101
|
+
Notes (3):
|
|
102
|
+
1. 📌 API contract — Endpoint specs for v2...
|
|
103
|
+
2. TODO: refactor auth [backend] — Pending work items...
|
|
104
|
+
3. Architecture decisions — Summary of key choices...
|
|
105
|
+
|
|
106
|
+
> /notes show a1b2c3
|
|
107
|
+
# API contract
|
|
108
|
+
Pinned | Tags: none | Created: 2025-01-15T10:30:00.000Z | Updated: 2025-01-16T09:12:00.000Z
|
|
109
|
+
|
|
110
|
+
## Endpoints
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
> /notes search refactor
|
|
114
|
+
Search results (1):
|
|
115
|
+
1. TODO: refactor auth [backend] — Pending work items...
|
|
116
|
+
|
|
117
|
+
> /notes tag a1b2c3 api
|
|
118
|
+
Added tag "api" to "API contract"
|
|
119
|
+
|
|
120
|
+
> /notes untag a1b2c3 api
|
|
121
|
+
Removed tag "api" from "API contract"
|
|
122
|
+
|
|
123
|
+
> /notes pin a1b2c3
|
|
124
|
+
Pinned "API contract"
|
|
125
|
+
|
|
126
|
+
> /notes unpin a1b2c3
|
|
127
|
+
Unpinned "API contract"
|
|
128
|
+
|
|
129
|
+
> /notes edit a1b2c3
|
|
130
|
+
# Opens external editors prefilled with the note's current title and content
|
|
131
|
+
Updated note: API contract
|
|
132
|
+
|
|
133
|
+
> /notes export
|
|
134
|
+
Exported 3 notes to /path/to/project/notes.json
|
|
135
|
+
|
|
136
|
+
> /notes export backup.json
|
|
137
|
+
Exported 3 notes to /path/to/project/backup.json
|
|
138
|
+
|
|
139
|
+
> /notes import backup.json
|
|
140
|
+
Imported 2 note(s) from /path/to/project/backup.json (1 already present, skipped)
|
|
141
|
+
|
|
142
|
+
> /notes rm a1b2c3
|
|
143
|
+
# Confirmation dialog... "Deleted note: API contract"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Export/Import format
|
|
147
|
+
|
|
148
|
+
`/notes export` writes the same JSON shape used for persistence. `/notes import` reads a file shaped like `{ "notes": [...], "version": 1 }` and **merges** it into the store: notes whose `id` already exists locally are skipped (existing notes win), new ids are appended.
|
|
149
|
+
|
|
150
|
+
## Roadmap
|
|
151
|
+
|
|
152
|
+
See [plan.md](./plan.md) for planned features: linking, templates, and other ideas.
|