mirror of
https://github.com/SikongJueluo/pi-extensions.git
synced 2026-10-05 11:52:55 +08:00
feat(pi-permission-ai-judge): add deferring authorizer extension
- add pnpm workspace scaffold with shared TypeScript config - register an ai-bash-judge authorizer with pi-permission-system - log permission request details and deterministic policy verdicts - record review entries and defer to the next authorizer
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import {
|
||||
getPermissionsService,
|
||||
PERMISSIONS_READY_CHANNEL,
|
||||
} from "@gotgenes/pi-permission-system";
|
||||
|
||||
const LINK_NAME = "ai-bash-judge";
|
||||
|
||||
export default function permissionAiJudge(pi: ExtensionAPI): void {
|
||||
let sessionStarted = false;
|
||||
let disposeAuthorizer: (() => void) | undefined;
|
||||
|
||||
/**
|
||||
* 尝试向 pi-permission-system 注册我们的 Authorizer。
|
||||
*
|
||||
* 之所以不能只在 session_start 里注册,是因为:
|
||||
* - 可能我们的 extension 先启动;
|
||||
* - 也可能 pi-permission-system 先启动。
|
||||
*
|
||||
* 所以同时监听 session_start 和 permissions:ready,
|
||||
* 谁后满足条件,谁完成注册。
|
||||
*/
|
||||
function tryRegister(): void {
|
||||
if (!sessionStarted || disposeAuthorizer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const service = getPermissionsService();
|
||||
|
||||
if (!service) {
|
||||
console.debug(
|
||||
`[${LINK_NAME}] permission service not ready; waiting`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
disposeAuthorizer = service.registerAuthorizer(
|
||||
LINK_NAME,
|
||||
|
||||
async (details, query, log) => {
|
||||
const surface =
|
||||
details.accessIntent?.surface ??
|
||||
details.surface ??
|
||||
undefined;
|
||||
|
||||
console.error(`[${LINK_NAME}] permission ask received`, {
|
||||
requestId: details.requestId,
|
||||
surface,
|
||||
toolName: details.toolName,
|
||||
command: details.command,
|
||||
path: details.path,
|
||||
value: details.value,
|
||||
agentName: details.agentName,
|
||||
});
|
||||
|
||||
/**
|
||||
* 测试 PermissionQuery。
|
||||
*
|
||||
* 这不会再次触发 Authorizer。
|
||||
* 它只是询问 pi-permission-system 的确定性规则:
|
||||
* “如果检查这个 bash command,规则本身会怎么判?”
|
||||
*/
|
||||
if (surface === "bash" && details.command) {
|
||||
const result = query.checkPermission(
|
||||
"bash",
|
||||
details.command,
|
||||
details.agentName ?? undefined,
|
||||
);
|
||||
|
||||
console.error(
|
||||
`[${LINK_NAME}] deterministic policy says`,
|
||||
result,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 permission-system 自己的 review log。
|
||||
*
|
||||
* 以后 AI 的 decision trail 也应该写这里。
|
||||
*/
|
||||
log.review("ai_bash_judge.test", {
|
||||
requestId: details.requestId,
|
||||
surface,
|
||||
command: details.command ?? null,
|
||||
verdict: "defer",
|
||||
});
|
||||
|
||||
/**
|
||||
* 第一版永远不审批。
|
||||
*
|
||||
* defer = 我不知道 / 我不处理,
|
||||
* 请 Authorizer Chain 继续交给下一个审批者。
|
||||
*
|
||||
* 正常情况下最终就是 LocalUserAuthorizer,
|
||||
* 所以你还是会看到原来的 permission prompt。
|
||||
*/
|
||||
return {
|
||||
kind: "defer",
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
console.error(`[${LINK_NAME}] registered`);
|
||||
}
|
||||
|
||||
pi.on("session_start", () => {
|
||||
sessionStarted = true;
|
||||
tryRegister();
|
||||
});
|
||||
|
||||
pi.events.on(PERMISSIONS_READY_CHANNEL, () => {
|
||||
tryRegister();
|
||||
});
|
||||
|
||||
pi.on("session_shutdown", () => {
|
||||
disposeAuthorizer?.();
|
||||
|
||||
disposeAuthorizer = undefined;
|
||||
sessionStarted = false;
|
||||
|
||||
console.error(`[${LINK_NAME}] unregistered`);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user