@byok-sdk/client 0.12.0 → 0.13.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 +13 -0
- package/dist/adapters/index.js +74 -5
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/pi/pi-adapter.d.ts +3 -0
- package/dist/adapters/pi/subagents-policy-extension.js +1 -1
- package/dist/adapters/pi/subagents-policy-extension.js.map +1 -1
- package/dist/agent-home.d.ts +74 -0
- package/dist/agent-memory/index.d.ts +1 -1
- package/dist/agent-memory/index.js.map +1 -1
- package/dist/bin/byok-agent-memory-mcp.js.map +1 -1
- package/dist/bin/byok-agent-message-mcp.js.map +1 -1
- package/dist/bin/byok-agent-team-mcp.js.map +1 -1
- package/dist/bin/byok-agent.js +467 -485
- package/dist/bin/byok-agent.js.map +1 -1
- package/dist/bin/byok-approval-mcp.js.map +1 -1
- package/dist/daemon/connection-manager.d.ts +63 -127
- package/dist/daemon/control-protocol.d.ts +8 -1
- package/dist/daemon/create-daemon.d.ts +26 -13
- package/dist/daemon/long-poll-transport.d.ts +29 -23
- package/dist/daemon/observer.d.ts +1 -1
- package/dist/daemon/task-runner.d.ts +18 -0
- package/dist/daemon/url.d.ts +10 -12
- package/dist/diagnostics/support-bundle.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +465 -483
- package/dist/index.js.map +1 -1
- package/package.json +5 -7
- package/dist/daemon/ws-transport.d.ts +0 -139
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderProfileBinding } from '@byok-sdk/protocol';
|
|
1
2
|
import { type RuntimeAdapter, type RuntimeDetectResult, type RuntimeAdapterPrepareInput, type RuntimeAdapterPrepareResult } from '../../types';
|
|
2
3
|
import { type ResolvedBin } from './resolve-bin';
|
|
3
4
|
import { type ResolvedPiExtensions } from './resolve-extensions';
|
|
@@ -22,6 +23,8 @@ export interface PiAdapterOptions {
|
|
|
22
23
|
* and transparently proxies the pinned Pi RPC process.
|
|
23
24
|
*/
|
|
24
25
|
byokLauncher?: PiByokLauncherConfig;
|
|
26
|
+
/** Admission-time exact local profile check. Tests may replace the process boundary. */
|
|
27
|
+
validateProviderProfileBinding?: (binding: ProviderProfileBinding, launcher: PiByokLauncherConfig) => Promise<void>;
|
|
25
28
|
}
|
|
26
29
|
export interface PiByokLauncherConfig {
|
|
27
30
|
command: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
|
|
3
|
-
// ../../node_modules/.bun/pi-subagents@0.60.0+
|
|
3
|
+
// ../../node_modules/.bun/pi-subagents@0.60.0+5b15fedd58145c46/node_modules/pi-subagents/src/runs/shared/capability-ceiling.ts
|
|
4
4
|
var SUBAGENT_CAPABILITY_CEILING_VERSION = 1;
|
|
5
5
|
var SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY = "pi-subagents.capability-ceiling.v1";
|
|
6
6
|
function registry() {
|
|
@@ -1 +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"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../node_modules/.bun/pi-subagents@0.60.0+5b15fedd58145c46/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"]}
|
package/dist/agent-home.d.ts
CHANGED
|
@@ -93,6 +93,27 @@ export declare class AgentHomeLayout {
|
|
|
93
93
|
private canonicalRoot?;
|
|
94
94
|
constructor(hostStorageRoot: string);
|
|
95
95
|
resolve(agentRefInput: AgentRef): Promise<AgentHomeResolution>;
|
|
96
|
+
/**
|
|
97
|
+
* Pure canonical-home derivation for read-only callers, such as the
|
|
98
|
+
* pre-admission single-writer count. It validates the AgentRef and joins
|
|
99
|
+
* exactly the same `<hostStorageRoot>/agents/<agentId>` segments
|
|
100
|
+
* {@link AgentHomeLayout.resolve} would, canonicalizing only the components
|
|
101
|
+
* that already exist.
|
|
102
|
+
*
|
|
103
|
+
* It deliberately creates no directory, takes no cross-process mutation
|
|
104
|
+
* gate and records no Agent binding, so an offer the host vetoes after the
|
|
105
|
+
* count leaves nothing behind on disk. `resolve()` stays the only path that
|
|
106
|
+
* may materialize a home or bind it to an Agent identity.
|
|
107
|
+
*
|
|
108
|
+
* An `agents` root or `agents/<agentId>` leaf that already exists but is a
|
|
109
|
+
* symlink (or any non-directory) is rejected here with the same error class
|
|
110
|
+
* and message `resolve()` raises for it, so an in-root `two -> one` link
|
|
111
|
+
* fails closed instead of silently keying the count of `one`. A leaf that
|
|
112
|
+
* does not exist yet is not an error: this derivation runs before the home
|
|
113
|
+
* is materialized. A home canonicalizing outside the `agents` root stays
|
|
114
|
+
* rejected as before.
|
|
115
|
+
*/
|
|
116
|
+
canonicalHomePath(agentRefInput: AgentRef): Promise<string>;
|
|
96
117
|
/**
|
|
97
118
|
* Prove the canonical root is materializable and writable before the daemon
|
|
98
119
|
* advertises Agent-home capability. No Agent identity or persistent Agent
|
|
@@ -120,10 +141,33 @@ export declare class AgentHomeLeaseManager {
|
|
|
120
141
|
acquire(resolution: AgentHomeResolution): Promise<AgentHomeLease>;
|
|
121
142
|
private openLeaseMarker;
|
|
122
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* WP0: counts-only readback of the per-canonical-Agent-home Attempt cap and
|
|
146
|
+
* what one daemon currently holds against it. Deliberately carries no home
|
|
147
|
+
* path, agentId or taskId: it exists so an operator can see that a home is
|
|
148
|
+
* still busy — including the fail-closed case where a failed `Session.close()`
|
|
149
|
+
* keeps the slot held after the task itself is gone — not to enumerate Agents.
|
|
150
|
+
* Projected into both `Daemon.status()` and the authenticated local control
|
|
151
|
+
* status (`create-daemon.ts`).
|
|
152
|
+
*/
|
|
153
|
+
export interface AgentHomeExecutionStatus {
|
|
154
|
+
/** Effective `DaemonConfig.maxConcurrentMutableSessionsPerAgentHome` for this daemon. */
|
|
155
|
+
maxConcurrentMutableSessionsPerAgentHome: number;
|
|
156
|
+
/** Canonical Agent homes this daemon currently holds at least one execution lease in. */
|
|
157
|
+
activeHomes: number;
|
|
158
|
+
/** Total Attempts holding an execution lease across those homes. */
|
|
159
|
+
activeAttempts: number;
|
|
160
|
+
}
|
|
123
161
|
/**
|
|
124
162
|
* Session-scoped execution leases share one process-owned home marker. The
|
|
125
163
|
* marker remains until the final session exits, so relocation still sees the
|
|
126
164
|
* Agent home as active, while different sessions no longer exclude each other.
|
|
165
|
+
*
|
|
166
|
+
* This layer counts; it does not cap. How many Attempts may be active in one
|
|
167
|
+
* canonical home is a daemon admission decision made once, before any side
|
|
168
|
+
* effect, by `TaskRunner.handleOffer`'s per-home busy gate reading
|
|
169
|
+
* {@link AgentHomeExecutionLeaseManager.activeAttemptCount} against
|
|
170
|
+
* `DaemonConfig.maxConcurrentMutableSessionsPerAgentHome` (default 1).
|
|
127
171
|
*/
|
|
128
172
|
export declare class AgentHomeExecutionLeaseManager {
|
|
129
173
|
private readonly manager;
|
|
@@ -134,6 +178,36 @@ export declare class AgentHomeExecutionLeaseManager {
|
|
|
134
178
|
readonly taskId: string;
|
|
135
179
|
readonly sessionRef?: string;
|
|
136
180
|
}): Promise<AgentHomeExecutionLease>;
|
|
181
|
+
/**
|
|
182
|
+
* WP0: Attempts currently holding an execution lease on this exact
|
|
183
|
+
* canonical home, across every lane and every session. This is the number
|
|
184
|
+
* the daemon's admission gate reads before any side effect — see
|
|
185
|
+
* `TaskRunner.handleOffer`'s per-home busy gate.
|
|
186
|
+
*
|
|
187
|
+
* Derived from the one lease registry above rather than a second tally, so
|
|
188
|
+
* it inherits the lease lifecycle exactly: an entry appears at `acquire()`,
|
|
189
|
+
* survives `bindSession()` (which rekeys in place), and disappears only at
|
|
190
|
+
* `release()`, which the task runner calls after the attempt is terminal
|
|
191
|
+
* AND `Session.close()` resolved. A failed disposal never reaches
|
|
192
|
+
* `release()`, so the slot stays held — fail closed, the same posture as
|
|
193
|
+
* `runtime-disposal-failed`. Crash residue needs nothing extra here: a
|
|
194
|
+
* restarted daemon starts with an empty registry and reclaims the on-disk
|
|
195
|
+
* marker only under the same stable owner identity (`openLeaseMarker`).
|
|
196
|
+
*
|
|
197
|
+
* Counted regardless of which lease manager owns the group: the invariant
|
|
198
|
+
* being protected is the filesystem path (`MEMORY.md`, `notes/`, `.git`),
|
|
199
|
+
* not the owner identity.
|
|
200
|
+
*/
|
|
201
|
+
activeAttemptCount(canonicalHome: string): number;
|
|
202
|
+
/**
|
|
203
|
+
* Counts-only readback for daemon/control status. Scoped to this manager's
|
|
204
|
+
* own leases, so the number describes this daemon rather than every home
|
|
205
|
+
* any manager in the process happens to hold. Never exposes a home path.
|
|
206
|
+
*/
|
|
207
|
+
activeAttemptSummary(): {
|
|
208
|
+
readonly homes: number;
|
|
209
|
+
readonly attempts: number;
|
|
210
|
+
};
|
|
137
211
|
mutate<T>(binding: AgentHomeExecutionBinding, operation: () => Promise<T>): Promise<T>;
|
|
138
212
|
private exclusive;
|
|
139
213
|
}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*
|
|
31
31
|
* 2. The transport. Nothing reachable from this entry may import `ws`, the
|
|
32
32
|
* daemon composition, or any transport module. Importing a single memory
|
|
33
|
-
* symbol from the root entry drags
|
|
33
|
+
* symbol from the root entry drags daemon transport into a host
|
|
34
34
|
* bundle; the subpath exists so it does not. `__tests__/agent-memory-entry-
|
|
35
35
|
* constraints.test.ts` walks this module graph and `scripts/check-agent-
|
|
36
36
|
* memory-entry.mjs` re-checks the built bundle.
|