feat: restructure as pnpm monorepo workspace
- Move limit-turns.ts into packages/pi-turn-limit/src/index.ts - Add root package.json (private workspace manifest) - Add pnpm-workspace.yaml - Add shared tsconfig.json - Add pi package manifest to extension (pi.extensions, pi-package keyword) - Update AGENTS.md with monorepo workflow
This commit is contained in:
parent
1c6fc220ea
commit
57d238a1ea
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules/
|
||||||
|
.pnpm-store/
|
||||||
|
pnpm-lock.yaml
|
||||||
32
AGENTS.md
Normal file
32
AGENTS.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
This is a monorepo for pi extensions using pnpm workspaces.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
packages/
|
||||||
|
pi-turn-limit/ # First extension: limits the number of turns
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install # Install all workspace dependencies
|
||||||
|
```
|
||||||
|
|
||||||
|
Each extension lives in `packages/<name>/` with its own `package.json`.
|
||||||
|
The root `package.json` is the workspace manifest.
|
||||||
|
|
||||||
|
## Adding a new extension
|
||||||
|
|
||||||
|
1. Create `packages/<name>/` directory
|
||||||
|
2. Add `package.json` with `"pi-package"` keyword and `pi.extensions` manifest
|
||||||
|
3. Put source in `packages/<name>/src/index.ts`
|
||||||
|
4. Run `pnpm install`
|
||||||
|
|
||||||
|
## Extension packaging
|
||||||
|
|
||||||
|
Extensions are loaded by pi as TypeScript files via jiti (no compilation needed).
|
||||||
|
The `pi` key in `package.json` tells pi which files to load.
|
||||||
|
|
||||||
|
See `~/.local/share/mise/installs/node/24.0.1/lib/node_modules/@mariozechner/pi-coding-agent/docs/extensions.md`
|
||||||
|
and `packages.md` for full details.
|
||||||
11
package.json
Normal file
11
package.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "pi-extensions",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "Pi coding agent extensions monorepo",
|
||||||
|
"type": "module",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
packages/pi-turn-limit/package.json
Normal file
17
packages/pi-turn-limit/package.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "pi-turn-limit",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Pi coding agent extension to limit number of turns taken by a model",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": "./src/index.ts"
|
||||||
|
},
|
||||||
|
"keywords": ["pi-package"],
|
||||||
|
"pi": {
|
||||||
|
"extensions": ["src/index.ts"]
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@mariozechner/pi-coding-agent": "*"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
56
packages/pi-turn-limit/src/index.ts
Normal file
56
packages/pi-turn-limit/src/index.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Configuration
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
const DEFAULT_MAX_TURNS = 25;
|
||||||
|
|
||||||
|
function getMaxTurns(): number {
|
||||||
|
const env = process.env.PI_MAX_TURNS;
|
||||||
|
if (!env) return DEFAULT_MAX_TURNS;
|
||||||
|
const parsed = parseInt(env, 10);
|
||||||
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_TURNS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Pure detection logic (testable)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export function checkTurnLimit(
|
||||||
|
turnIndex: number,
|
||||||
|
maxTurns: number,
|
||||||
|
): { exceeded: boolean; turnIndex: number; maxTurns: number } {
|
||||||
|
return {
|
||||||
|
exceeded: turnIndex > maxTurns,
|
||||||
|
turnIndex,
|
||||||
|
maxTurns,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Extension handler
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export default function (pi: ExtensionAPI) {
|
||||||
|
let turnCount = 0;
|
||||||
|
const maxTurns = getMaxTurns();
|
||||||
|
|
||||||
|
pi.on("agent_start", async (_event, ctx) => {
|
||||||
|
// Reset counter for each new user prompt
|
||||||
|
turnCount = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.on("turn_start", async (event, ctx) => {
|
||||||
|
turnCount++;
|
||||||
|
|
||||||
|
const { exceeded } = checkTurnLimit(event.turnIndex, maxTurns);
|
||||||
|
if (exceeded && ctx.hasUI) {
|
||||||
|
ctx.ui.notify(
|
||||||
|
`Turn limit exceeded: ${maxTurns} turns reached. Agent aborted.`,
|
||||||
|
"error",
|
||||||
|
);
|
||||||
|
ctx.abort();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
2
pnpm-workspace.yaml
Normal file
2
pnpm-workspace.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
- "packages/*"
|
||||||
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"include": ["packages/**/*"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user