@ian-pascoe/pi-codemode 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 +241 -0
- package/package.json +59 -0
- package/src/codemode-cell-transform.ts +612 -0
- package/src/codemode-deno-launch.ts +59 -0
- package/src/codemode-deno-process.ts +208 -0
- package/src/codemode-observer-ui.ts +517 -0
- package/src/codemode-presentation-output.ts +16 -0
- package/src/codemode-runtime.ts +24 -0
- package/src/codemode-session-coordinator.ts +1297 -0
- package/src/codemode-session-files.ts +80 -0
- package/src/codemode-tool-catalog.ts +350 -0
- package/src/codemode-tool-contract.ts +480 -0
- package/src/codemode-tool-exposure.ts +159 -0
- package/src/codemode-tool-rendering.ts +487 -0
- package/src/codemode-worker-protocol.ts +480 -0
- package/src/codemode-worker.ts +1092 -0
- package/src/index.ts +1 -0
- package/src/pi-agent-session-capture.ts +157 -0
- package/src/pi-codemode-extension.ts +469 -0
- package/src/pi-codemode-settings.ts +168 -0
- package/src/pi-tool-bridge.ts +744 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ian Pascoe
|
|
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,241 @@
|
|
|
1
|
+
# @ian-pascoe/pi-codemode
|
|
2
|
+
|
|
3
|
+
Run persistent TypeScript notebook Cells that compose Pi's registered tools.
|
|
4
|
+
CodeMode calls the exact handlers Pi registered; it does not contain substitute
|
|
5
|
+
implementations of built-in tools.
|
|
6
|
+
|
|
7
|
+
Tested with Pi `0.84.2` and Node `22.19.0`. The package installs its pinned
|
|
8
|
+
`deno@2.9.5` runtime, which itself transpiles and executes Cells. Its official
|
|
9
|
+
npm binaries cover macOS, glibc Linux, and Windows on x64 and arm64.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pi install npm:@ian-pascoe/pi-codemode
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
From this repository:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pi install git:github.com/ian-pascoe/pi-extensions
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Tools
|
|
24
|
+
|
|
25
|
+
### `codemode_execute`
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
codemode_execute({
|
|
29
|
+
script: string;
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
wait?: boolean;
|
|
32
|
+
sessionId?: string;
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`wait` defaults to `true`. `timeoutMs` has no default. Omitting `sessionId`
|
|
37
|
+
creates a new CodeMode Session; supplying an unknown ID fails.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const result = await tools.read({ path: "README.md" });
|
|
41
|
+
return result.content[0];
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Set `wait: false` to return immediately with `pending`, then poll the returned
|
|
45
|
+
ID. An accepted asynchronous execution always returns `pending`, even if its
|
|
46
|
+
Cell finishes before the outer call returns.
|
|
47
|
+
|
|
48
|
+
### `codemode_result`
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
codemode_result({ sessionId: string });
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Returns the active or latest terminal result without consuming it.
|
|
55
|
+
|
|
56
|
+
### `codemode_cancel`
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
codemode_cancel({ sessionId: string });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Stops the session process and frees its capacity. The cancel call succeeds;
|
|
63
|
+
subsequent polling returns the retained `cancellation` failure.
|
|
64
|
+
|
|
65
|
+
All three tools return:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
type CodeModeResult =
|
|
69
|
+
| { result: "success"; sessionId: string; data?: JsonValue }
|
|
70
|
+
| { result: "pending"; sessionId: string }
|
|
71
|
+
| {
|
|
72
|
+
result: "failed";
|
|
73
|
+
sessionId: string;
|
|
74
|
+
error: {
|
|
75
|
+
code:
|
|
76
|
+
| "unknown"
|
|
77
|
+
| "busy"
|
|
78
|
+
| "capacity"
|
|
79
|
+
| "script"
|
|
80
|
+
| "serialization"
|
|
81
|
+
| "timeout"
|
|
82
|
+
| "cancellation"
|
|
83
|
+
| "termination"
|
|
84
|
+
| "runtime";
|
|
85
|
+
message: string;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`AgentToolResult.content` remains exactly this JSON and is the only CodeMode
|
|
91
|
+
result text returned to the model. Pi retains additional bounded Presentation
|
|
92
|
+
Snapshots in tool-result details for Transcript replay and the TUI.
|
|
93
|
+
|
|
94
|
+
## Transcript and Observer UI
|
|
95
|
+
|
|
96
|
+
The CodeMode Transcript gives all three tools semantic collapsed and expanded
|
|
97
|
+
rendering. Collapsed rows prioritize Cell lifecycle, a short Session ID, Cell
|
|
98
|
+
Ordinal, returned-value shape, nested-tool count, and elapsed time. Expanded
|
|
99
|
+
rows show the full Session ID, explicit call arguments, TypeScript source,
|
|
100
|
+
structured returned data or error, and bounded nested-tool names, outcomes, and
|
|
101
|
+
durations. Nested arguments and raw nested outputs are never copied into the
|
|
102
|
+
presentation.
|
|
103
|
+
|
|
104
|
+
Status always uses a symbol and text together:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
◉ running ○ idle ✓ completed
|
|
108
|
+
× failed ■ cancelled ! timed out
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Awaited Cells publish a presentation update immediately and once per second.
|
|
112
|
+
Source display is limited to 200 lines or 50 KB. Returned-data display uses
|
|
113
|
+
Pi's 2,000-line/50-KB limit; complete oversized data is written to a private
|
|
114
|
+
Result Spill while the model-facing result remains unchanged. Result Spill
|
|
115
|
+
files last for the live Pi session. Replayed history falls back to its retained
|
|
116
|
+
bounded data when a prior spill is no longer available.
|
|
117
|
+
|
|
118
|
+
In TUI mode, the read-only CodeMode Observer UI appears above the editor during
|
|
119
|
+
Cell activity. It shows up to eight running, idle, or recently terminal
|
|
120
|
+
Sessions, uses the shortest unique Session prefix of at least eight characters,
|
|
121
|
+
and adds `… +N more` when bounded. A footer shows `◉ N running · N live` only
|
|
122
|
+
while Cells run. The widget disappears ten seconds after every Session becomes
|
|
123
|
+
idle or terminal and remounts on later activity. It has no controls and issues
|
|
124
|
+
no hidden CodeMode or Pi tool calls.
|
|
125
|
+
|
|
126
|
+
## Notebook Bindings
|
|
127
|
+
|
|
128
|
+
Top-level `let`, `const`, `var`, function, class, and destructuring declarations
|
|
129
|
+
become Notebook Bindings. Later Cells in the same session use them without
|
|
130
|
+
`globalThis`:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// Cell 1
|
|
134
|
+
let count = 1;
|
|
135
|
+
function current() {
|
|
136
|
+
return count;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Cell 2
|
|
140
|
+
count += 1;
|
|
141
|
+
return current(); // 2
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
A later declaration may replace an existing binding, including a `const`.
|
|
145
|
+
Ordinary assignment to the current `const` still fails. Existing functions see
|
|
146
|
+
later assignments and successful redefinitions. A failed declaration
|
|
147
|
+
initializer preserves the previous value; earlier completed mutations and
|
|
148
|
+
declarations in the same failing Cell remain committed.
|
|
149
|
+
|
|
150
|
+
Cells accept TypeScript syntax, which Deno transpiles without type checking.
|
|
151
|
+
Type annotations therefore do not validate tool inputs or results. Cells support
|
|
152
|
+
top-level `await`, explicit `return`, and automatic return of the final
|
|
153
|
+
expression. Static and dynamic imports, `eval`, and dynamic function
|
|
154
|
+
constructors are unavailable. Annex-B block functions, nested lexical scopes,
|
|
155
|
+
and declarations beneath a source `with` statement remain Cell-local.
|
|
156
|
+
|
|
157
|
+
Notebook Bindings use protected non-configurable Deno global properties
|
|
158
|
+
internally. Normal unqualified and `globalThis` assignment both observe
|
|
159
|
+
`const` protection. Protected runtime names are rejected.
|
|
160
|
+
|
|
161
|
+
One Cell may run at a time in each session. Ordinary script and catchable Pi
|
|
162
|
+
tool failures leave the session reusable. Timeout, cancellation, Pi
|
|
163
|
+
termination, or process failure destroys that session's heap.
|
|
164
|
+
|
|
165
|
+
## Registered tools
|
|
166
|
+
|
|
167
|
+
The `codemode_execute` description contains generated TypeScript declarations
|
|
168
|
+
for the currently exposed registered tools. Guest calls resolve to:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
type PiToolResult = {
|
|
172
|
+
content: Array<
|
|
173
|
+
{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }
|
|
174
|
+
>;
|
|
175
|
+
details?: unknown;
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Ordinary tool failures reject with a catchable `CodeModeToolError`. A Pi result
|
|
180
|
+
that requests termination stops the complete CodeMode Session and cannot be
|
|
181
|
+
caught by guest code.
|
|
182
|
+
|
|
183
|
+
## Exposure settings
|
|
184
|
+
|
|
185
|
+
Configure Exposure Modes under `codemode` in `~/.pi/agent/settings.json` or a
|
|
186
|
+
trusted project's `.pi/settings.json`:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"codemode": {
|
|
191
|
+
"maxSessions": 8,
|
|
192
|
+
"tools": [
|
|
193
|
+
{ "pattern": "*", "exposure": "codemode-only" },
|
|
194
|
+
{ "pattern": "bash", "exposure": "direct-and-codemode" },
|
|
195
|
+
{ "pattern": "browser_*", "exposure": "direct-only" }
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Patterns are case-sensitive minimatch globs over exact registered names; the
|
|
202
|
+
last match wins. Project `tools` replaces the global array, while project
|
|
203
|
+
`maxSessions` overrides only that field. `/reload` rereads settings.
|
|
204
|
+
|
|
205
|
+
An unmatched active tool defaults to `direct-and-codemode`; an unmatched
|
|
206
|
+
inactive tool remains unavailable. An explicit rule may expose an inactive tool
|
|
207
|
+
or activate direct access. The three `codemode_*` tools are always direct-only.
|
|
208
|
+
Pi's global allowed/excluded registry remains authoritative. Invalid fields or
|
|
209
|
+
patterns disable CodeMode for that session without changing Pi's active tools.
|
|
210
|
+
|
|
211
|
+
`maxSessions` defaults to 8 and counts only live Deno processes. Up to 64 recent
|
|
212
|
+
worker-free terminal or failed-admission records remain pollable.
|
|
213
|
+
|
|
214
|
+
## Isolation and limits
|
|
215
|
+
|
|
216
|
+
Each live CodeMode Session owns a pinned Deno subprocess. Deno itself executes
|
|
217
|
+
unique `Blob` modules with the `application/typescript` media type, keeping
|
|
218
|
+
generated helper source out of ordinary source locations. Every operating-system
|
|
219
|
+
permission class is denied: filesystem read/write, network, environment, system
|
|
220
|
+
information, subprocesses, FFI, and remote imports.
|
|
221
|
+
|
|
222
|
+
Guest code receives ECMAScript built-ins, a read-only `tools` object, and only a
|
|
223
|
+
frozen `Deno.version` identity. Raw process and standard-stream access,
|
|
224
|
+
`console`, `Worker`, timers, filesystem/network APIs, and module loading are
|
|
225
|
+
withheld. The parent watchdog terminates the subprocess for timeout or an
|
|
226
|
+
infinite loop. Deno/V8 bounds each Session to a 128 MiB old-space heap and a
|
|
227
|
+
1 MiB stack. Protocol inputs, tool results, and Cell results remain JSON-only
|
|
228
|
+
and limited to 8 MiB of UTF-8.
|
|
229
|
+
|
|
230
|
+
Registered Pi tools still execute in Pi's parent process with their normal
|
|
231
|
+
permissions and lifecycle hooks. Cancellation aborts them through Pi's
|
|
232
|
+
`AbortSignal`; a handler that ignores that signal cannot be forcibly killed, so
|
|
233
|
+
its late result is discarded after the CodeMode process stops.
|
|
234
|
+
|
|
235
|
+
CodeMode uses a capability-gated private Pi `AgentSession` seam, tested against
|
|
236
|
+
Pi `0.84.2`, to reach wrapped registered handlers and enforce direct exposure.
|
|
237
|
+
An incompatible Pi version fails closed and leaves active tools unchanged.
|
|
238
|
+
|
|
239
|
+
Sessions are memory-only in this release and end on Pi reload, session switch,
|
|
240
|
+
fork, resume, or shutdown. A future persistence format may checkpoint complete
|
|
241
|
+
JSON-safe Notebook Bindings; V1 neither serializes heaps nor replays Cells.
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ian-pascoe/pi-codemode",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Process-isolated persistent TypeScript tool composition for Pi",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"codemode",
|
|
8
|
+
"deno",
|
|
9
|
+
"pi",
|
|
10
|
+
"pi-extension",
|
|
11
|
+
"pi-package",
|
|
12
|
+
"typescript"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/ian-pascoe/pi-extensions#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/ian-pascoe/pi-extensions/issues"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Ian Pascoe <ian.g.pascoe@gmail.com>",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/ian-pascoe/pi-extensions.git",
|
|
23
|
+
"directory": "packages/pi-codemode"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"src",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"type": "module",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"provenance": true
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "vitest run --config ../../vitest.config.ts --root .",
|
|
37
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"deno": "2.9.5",
|
|
41
|
+
"minimatch": "^10.2.5",
|
|
42
|
+
"typescript": "6.0.3"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@earendil-works/pi-agent-core": "*",
|
|
46
|
+
"@earendil-works/pi-ai": "*",
|
|
47
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
48
|
+
"@earendil-works/pi-tui": "*",
|
|
49
|
+
"typebox": "*"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=22.19.0"
|
|
53
|
+
},
|
|
54
|
+
"pi": {
|
|
55
|
+
"extensions": [
|
|
56
|
+
"./src/index.ts"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|