@byok-sdk/client 0.10.1 → 0.11.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/README.md +71 -3
- package/dist/adapters/claude/claude-adapter.d.ts +3 -2
- package/dist/adapters/claude/permission-mapping.d.ts +48 -1
- package/dist/adapters/claude/resolve-approval-mcp-bin.d.ts +3 -2
- package/dist/adapters/codex/permission-mapping.d.ts +16 -0
- package/dist/adapters/index.js +292 -23
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/mcp-tool-grants.d.ts +36 -0
- package/dist/adapters/pi/resolve-extensions.d.ts +4 -1
- package/dist/adapters/pi/subagents-policy-config.d.ts +7 -0
- package/dist/adapters/pi/subagents-policy-extension.js +137 -0
- package/dist/adapters/pi/subagents-policy-extension.js.map +1 -0
- package/dist/agent-memory/index.d.ts +1 -1
- package/dist/agent-memory/index.js +4 -4
- package/dist/agent-memory/index.js.map +1 -1
- package/dist/bin/agent-memory-mcp-server.d.ts +2 -2
- package/dist/bin/agent-message-mcp-server.d.ts +0 -1
- package/dist/bin/byok-agent-memory-mcp.js +340 -7
- package/dist/bin/byok-agent-memory-mcp.js.map +1 -1
- package/dist/bin/byok-agent-message-mcp.js +331 -7
- package/dist/bin/byok-agent-message-mcp.js.map +1 -1
- package/dist/bin/byok-agent-team-mcp.d.ts +2 -0
- package/dist/bin/byok-agent-team-mcp.js +765 -0
- package/dist/bin/byok-agent-team-mcp.js.map +1 -0
- package/dist/bin/byok-agent.js +15889 -14610
- package/dist/bin/byok-agent.js.map +1 -1
- package/dist/bin/byok-approval-mcp.js +312 -45
- package/dist/bin/byok-approval-mcp.js.map +1 -1
- package/dist/bin/commands/team.d.ts +15 -0
- package/dist/bin/sdk-reserved-helper-runners.d.ts +2 -0
- package/dist/bin/team-mcp-server.d.ts +27 -0
- package/dist/bin/team-tmux-view.d.ts +19 -0
- package/dist/daemon/agent-message-mcp-preflight.d.ts +17 -0
- package/dist/daemon/control-protocol.d.ts +38 -0
- package/dist/daemon/create-daemon.d.ts +7 -0
- package/dist/daemon/mcp-tools-probe.d.ts +105 -0
- package/dist/daemon/resolve-agent-memory-mcp-bin.d.ts +2 -1
- package/dist/daemon/resolve-agent-message-mcp-bin.d.ts +2 -1
- package/dist/daemon/task-runner.d.ts +18 -1
- package/dist/daemon/team-workspace.d.ts +202 -0
- package/dist/daemon/toolset-registry.d.ts +0 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2682 -1090
- package/dist/index.js.map +1 -1
- package/dist/sdk-reserved-helper-host.d.ts +25 -0
- package/dist/sdk-reserved-mcp.d.ts +23 -0
- package/dist/types.d.ts +36 -0
- package/package.json +10 -5
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { McpStdioServerConfig, McpToolsetToolObservation } from '../types';
|
|
2
|
+
/** One projected toolset server and the exact tool names observed on it. */
|
|
3
|
+
export interface McpToolsetGrant {
|
|
4
|
+
readonly server: string;
|
|
5
|
+
readonly tools: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
/** Static grant candidates for exactly the SDK-owned pre-grantable servers present in one task. */
|
|
8
|
+
export declare function resolveReservedMcpToolGrants(servers: Readonly<Record<string, McpStdioServerConfig>> | undefined): readonly McpToolsetGrant[];
|
|
9
|
+
export type McpToolsetGrantResolution = {
|
|
10
|
+
ok: true;
|
|
11
|
+
grants: readonly McpToolsetGrant[];
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
reason: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Pair every projected (non-reserved) MCP server with the tool names the
|
|
18
|
+
* daemon actually observed on it, or fail closed.
|
|
19
|
+
*
|
|
20
|
+
* Both runtimes this SDK drives non-interactively refuse an MCP tool call
|
|
21
|
+
* that was not pre-granted — claude auto-denies it under `--permission-mode
|
|
22
|
+
* default` and under `acceptEdits`, codex rejects it under
|
|
23
|
+
* `approval_policy=never` — so a projected toolset is only genuinely usable
|
|
24
|
+
* if the adapter can name its tools in the runtime's own grant surface. That
|
|
25
|
+
* makes an unobserved server an inexpressible policy, not a smaller one: the
|
|
26
|
+
* task would claim, spawn a model, and then be told it may not call the very
|
|
27
|
+
* tools it was offered for. Rejecting before spawn is the same fail-closed
|
|
28
|
+
* posture the permission mappers already take for an inexpressible
|
|
29
|
+
* `denyTools` or `network` constraint.
|
|
30
|
+
*
|
|
31
|
+
* Reserved SDK servers are deliberately absent from the result: each carries
|
|
32
|
+
* a fixed grant its own protocol defines, never an observed one.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveMcpToolsetGrants(servers: Readonly<Record<string, McpStdioServerConfig>> | undefined, observation: McpToolsetToolObservation | undefined): McpToolsetGrantResolution;
|
|
35
|
+
/** Order-independent identity of one grant set, for adapters that must prove start() received the authority prepare() was admitted with. */
|
|
36
|
+
export declare function grantFingerprint(grants: readonly McpToolsetGrant[]): string;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export interface ResolvedPiExtensions {
|
|
2
2
|
readonly webAccess: string;
|
|
3
3
|
readonly mcpAdapter: string;
|
|
4
|
+
readonly subagentsPolicy: string;
|
|
5
|
+
readonly subagents: string;
|
|
6
|
+
readonly todo: string;
|
|
4
7
|
}
|
|
5
8
|
/**
|
|
6
|
-
* Resolve the
|
|
9
|
+
* Resolve the Pi extensions shipped as required `@byok-sdk/client`
|
|
7
10
|
* dependencies. Pi receives explicit extension paths so runtime behavior is
|
|
8
11
|
* pinned to this package graph rather than a user's mutable global Pi package
|
|
9
12
|
* settings.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const BYOK_PI_PERMISSION_MODE = "BYOK_PI_PERMISSION_MODE";
|
|
2
|
+
/** SDK-owned extension tools that do not mutate the task workspace. */
|
|
3
|
+
export declare const BYOK_PI_READONLY_PARENT_TOOLS: readonly ['subagent', 'todo'];
|
|
4
|
+
/** Child tools retained when a readonly parent delegates through pi-subagents. */
|
|
5
|
+
export declare const BYOK_PI_READONLY_SUBAGENT_TOOLS: readonly ['read', 'grep', 'find', 'ls'];
|
|
6
|
+
/** Package-provided read-only roles; writer and ambient custom roles stay unavailable. */
|
|
7
|
+
export declare const BYOK_PI_READONLY_SUBAGENT_AGENTS: readonly ['reviewer', 'oracle', 'codex-exec', 'claude-code', 'cursor-agent'];
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
|
|
3
|
+
// ../../node_modules/.bun/pi-subagents@0.60.0+ba57dcb6e433cb73/node_modules/pi-subagents/src/runs/shared/capability-ceiling.ts
|
|
4
|
+
var SUBAGENT_CAPABILITY_CEILING_VERSION = 1;
|
|
5
|
+
var SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY = "pi-subagents.capability-ceiling.v1";
|
|
6
|
+
function registry() {
|
|
7
|
+
const key = Symbol.for(SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY);
|
|
8
|
+
const store = globalThis;
|
|
9
|
+
const existing = store[key];
|
|
10
|
+
if (existing instanceof Map) return existing;
|
|
11
|
+
const created = /* @__PURE__ */ new Map();
|
|
12
|
+
store[key] = created;
|
|
13
|
+
return created;
|
|
14
|
+
}
|
|
15
|
+
function validateText(value, field) {
|
|
16
|
+
if (typeof value !== "string" || !value.trim() || /[\u0000-\u001f\u007f]/u.test(value) || Buffer.byteLength(value.trim(), "utf8") > 256) {
|
|
17
|
+
throw new Error(`Invalid capability ceiling ${field}; expected a non-empty string without control characters (max 256 UTF-8 bytes).`);
|
|
18
|
+
}
|
|
19
|
+
return value.trim();
|
|
20
|
+
}
|
|
21
|
+
function normalizeCeiling(ceiling) {
|
|
22
|
+
if (!ceiling || typeof ceiling !== "object" || Array.isArray(ceiling)) throw new Error("Invalid capability ceiling; expected an object.");
|
|
23
|
+
const hasAllowedTools = Object.hasOwn(ceiling, "allowedTools");
|
|
24
|
+
const hasAllowedAgents = Object.hasOwn(ceiling, "allowedAgents");
|
|
25
|
+
const hasDenyExtensions = Object.hasOwn(ceiling, "denyExtensions");
|
|
26
|
+
if (!hasAllowedTools && !hasAllowedAgents && !hasDenyExtensions) throw new Error("Invalid capability ceiling; expected allowedTools, allowedAgents, or denyExtensions.");
|
|
27
|
+
if (hasDenyExtensions && typeof ceiling.denyExtensions !== "boolean") throw new Error("Invalid capability ceiling denyExtensions; expected a boolean.");
|
|
28
|
+
const normalizeList = (field, pattern) => {
|
|
29
|
+
if (!Object.hasOwn(ceiling, field)) return void 0;
|
|
30
|
+
const values = ceiling[field];
|
|
31
|
+
if (!Array.isArray(values)) throw new Error(`Invalid capability ceiling ${field}; expected an array.`);
|
|
32
|
+
if (values.length > 256) throw new Error(`Invalid capability ceiling ${field}; expected at most 256 names.`);
|
|
33
|
+
return [...new Set(values.map((entry) => {
|
|
34
|
+
const name = validateText(entry, `${field} entry`);
|
|
35
|
+
if (!pattern.test(name)) throw new Error(`Invalid capability ceiling ${field} entry '${name}'.`);
|
|
36
|
+
if (Buffer.byteLength(name, "utf8") > 128) throw new Error(`Invalid capability ceiling ${field} entry '${name}'; max 128 UTF-8 bytes.`);
|
|
37
|
+
return name;
|
|
38
|
+
}))].sort();
|
|
39
|
+
};
|
|
40
|
+
const allowedTools = normalizeList("allowedTools", /^[A-Za-z0-9_.:-]+$/u);
|
|
41
|
+
const allowedAgents = normalizeList("allowedAgents", /^[A-Za-z0-9_.:-]+$/u);
|
|
42
|
+
return {
|
|
43
|
+
version: SUBAGENT_CAPABILITY_CEILING_VERSION,
|
|
44
|
+
...allowedTools !== void 0 ? { allowedTools } : {},
|
|
45
|
+
...allowedAgents !== void 0 ? { allowedAgents } : {},
|
|
46
|
+
denyExtensions: ceiling.denyExtensions === true,
|
|
47
|
+
sources: []
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function registerSubagentCapabilityCeiling(options) {
|
|
51
|
+
const sessionId = validateText(options.sessionId, "sessionId");
|
|
52
|
+
const source = validateText(options.source, "source");
|
|
53
|
+
let normalized = normalizeCeiling(options.ceiling);
|
|
54
|
+
const token = Symbol(source);
|
|
55
|
+
const store = registry();
|
|
56
|
+
let session = store.get(sessionId);
|
|
57
|
+
if (!session) {
|
|
58
|
+
session = /* @__PURE__ */ new Map();
|
|
59
|
+
store.set(sessionId, session);
|
|
60
|
+
}
|
|
61
|
+
const setRegistration = () => {
|
|
62
|
+
normalized = normalizeCeiling(normalized);
|
|
63
|
+
normalized.sources = [source];
|
|
64
|
+
session.set(token, { source, ceiling: normalized });
|
|
65
|
+
};
|
|
66
|
+
setRegistration();
|
|
67
|
+
let disposed = false;
|
|
68
|
+
return {
|
|
69
|
+
update(ceiling) {
|
|
70
|
+
if (disposed) throw new Error("Cannot update a disposed capability ceiling handle.");
|
|
71
|
+
normalized = normalizeCeiling(ceiling);
|
|
72
|
+
normalized.sources = [source];
|
|
73
|
+
session.set(token, { source, ceiling: normalized });
|
|
74
|
+
},
|
|
75
|
+
dispose() {
|
|
76
|
+
if (disposed) return;
|
|
77
|
+
disposed = true;
|
|
78
|
+
session.delete(token);
|
|
79
|
+
if (session.size === 0) store.delete(sessionId);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/adapters/pi/subagents-policy-config.ts
|
|
85
|
+
var BYOK_PI_PERMISSION_MODE = "BYOK_PI_PERMISSION_MODE";
|
|
86
|
+
var BYOK_PI_READONLY_SUBAGENT_TOOLS = ["read", "grep", "find", "ls"];
|
|
87
|
+
var BYOK_PI_READONLY_SUBAGENT_AGENTS = [
|
|
88
|
+
"reviewer",
|
|
89
|
+
"oracle",
|
|
90
|
+
"codex-exec",
|
|
91
|
+
"claude-code",
|
|
92
|
+
"cursor-agent"
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
// src/adapters/pi/subagents-policy-extension.ts
|
|
96
|
+
function permissionMode() {
|
|
97
|
+
const mode = process.env[BYOK_PI_PERMISSION_MODE];
|
|
98
|
+
if (mode === "auto" || mode === "readonly") return mode;
|
|
99
|
+
throw new Error(`${BYOK_PI_PERMISSION_MODE} must be "auto" or "readonly"`);
|
|
100
|
+
}
|
|
101
|
+
function registerByokSubagentsPolicy(pi) {
|
|
102
|
+
const mode = permissionMode();
|
|
103
|
+
let ceiling;
|
|
104
|
+
pi.on("session_start", (_event, ctx) => {
|
|
105
|
+
ceiling?.dispose();
|
|
106
|
+
ceiling = void 0;
|
|
107
|
+
if (mode === "auto") return;
|
|
108
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
109
|
+
if (!sessionId) throw new Error("readonly Pi subagent policy requires an authoritative session id");
|
|
110
|
+
ceiling = registerSubagentCapabilityCeiling({
|
|
111
|
+
sessionId,
|
|
112
|
+
source: "byok-sdk-readonly",
|
|
113
|
+
ceiling: {
|
|
114
|
+
allowedTools: BYOK_PI_READONLY_SUBAGENT_TOOLS,
|
|
115
|
+
allowedAgents: BYOK_PI_READONLY_SUBAGENT_AGENTS,
|
|
116
|
+
denyExtensions: true
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
pi.on("tool_call", (event) => {
|
|
121
|
+
if (mode === "readonly" && event.toolName === "subagent" && ceiling === void 0) {
|
|
122
|
+
return {
|
|
123
|
+
block: true,
|
|
124
|
+
terminate: true,
|
|
125
|
+
reason: "readonly Pi subagent capability ceiling is unavailable"
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
pi.on("session_shutdown", () => {
|
|
130
|
+
ceiling?.dispose();
|
|
131
|
+
ceiling = void 0;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { registerByokSubagentsPolicy as default };
|
|
136
|
+
//# sourceMappingURL=subagents-policy-extension.js.map
|
|
137
|
+
//# sourceMappingURL=subagents-policy-extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../node_modules/.bun/pi-subagents@0.60.0+ba57dcb6e433cb73/node_modules/pi-subagents/src/runs/shared/capability-ceiling.ts","../../../src/adapters/pi/subagents-policy-config.ts","../../../src/adapters/pi/subagents-policy-extension.ts"],"names":[],"mappings":"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","file":"subagents-policy-extension.js","sourcesContent":["import { Buffer } from \"node:buffer\";\n\nexport const SUBAGENT_CAPABILITY_CEILING_VERSION = 1 as const;\nexport const SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY = \"pi-subagents.capability-ceiling.v1\";\nexport const SUBAGENT_CAPABILITY_CEILING_ENV = \"PI_SUBAGENT_CAPABILITY_CEILING_V1\";\n\nexport type SubagentCapabilityCeiling =\n\t| { allowedTools: readonly string[]; allowedAgents?: readonly string[]; denyExtensions?: boolean }\n\t| { allowedTools?: readonly string[]; allowedAgents?: readonly string[]; denyExtensions: boolean }\n\t| { allowedTools?: readonly string[]; allowedAgents: readonly string[]; denyExtensions?: boolean };\n\nexport interface ResolvedSubagentCapabilityCeiling {\n\tversion: typeof SUBAGENT_CAPABILITY_CEILING_VERSION;\n\tallowedTools?: string[];\n\tallowedAgents?: string[];\n\tdenyExtensions: boolean;\n\tsources: string[];\n}\n\nexport interface SubagentCapabilityAudit {\n\tceiling: ResolvedSubagentCapabilityCeiling;\n\trequestedTools?: string[];\n\teffectiveTools: string[];\n\tremovedTools: string[];\n\tinternalTools: string[];\n\textensionsDenied: boolean;\n\tremovedExtensionCount: number;\n\trequestedMcpToolCount: number;\n\teffectiveMcpTools: string[];\n\tagentAllowed: boolean;\n\tagentRestrictionSources?: string[];\n}\n\nexport interface RegisterSubagentCapabilityCeilingOptions {\n\tsessionId: string;\n\tsource: string;\n\tceiling: SubagentCapabilityCeiling;\n}\n\nexport interface SubagentCapabilityCeilingHandle {\n\tupdate(ceiling: SubagentCapabilityCeiling): void;\n\tdispose(): void;\n}\n\ntype Registration = { source: string; ceiling: ResolvedSubagentCapabilityCeiling };\ntype Registry = Map<string, Map<symbol, Registration>>;\n\nfunction registry(): Registry {\n\tconst key = Symbol.for(SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY);\n\tconst store = globalThis as typeof globalThis & { [key: symbol]: unknown };\n\tconst existing = store[key];\n\tif (existing instanceof Map) return existing as Registry;\n\tconst created: Registry = new Map();\n\tstore[key] = created;\n\treturn created;\n}\n\nfunction validateText(value: unknown, field: string): string {\n\tif (typeof value !== \"string\" || !value.trim() || /[\\u0000-\\u001f\\u007f]/u.test(value) || Buffer.byteLength(value.trim(), \"utf8\") > 256) {\n\t\tthrow new Error(`Invalid capability ceiling ${field}; expected a non-empty string without control characters (max 256 UTF-8 bytes).`);\n\t}\n\treturn value.trim();\n}\n\nfunction normalizeCeiling(ceiling: SubagentCapabilityCeiling): ResolvedSubagentCapabilityCeiling {\n\tif (!ceiling || typeof ceiling !== \"object\" || Array.isArray(ceiling)) throw new Error(\"Invalid capability ceiling; expected an object.\");\n\tconst hasAllowedTools = Object.hasOwn(ceiling, \"allowedTools\");\n\tconst hasAllowedAgents = Object.hasOwn(ceiling, \"allowedAgents\");\n\tconst hasDenyExtensions = Object.hasOwn(ceiling, \"denyExtensions\");\n\tif (!hasAllowedTools && !hasAllowedAgents && !hasDenyExtensions) throw new Error(\"Invalid capability ceiling; expected allowedTools, allowedAgents, or denyExtensions.\");\n\tif (hasDenyExtensions && typeof ceiling.denyExtensions !== \"boolean\") throw new Error(\"Invalid capability ceiling denyExtensions; expected a boolean.\");\n\tconst normalizeList = (field: \"allowedTools\" | \"allowedAgents\", pattern: RegExp): string[] | undefined => {\n\t\tif (!Object.hasOwn(ceiling, field)) return undefined;\n\t\tconst values = ceiling[field];\n\t\tif (!Array.isArray(values)) throw new Error(`Invalid capability ceiling ${field}; expected an array.`);\n\t\tif (values.length > 256) throw new Error(`Invalid capability ceiling ${field}; expected at most 256 names.`);\n\t\treturn [...new Set(values.map((entry) => {\n\t\t\tconst name = validateText(entry, `${field} entry`);\n\t\t\tif (!pattern.test(name)) throw new Error(`Invalid capability ceiling ${field} entry '${name}'.`);\n\t\t\tif (Buffer.byteLength(name, \"utf8\") > 128) throw new Error(`Invalid capability ceiling ${field} entry '${name}'; max 128 UTF-8 bytes.`);\n\t\t\treturn name;\n\t\t}))].sort();\n\t};\n\tconst allowedTools = normalizeList(\"allowedTools\", /^[A-Za-z0-9_.:-]+$/u);\n\tconst allowedAgents = normalizeList(\"allowedAgents\", /^[A-Za-z0-9_.:-]+$/u);\n\treturn {\n\t\tversion: SUBAGENT_CAPABILITY_CEILING_VERSION,\n\t\t...(allowedTools !== undefined ? { allowedTools } : {}),\n\t\t...(allowedAgents !== undefined ? { allowedAgents } : {}),\n\t\tdenyExtensions: ceiling.denyExtensions === true,\n\t\tsources: [],\n\t};\n}\n\nexport function parseSubagentCapabilityCeiling(value: unknown, field = \"capability ceiling\"): ResolvedSubagentCapabilityCeiling {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw new Error(`Invalid ${field}; expected an object.`);\n\tconst record = value as Record<string, unknown>;\n\tif (record.version !== SUBAGENT_CAPABILITY_CEILING_VERSION) throw new Error(`Invalid ${field} version.`);\n\tconst normalized = normalizeCeiling(record as SubagentCapabilityCeiling);\n\tconst sources = record.sources;\n\tif (!Array.isArray(sources) || sources.some((source) => typeof source !== \"string\")) throw new Error(`Invalid ${field} sources; expected an array of strings.`);\n\tnormalized.sources = [...new Set(sources.map((source) => validateText(source, `${field} source`)))].sort();\n\treturn normalized;\n}\n\nexport function registerSubagentCapabilityCeiling(options: RegisterSubagentCapabilityCeilingOptions): SubagentCapabilityCeilingHandle {\n\tconst sessionId = validateText(options.sessionId, \"sessionId\");\n\tconst source = validateText(options.source, \"source\");\n\tlet normalized = normalizeCeiling(options.ceiling);\n\tconst token = Symbol(source);\n\tconst store = registry();\n\tlet session = store.get(sessionId);\n\tif (!session) {\n\t\tsession = new Map();\n\t\tstore.set(sessionId, session);\n\t}\n\tconst setRegistration = () => {\n\t\tnormalized = normalizeCeiling(normalized);\n\t\tnormalized.sources = [source];\n\t\tsession!.set(token, { source, ceiling: normalized });\n\t};\n\tsetRegistration();\n\tlet disposed = false;\n\treturn {\n\t\tupdate(ceiling) {\n\t\t\tif (disposed) throw new Error(\"Cannot update a disposed capability ceiling handle.\");\n\t\t\tnormalized = normalizeCeiling(ceiling);\n\t\t\tnormalized.sources = [source];\n\t\t\tsession!.set(token, { source, ceiling: normalized });\n\t\t},\n\t\tdispose() {\n\t\t\tif (disposed) return;\n\t\t\tdisposed = true;\n\t\t\tsession!.delete(token);\n\t\t\tif (session!.size === 0) store.delete(sessionId);\n\t\t},\n\t};\n}\n\nexport function intersectSubagentCapabilityCeilings(...ceilings: Array<ResolvedSubagentCapabilityCeiling | undefined>): ResolvedSubagentCapabilityCeiling | undefined {\n\tconst active = ceilings.filter((ceiling): ceiling is ResolvedSubagentCapabilityCeiling => ceiling !== undefined);\n\tif (active.length === 0) return undefined;\n\tconst intersectLists = (field: \"allowedTools\" | \"allowedAgents\"): string[] | undefined => {\n\t\tconst definedLists = active.filter((ceiling) => ceiling[field] !== undefined).map((ceiling) => new Set(ceiling[field]));\n\t\tif (definedLists.length === 0) return undefined;\n\t\treturn [...definedLists[0]!].filter((entry) => definedLists.every((list) => list.has(entry))).sort();\n\t};\n\tconst allowedTools = intersectLists(\"allowedTools\");\n\tconst allowedAgents = intersectLists(\"allowedAgents\");\n\treturn {\n\t\tversion: SUBAGENT_CAPABILITY_CEILING_VERSION,\n\t\t...(allowedTools !== undefined ? { allowedTools } : {}),\n\t\t...(allowedAgents !== undefined ? { allowedAgents } : {}),\n\t\tdenyExtensions: active.some((ceiling) => ceiling.denyExtensions),\n\t\tsources: [...new Set(active.flatMap((ceiling) => ceiling.sources))].sort(),\n\t};\n}\n\nexport function resolveSubagentCapabilityCeiling(sessionId: string | undefined, inherited?: ResolvedSubagentCapabilityCeiling): ResolvedSubagentCapabilityCeiling | undefined {\n\tconst active: ResolvedSubagentCapabilityCeiling[] = [];\n\tif (sessionId) {\n\t\tconst registrations = registry().get(sessionId);\n\t\tif (registrations) active.push(...Array.from(registrations.values(), ({ ceiling }) => ceiling));\n\t}\n\treturn intersectSubagentCapabilityCeilings(inherited, ...active);\n}\n\nexport function resolveCurrentSubagentCapabilityCeiling(sessionId: string | undefined): ResolvedSubagentCapabilityCeiling | undefined {\n\treturn resolveSubagentCapabilityCeiling(sessionId, decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]));\n}\n\nexport function isAgentAllowedByCapabilityCeiling(agentName: string, ceiling: ResolvedSubagentCapabilityCeiling | undefined): boolean {\n\treturn ceiling?.allowedAgents === undefined || ceiling.allowedAgents.includes(agentName);\n}\n\nexport function capabilityCeilingAgentRestrictionMessage(agentName: string, ceiling: ResolvedSubagentCapabilityCeiling | undefined): string | undefined {\n\tif (isAgentAllowedByCapabilityCeiling(agentName, ceiling)) return undefined;\n\tconst sources = ceiling?.sources.length ? ceiling.sources.join(\", \") : \"unknown source\";\n\tconst allowed = ceiling?.allowedAgents?.length ? ceiling.allowedAgents.join(\", \") : \"(none)\";\n\treturn `Capability ceiling from ${sources} does not allow agent '${agentName}'. Allowed agents: ${allowed}.`;\n}\n\nexport function assertAgentAllowedByCapabilityCeiling(agentName: string, ceiling: ResolvedSubagentCapabilityCeiling | undefined): void {\n\tconst message = capabilityCeilingAgentRestrictionMessage(agentName, ceiling);\n\tif (message) throw new Error(message);\n}\n\nexport function capabilityCeilingAgentRestrictionSources(ceiling: ResolvedSubagentCapabilityCeiling | undefined): string[] | undefined {\n\treturn ceiling?.allowedAgents === undefined ? undefined : [...ceiling.sources];\n}\n\nexport function encodeSubagentCapabilityCeiling(ceiling: ResolvedSubagentCapabilityCeiling | undefined): string | undefined {\n\tif (!ceiling) return undefined;\n\treturn Buffer.from(JSON.stringify(ceiling), \"utf8\").toString(\"base64url\");\n}\n\nexport function decodeSubagentCapabilityCeiling(value: string | undefined): ResolvedSubagentCapabilityCeiling | undefined {\n\tif (value === undefined || value === \"\") return undefined;\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(Buffer.from(value, \"base64url\").toString(\"utf8\"));\n\t} catch (error) {\n\t\tthrow new Error(`Invalid inherited capability ceiling: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed) || (parsed as { version?: unknown }).version !== SUBAGENT_CAPABILITY_CEILING_VERSION) {\n\t\tthrow new Error(\"Invalid inherited capability ceiling version.\");\n\t}\n\treturn parseSubagentCapabilityCeiling(parsed, \"inherited capability ceiling\");\n}\n","export const BYOK_PI_PERMISSION_MODE = 'BYOK_PI_PERMISSION_MODE';\n\n/** SDK-owned extension tools that do not mutate the task workspace. */\nexport const BYOK_PI_READONLY_PARENT_TOOLS = ['subagent', 'todo'] as const;\n\n/** Child tools retained when a readonly parent delegates through pi-subagents. */\nexport const BYOK_PI_READONLY_SUBAGENT_TOOLS = ['read', 'grep', 'find', 'ls'] as const;\n\n/** Package-provided read-only roles; writer and ambient custom roles stay unavailable. */\nexport const BYOK_PI_READONLY_SUBAGENT_AGENTS = [\n 'reviewer',\n 'oracle',\n 'codex-exec',\n 'claude-code',\n 'cursor-agent',\n] as const;\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport {\n registerSubagentCapabilityCeiling,\n type SubagentCapabilityCeilingHandle,\n} from 'pi-subagents/capability-ceiling';\nimport {\n BYOK_PI_PERMISSION_MODE,\n BYOK_PI_READONLY_SUBAGENT_AGENTS,\n BYOK_PI_READONLY_SUBAGENT_TOOLS,\n} from './subagents-policy-config';\n\nfunction permissionMode(): 'auto' | 'readonly' {\n const mode = process.env[BYOK_PI_PERMISSION_MODE];\n if (mode === 'auto' || mode === 'readonly') return mode;\n throw new Error(`${BYOK_PI_PERMISSION_MODE} must be \"auto\" or \"readonly\"`);\n}\n\n/**\n * Keep pi-subagents available in every Pi session without letting a readonly\n * parent widen its task contract through a child process.\n */\nexport default function registerByokSubagentsPolicy(pi: ExtensionAPI): void {\n const mode = permissionMode();\n let ceiling: SubagentCapabilityCeilingHandle | undefined;\n\n pi.on('session_start', (_event, ctx) => {\n ceiling?.dispose();\n ceiling = undefined;\n if (mode === 'auto') return;\n\n const sessionId = ctx.sessionManager.getSessionId();\n if (!sessionId) throw new Error('readonly Pi subagent policy requires an authoritative session id');\n ceiling = registerSubagentCapabilityCeiling({\n sessionId,\n source: 'byok-sdk-readonly',\n ceiling: {\n allowedTools: BYOK_PI_READONLY_SUBAGENT_TOOLS,\n allowedAgents: BYOK_PI_READONLY_SUBAGENT_AGENTS,\n denyExtensions: true,\n },\n });\n });\n\n pi.on('tool_call', (event) => {\n if (mode === 'readonly' && event.toolName === 'subagent' && ceiling === undefined) {\n return {\n block: true,\n terminate: true,\n reason: 'readonly Pi subagent capability ceiling is unavailable',\n };\n }\n });\n\n pi.on('session_shutdown', () => {\n ceiling?.dispose();\n ceiling = undefined;\n });\n}\n"]}
|
|
@@ -80,7 +80,7 @@ export type { AgentMemoryFilesystem } from '../daemon/agent-memory-filesystem';
|
|
|
80
80
|
export type { AgentMemoryFilesystemFileState } from '../daemon/agent-memory-filesystem';
|
|
81
81
|
/** Product-owned deployment pointer to the helper binary; the SDK never searches PATH. */
|
|
82
82
|
export type { AgentMemoryFilesystemHelperConfig } from '../daemon/agent-memory-filesystem';
|
|
83
|
-
/** Serves `
|
|
83
|
+
/** Serves `memory_recall`/`memory_save` as a stdio MCP server over host-provided streams. */
|
|
84
84
|
export { serveAgentMemoryMcpOverStdio } from '../bin/agent-memory-mcp-server';
|
|
85
85
|
/** MCP tool name a host must allowlist for reads. */
|
|
86
86
|
export { AGENT_MEMORY_RECALL_TOOL_NAME } from '../bin/agent-memory-mcp-server';
|
|
@@ -678,8 +678,8 @@ var AgentMemoryFilesystemHelperClient = class _AgentMemoryFilesystemHelperClient
|
|
|
678
678
|
async function openAgentMemoryFilesystemHelper(input) {
|
|
679
679
|
return AgentMemoryFilesystemHelperClient.open(input);
|
|
680
680
|
}
|
|
681
|
-
var AGENT_MEMORY_RECALL_TOOL_NAME = "
|
|
682
|
-
var AGENT_MEMORY_SAVE_TOOL_NAME = "
|
|
681
|
+
var AGENT_MEMORY_RECALL_TOOL_NAME = "memory_recall";
|
|
682
|
+
var AGENT_MEMORY_SAVE_TOOL_NAME = "memory_save";
|
|
683
683
|
function record(value) {
|
|
684
684
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
685
685
|
}
|
|
@@ -710,11 +710,11 @@ async function handleAgentMemoryMcpRequest(request, deps) {
|
|
|
710
710
|
if (!params || !args || typeof params.name !== "string") return invalid(id, "memory tool input must be an object");
|
|
711
711
|
try {
|
|
712
712
|
if (params.name === AGENT_MEMORY_RECALL_TOOL_NAME) {
|
|
713
|
-
if (Object.keys(args).some((key) => key !== "path" && key !== "ifRevision") || typeof args.path !== "string" || args.ifRevision !== void 0 && typeof args.ifRevision !== "string") return invalid(id, "
|
|
713
|
+
if (Object.keys(args).some((key) => key !== "path" && key !== "ifRevision") || typeof args.path !== "string" || args.ifRevision !== void 0 && typeof args.ifRevision !== "string") return invalid(id, "memory_recall accepts only path and optional ifRevision");
|
|
714
714
|
return success(id, await deps.recall({ path: args.path, ...args.ifRevision === void 0 ? {} : { ifRevision: args.ifRevision } }));
|
|
715
715
|
}
|
|
716
716
|
if (params.name === AGENT_MEMORY_SAVE_TOOL_NAME) {
|
|
717
|
-
if (Object.keys(args).some((key) => key !== "op" && key !== "path" && key !== "expectedRevision" && key !== "content") || args.op !== "replace" && args.op !== "delete" || typeof args.path !== "string" || typeof args.expectedRevision !== "string" || args.op === "replace" && typeof args.content !== "string" || args.op === "delete" && args.content !== void 0) return invalid(id, "
|
|
717
|
+
if (Object.keys(args).some((key) => key !== "op" && key !== "path" && key !== "expectedRevision" && key !== "content") || args.op !== "replace" && args.op !== "delete" || typeof args.path !== "string" || typeof args.expectedRevision !== "string" || args.op === "replace" && typeof args.content !== "string" || args.op === "delete" && args.content !== void 0) return invalid(id, "memory_save requires replace|delete, path, expectedRevision, and content only for replace");
|
|
718
718
|
const content = args.content;
|
|
719
719
|
return success(id, await deps.save({ op: args.op, path: args.path, expectedRevision: args.expectedRevision, ...typeof content === "string" ? { content } : {} }));
|
|
720
720
|
}
|