@erichll/pi-auto-review 0.21.0 → 0.22.1
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/CHANGELOG.md +35 -0
- package/README.md +9 -5
- package/package.json +9 -9
- package/src/policy-audit/sqlite.ts +55 -0
- package/src/policy-audit/store.ts +3 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.22.1 - 2026-10-01
|
|
4
|
+
|
|
5
|
+
- Fix permission-policy auditing being disabled on Bun with
|
|
6
|
+
`No such built-in module: node:sqlite`. Bun, including Bun-compiled Pi, now
|
|
7
|
+
uses its built-in `bun:sqlite`; Node continues to use `node:sqlite`.
|
|
8
|
+
- Preserve audit statistics and request deduplication when switching between
|
|
9
|
+
Node and Bun by sharing the existing database schema and HMAC key.
|
|
10
|
+
- Finalize Bun's cached SQLite statements when closing the database so the
|
|
11
|
+
last WAL connection can checkpoint and release its resources.
|
|
12
|
+
- Add regression coverage for database migration, redaction, retention,
|
|
13
|
+
failure handling, concurrent Node/Bun writers, and persistent audit reports
|
|
14
|
+
in a real Bun-compiled Pi process.
|
|
15
|
+
- Update the permission-system example for current MCP tool names, including
|
|
16
|
+
`codemode`, `tool_search`, `mcp__atlassian__*`, and `mcp__pencil__*`.
|
|
17
|
+
|
|
18
|
+
## 0.22.0 - 2026-09-30
|
|
19
|
+
|
|
20
|
+
- Raise the `@earendil-works/pi-ai` and `@earendil-works/pi-coding-agent` peer
|
|
21
|
+
floor to `^0.99.1` and the development baseline to `^0.99.1`. Validated
|
|
22
|
+
against Pi 0.99.1 with `tsc --noEmit` and the full test suite: the extension
|
|
23
|
+
adopts the 0.99 extension surface without code changes.
|
|
24
|
+
- Raise the `@gotgenes/pi-permission-system` peer floor to `>=36.0.0` and the
|
|
25
|
+
development baseline to `^36.0.0`. Versions 35.0.3 and 36.0.0 reclassify
|
|
26
|
+
`sed` and `awk` readers and withdraw `find`, `fd`, and `sort` read claims for
|
|
27
|
+
computed and quoted arguments; the broker's evidence normalization and audit
|
|
28
|
+
classification were validated against 36.0.0.
|
|
29
|
+
- Sync `examples/pi-permission-system.config.example.json` with the current tool
|
|
30
|
+
set: allow `web_enable`, `subagents_enable`, `contact_supervisor`, and
|
|
31
|
+
`bg_wait`, following the earlier skill/MCP regrouping, the `subagent` and
|
|
32
|
+
`source_check` allowances, the `goal_block` to `goal_blocked` correction, and
|
|
33
|
+
the `fetch_content` promotion from `ask` to `allow`.
|
|
34
|
+
- Bump the development `typescript` baseline to `^7.0.2` and migrate the test
|
|
35
|
+
external-ts loader from `ts.transpileModule` (removed in TypeScript 7's new JS
|
|
36
|
+
API) to Node's built-in `stripTypeScriptTypes`.
|
|
37
|
+
|
|
3
38
|
## 0.21.0 - 2026-09-25
|
|
4
39
|
|
|
5
40
|
- Raise the `@gotgenes/pi-permission-system` peer floor to `>=34.0.0` and update
|
package/README.md
CHANGED
|
@@ -31,11 +31,13 @@ that dependency is a hard prerequisite (see [Install and enable](#install-and-en
|
|
|
31
31
|
> **Prerequisite:** pi-auto-review is an authorizer inside
|
|
32
32
|
> `@gotgenes/pi-permission-system`. Pi does not auto-install peer packages, so
|
|
33
33
|
> install the permission system separately (once per machine) before this
|
|
34
|
-
> extension. This release line
|
|
34
|
+
> extension. This release line requires Pi 0.99.1 or later and supports
|
|
35
|
+
> permission-system 36.0.0 and later:
|
|
35
36
|
|
|
36
|
-
Node.js 22.13.0 or newer
|
|
37
|
-
`node:sqlite
|
|
38
|
-
|
|
37
|
+
Node-based Pi requires Node.js 22.13.0 or newer. Permission auditing uses the
|
|
38
|
+
host runtime's built-in SQLite: `node:sqlite` on Node and `bun:sqlite` on Bun,
|
|
39
|
+
including Bun-compiled Pi (verified with Bun 1.3.14). It does not require a
|
|
40
|
+
SQLite CLI, system SQLite library, or npm SQLite package.
|
|
39
41
|
|
|
40
42
|
```bash
|
|
41
43
|
pi install npm:@gotgenes/pi-permission-system
|
|
@@ -373,7 +375,9 @@ project-specific labels; inspect suggestions before copying them.
|
|
|
373
375
|
|
|
374
376
|
Data lives at
|
|
375
377
|
`~/.pi/agent/extensions/pi-auto-review/policy-audit.sqlite`, beside an
|
|
376
|
-
owner-only HMAC key.
|
|
378
|
+
owner-only HMAC key. Node and Bun use the same database schema and key, so
|
|
379
|
+
switching runtimes preserves statistics and request deduplication.
|
|
380
|
+
The directory is mode `0700`; the key, database, WAL, and
|
|
377
381
|
SHM are mode `0600`. Initialization, lock, write, or corruption failures disable
|
|
378
382
|
auditing and warn once without changing any permission result. A corrupt
|
|
379
383
|
database is not deleted or rebuilt automatically. Disable new collection with:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erichll/pi-auto-review",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "Fail-closed, model-backed approval broker for Pi: deterministically hard-denies dangerous operations, reviews dangerous boundaries with a reviewer model, and issues one-shot expiring grants that OS sandbox adapters must consume before retrying.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,16 +47,16 @@
|
|
|
47
47
|
"test": "node --disable-warning=ExperimentalWarning --experimental-transform-types --import ./test/register-external-ts.mjs --test test/*.test.ts"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@earendil-works/pi-ai": "^0.
|
|
51
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
52
|
-
"@gotgenes/pi-permission-system": ">=
|
|
50
|
+
"@earendil-works/pi-ai": "^0.99.1",
|
|
51
|
+
"@earendil-works/pi-coding-agent": "^0.99.1",
|
|
52
|
+
"@gotgenes/pi-permission-system": ">=36.0.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@earendil-works/pi-ai": "^0.
|
|
56
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
57
|
-
"@earendil-works/pi-server": "^0.
|
|
58
|
-
"@gotgenes/pi-permission-system": "^
|
|
55
|
+
"@earendil-works/pi-ai": "^0.99.1",
|
|
56
|
+
"@earendil-works/pi-coding-agent": "^0.99.1",
|
|
57
|
+
"@earendil-works/pi-server": "^0.99.1",
|
|
58
|
+
"@gotgenes/pi-permission-system": "^36.0.0",
|
|
59
59
|
"@types/node": "^26.6.2",
|
|
60
|
-
"typescript": "^
|
|
60
|
+
"typescript": "^7.0.2"
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
type Statement = {
|
|
2
|
+
run(...params: unknown[]): { changes: number | bigint };
|
|
3
|
+
// Node returns undefined for a missing row; Bun returns null.
|
|
4
|
+
get(...params: unknown[]): Record<string, unknown> | null | undefined;
|
|
5
|
+
all(...params: unknown[]): Record<string, unknown>[];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type SqliteDatabase = {
|
|
9
|
+
exec(sql: string): void;
|
|
10
|
+
prepare(sql: string): Statement;
|
|
11
|
+
close(): void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type SqliteModule = {
|
|
15
|
+
DatabaseSync: new (path: string, options?: Record<string, unknown>) => SqliteDatabase;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type BunDatabase = Omit<SqliteDatabase, "prepare"> & {
|
|
19
|
+
query(sql: string): Statement;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** Load the host's built-in SQLite lazily, including inside Bun-compiled Pi. */
|
|
23
|
+
export async function loadSqlite(): Promise<SqliteModule> {
|
|
24
|
+
if (process.versions.bun) {
|
|
25
|
+
// A runtime specifier avoids requiring Bun's ambient types in Node builds.
|
|
26
|
+
const specifier = "bun:sqlite";
|
|
27
|
+
const sqlite = await import(specifier) as {
|
|
28
|
+
Database: new (path: string, options?: Record<string, unknown>) => BunDatabase;
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
DatabaseSync: class implements SqliteDatabase {
|
|
32
|
+
private readonly database: BunDatabase;
|
|
33
|
+
|
|
34
|
+
constructor(path: string, options?: Record<string, unknown>) {
|
|
35
|
+
this.database = new sqlite.Database(path, options);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exec(sql: string): void {
|
|
39
|
+
this.database.exec(sql);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
prepare(sql: string): Statement {
|
|
43
|
+
// Bun finalizes cached queries on close. Uncached prepare() statements
|
|
44
|
+
// can outlive the connection, retaining locks and delaying checkpoints.
|
|
45
|
+
return this.database.query(sql);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
close(): void {
|
|
49
|
+
this.database.close();
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return import("node:sqlite") as Promise<SqliteModule>;
|
|
55
|
+
}
|
|
@@ -11,24 +11,12 @@ import {
|
|
|
11
11
|
} from "node:fs";
|
|
12
12
|
import { dirname, join, resolve } from "node:path";
|
|
13
13
|
import type { ClassifiedPermission } from "./classifier.ts";
|
|
14
|
+
import { loadSqlite, type SqliteDatabase, type SqliteModule } from "./sqlite.ts";
|
|
14
15
|
|
|
15
16
|
export const POLICY_AUDIT_SCHEMA_VERSION = 2;
|
|
16
17
|
export const POLICY_AUDIT_DATABASE_NAME = "policy-audit.sqlite";
|
|
17
18
|
export const POLICY_AUDIT_KEY_NAME = "policy-audit.key";
|
|
18
19
|
|
|
19
|
-
type RunResult = { changes: number | bigint };
|
|
20
|
-
type Statement = {
|
|
21
|
-
run(...params: unknown[]): RunResult;
|
|
22
|
-
get(...params: unknown[]): Record<string, unknown> | undefined;
|
|
23
|
-
all(...params: unknown[]): Record<string, unknown>[];
|
|
24
|
-
};
|
|
25
|
-
type Database = {
|
|
26
|
-
exec(sql: string): void;
|
|
27
|
-
prepare(sql: string): Statement;
|
|
28
|
-
close(): void;
|
|
29
|
-
};
|
|
30
|
-
type SqliteModule = { DatabaseSync: new (path: string, options?: Record<string, unknown>) => Database };
|
|
31
|
-
|
|
32
20
|
export type SanitizedPermissionDecision = ClassifiedPermission & {
|
|
33
21
|
requestId: string;
|
|
34
22
|
result: "allow" | "deny";
|
|
@@ -124,7 +112,7 @@ export class PolicyAuditStore {
|
|
|
124
112
|
mkdirSync(options.directory, { recursive: true, mode: 0o700 });
|
|
125
113
|
chmodSync(options.directory, 0o700);
|
|
126
114
|
const key = loadOrCreateKey(options.directory);
|
|
127
|
-
const sqlite = await (options.sqliteLoader ??
|
|
115
|
+
const sqlite = await (options.sqliteLoader ?? loadSqlite)();
|
|
128
116
|
const databasePath = join(options.directory, POLICY_AUDIT_DATABASE_NAME);
|
|
129
117
|
const db = new sqlite.DatabaseSync(databasePath);
|
|
130
118
|
chmodSync(databasePath, 0o600);
|
|
@@ -139,7 +127,7 @@ export class PolicyAuditStore {
|
|
|
139
127
|
}
|
|
140
128
|
|
|
141
129
|
private constructor(
|
|
142
|
-
private readonly db:
|
|
130
|
+
private readonly db: SqliteDatabase,
|
|
143
131
|
private readonly key: Buffer,
|
|
144
132
|
private readonly databasePath: string,
|
|
145
133
|
private readonly retentionDays: number,
|