pi-fabric 0.92.32 → 0.92.33
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/dist/chunks/{chunk-DUMIK5RZ.js → chunk-CEXO6ELQ.js} +2 -2
- package/dist/chunks/{chunk-JOEFBOFN.js → chunk-DLLIRB63.js} +2 -2
- package/dist/chunks/{chunk-FAMBJFFF.js → chunk-IJL3QK3J.js} +3 -1
- package/dist/chunks/chunk-IJL3QK3J.js.map +7 -0
- package/dist/core/action-registry.js +2 -2
- package/dist/core/shell-middleware.d.ts +4 -0
- package/dist/core/shell-middleware.d.ts.map +1 -0
- package/dist/fabric-runtime-state.js +76 -18
- package/dist/fabric-runtime-state.js.map +3 -3
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +10 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +3 -1
- package/dist/providers/pi-tools-provider.d.ts.map +1 -1
- package/docs/configuration.md +1 -1
- package/docs/shell-middleware.md +61 -0
- package/package.json +1 -1
- package/dist/chunks/chunk-FAMBJFFF.js.map +0 -7
- /package/dist/chunks/{chunk-DUMIK5RZ.js.map → chunk-CEXO6ELQ.js.map} +0 -0
- /package/dist/chunks/{chunk-JOEFBOFN.js.map → chunk-DLLIRB63.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-J2HV2URQ.js";
|
|
5
5
|
import {
|
|
6
6
|
NESTED_TOOL_CALL_ID_PREFIX
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DLLIRB63.js";
|
|
8
8
|
import {
|
|
9
9
|
THINKING_DIGEST_CUSTOM_TYPE,
|
|
10
10
|
buildThinkingDigest,
|
|
@@ -2012,4 +2012,4 @@ export {
|
|
|
2012
2012
|
PrewalkController,
|
|
2013
2013
|
PrewalkDriftTracker
|
|
2014
2014
|
};
|
|
2015
|
-
//# sourceMappingURL=chunk-
|
|
2015
|
+
//# sourceMappingURL=chunk-CEXO6ELQ.js.map
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from "./chunk-PSNXUZMY.js";
|
|
27
27
|
import {
|
|
28
28
|
FABRIC_NESTED_TOOL_CALL_ID_PREFIX
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-IJL3QK3J.js";
|
|
30
30
|
import {
|
|
31
31
|
FabricResolutionError,
|
|
32
32
|
FabricTraceSafeError,
|
|
@@ -1467,4 +1467,4 @@ export {
|
|
|
1467
1467
|
NESTED_TOOL_CALL_ID_PREFIX,
|
|
1468
1468
|
ActionRegistry
|
|
1469
1469
|
};
|
|
1470
|
-
//# sourceMappingURL=chunk-
|
|
1470
|
+
//# sourceMappingURL=chunk-DLLIRB63.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/protocol.ts
|
|
2
|
+
var FABRIC_BASH_MIDDLEWARE = Symbol.for("pi-fabric:bash-middleware:v1");
|
|
2
3
|
var FABRIC_PROVIDER_REGISTER_EVENT = "pi-fabric:provider:register:v1";
|
|
3
4
|
var FABRIC_PROVIDER_DISCOVER_EVENT = "pi-fabric:provider:discover:v1";
|
|
4
5
|
var FABRIC_COMPONENT_REGISTER_EVENT = "pi-fabric:component:register:v1";
|
|
@@ -43,6 +44,7 @@ var readFabricToolResultProxyDetailsV1 = (value) => {
|
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
export {
|
|
47
|
+
FABRIC_BASH_MIDDLEWARE,
|
|
46
48
|
FABRIC_PROVIDER_REGISTER_EVENT,
|
|
47
49
|
FABRIC_PROVIDER_DISCOVER_EVENT,
|
|
48
50
|
FABRIC_COMPONENT_REGISTER_EVENT,
|
|
@@ -57,4 +59,4 @@ export {
|
|
|
57
59
|
FABRIC_TOOL_RESULT_PROXY_KIND,
|
|
58
60
|
readFabricToolResultProxyDetailsV1
|
|
59
61
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
62
|
+
//# sourceMappingURL=chunk-IJL3QK3J.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/protocol.ts"],
|
|
4
|
+
"sourcesContent": ["import type { BashOperations, BashToolOptions, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\n\n/** Host-local opt-in on a bash ToolDefinition; never serialized into guest schemas. */\nexport const FABRIC_BASH_MIDDLEWARE = Symbol.for(\"pi-fabric:bash-middleware:v1\");\n\n/** The extension keeps standalone execution; Fabric owns local process/job lifetime. */\nexport interface FabricBashMiddlewareV1 {\n version: 1;\n options?: Omit<BashToolOptions, \"operations\">;\n /** Filter output before Fabric retains it in previews, results, or background logs. */\n wrapOperations: (operations: BashOperations) => BashOperations;\n}\n\nexport const FABRIC_PROVIDER_REGISTER_EVENT = \"pi-fabric:provider:register:v1\";\nexport const FABRIC_PROVIDER_DISCOVER_EVENT = \"pi-fabric:provider:discover:v1\";\nexport const FABRIC_COMPONENT_REGISTER_EVENT = \"pi-fabric:component:register:v1\";\nexport const FABRIC_COMPONENT_DISCOVER_EVENT = \"pi-fabric:component:discover:v1\";\nexport const FABRIC_PREWALK_REQUEST_EVENT = \"pi-fabric:prewalk:request:v1\";\n\nexport type FabricPrewalkRequestResultV1 =\n | { ok: true }\n | { ok: false; error: string };\n\n/** Host-local request used by queue extensions that need an acknowledged prewalk arm. */\nexport interface FabricPrewalkRequestV1 {\n version: 1;\n context: ExtensionContext;\n claim: () => boolean;\n respond: (result: FabricPrewalkRequestResultV1) => void;\n}\n\nexport const readFabricPrewalkRequestV1 = (\n value: unknown,\n): FabricPrewalkRequestV1 | undefined => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n if (\n record.version !== 1 ||\n typeof record.context !== \"object\" ||\n record.context === null ||\n typeof record.claim !== \"function\" ||\n typeof record.respond !== \"function\"\n ) {\n return undefined;\n }\n return value as FabricPrewalkRequestV1;\n};\n\nexport const FABRIC_PEER_CARDS_EVENT = \"pi-fabric:peers:cards:v1\";\nexport const FABRIC_PEER_AWAIT_SETTLE_EVENT = \"pi-fabric:peer:await-settle:v1\";\n\n/** One root peer session on the project mesh, for pickers and status lines. */\nexport interface FabricPeerCardV1 {\n id: string;\n /** Linear-style project label (e.g. \"PQS-2\") minted by the owning host. */\n label: string;\n status: \"idle\" | \"running\";\n model?: string;\n cwd?: string;\n startedAt: number;\n updatedAt: number;\n pendingMessages: boolean;\n}\n\nexport type FabricPeerCardsResultV1 =\n | { ok: true; cards: FabricPeerCardV1[] }\n | { ok: false; error: string };\n\n/** Host-local request used by queue extensions to enumerate live peer sessions. */\nexport interface FabricPeerCardsRequestV1 {\n version: 1;\n context: ExtensionContext;\n claim: () => boolean;\n respond: (result: FabricPeerCardsResultV1) => void;\n}\n\nexport const readFabricPeerCardsRequestV1 = (\n value: unknown,\n): FabricPeerCardsRequestV1 | undefined => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n if (\n record.version !== 1 ||\n typeof record.context !== \"object\" ||\n record.context === null ||\n typeof record.claim !== \"function\" ||\n typeof record.respond !== \"function\"\n ) {\n return undefined;\n }\n return value as FabricPeerCardsRequestV1;\n};\n\nexport interface FabricPeerSettleProgressV1 {\n waiting: Array<{ label: string; status: \"idle\" | \"running\" }>;\n}\n\nexport type FabricPeerAwaitSettleResultV1 =\n | { ok: true }\n | { ok: false; error: string };\n\n/**\n * Host-local request used by queue extensions to hold dispatch until peer\n * sessions settle. A peer counts as settled once it has been quiet\n * (status-wide) for settledForMs; peers that vanish from the mesh count as\n * settled since they can no longer conflict. Selector matches a peer label\n * (case-insensitive) or exact participant id; omitted waits on all peers.\n */\nexport interface FabricPeerAwaitSettleRequestV1 {\n version: 1;\n context: ExtensionContext;\n selector?: string;\n settledForMs?: number;\n signal?: AbortSignal;\n update?: (progress: FabricPeerSettleProgressV1) => void;\n claim: () => boolean;\n respond: (result: FabricPeerAwaitSettleResultV1) => void;\n}\n\nexport const readFabricPeerAwaitSettleRequestV1 = (\n value: unknown,\n): FabricPeerAwaitSettleRequestV1 | undefined => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n const signal = record.signal as AbortSignal | undefined;\n if (\n record.version !== 1 ||\n typeof record.context !== \"object\" ||\n record.context === null ||\n typeof record.claim !== \"function\" ||\n typeof record.respond !== \"function\" ||\n (record.selector !== undefined && typeof record.selector !== \"string\") ||\n (record.settledForMs !== undefined && typeof record.settledForMs !== \"number\") ||\n (signal !== undefined && typeof signal.aborted !== \"boolean\") ||\n (record.update !== undefined && typeof record.update !== \"function\")\n ) {\n return undefined;\n }\n return value as FabricPeerAwaitSettleRequestV1;\n};\n\n/** Identifies host-side tool lifecycle events replayed for a nested Fabric call. */\nexport const FABRIC_NESTED_TOOL_CALL_ID_PREFIX = \"fabric_\";\n\n/** Discriminant for the transient details envelope on a proxied provider result. */\nexport const FABRIC_TOOL_RESULT_PROXY_KIND = \"pi-fabric.tool-result-proxy.v1\";\n\n/**\n * Host-only middleware details for non-Pi Fabric providers. `result` is the\n * exact value before maxNestedResultChars is enforced and is not persisted as\n * a separate Pi tool-result message.\n */\nexport interface FabricToolResultProxyDetailsV1 {\n kind: typeof FABRIC_TOOL_RESULT_PROXY_KIND;\n ref: string;\n result: unknown;\n}\n\nexport const readFabricToolResultProxyDetailsV1 = (\n value: unknown,\n): FabricToolResultProxyDetailsV1 | undefined => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n if (\n record.kind !== FABRIC_TOOL_RESULT_PROXY_KIND ||\n typeof record.ref !== \"string\" ||\n !Object.prototype.hasOwnProperty.call(record, \"result\")\n ) {\n return undefined;\n }\n return record as unknown as FabricToolResultProxyDetailsV1;\n};\n\nexport type FabricRisk = \"read\" | \"write\" | \"execute\" | \"network\" | \"agent\";\nexport type FabricEffectKind = \"none\" | \"scoped\" | \"transactional\" | \"emission\";\nexport type FabricEffectOrdering = \"commutative\" | \"ordered\" | \"unknown\";\n\nexport interface FabricActionEffect {\n kind: FabricEffectKind;\n resources?: string[];\n ordering?: FabricEffectOrdering;\n}\n\n/** MCP tool annotations (Model Context Protocol ToolAnnotations), cached when a runtime surfaces them. */\nexport interface FabricToolAnnotations {\n readOnlyHint?: boolean;\n idempotentHint?: boolean;\n destructiveHint?: boolean;\n openWorldHint?: boolean;\n}\nexport type FabricActivityEntityKind =\n | \"agent\"\n | \"actor\"\n | \"tool\"\n | \"extension\"\n | \"mcp\"\n | \"mesh\"\n | \"task\"\n | \"custom\";\n\nexport type FabricInvocationActivityUpdate =\n | { type: \"progress\"; message: string }\n | { type: \"entity\"; id: string; kind: FabricActivityEntityKind; name?: string }\n | { type: \"metrics\"; tokens?: number; toolCalls?: number; cost?: number };\n\nexport interface FabricMediaBlock {\n type: \"image\";\n data: string;\n mimeType: string;\n}\n\nexport interface FabricActionDescriptor {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n outputSchema?: Record<string, unknown>;\n risk: FabricRisk;\n namespace?: string;\n effect?: FabricActionEffect;\n annotations?: FabricToolAnnotations;\n}\n\nexport interface FabricCapabilityActionHead {\n key: string;\n parentKey: string;\n ref: string;\n name: string;\n description: string;\n descriptorHash: string;\n risk: FabricRisk;\n namespace?: string;\n effect?: FabricActionEffect;\n}\n\nexport interface FabricCapabilityProviderHead {\n key: string;\n parentKey: string;\n name: string;\n description: string;\n descriptorHash: string;\n actions: FabricCapabilityActionHead[];\n}\n\nexport interface FabricCapabilityBindingView {\n ref: string;\n provider: string;\n providerBindingId: string;\n generation: number;\n descriptorHash: string;\n}\n\nexport interface FabricCommittedCapabilityView {\n id: string;\n /** Runtime-local digest including provider binding generations. */\n digest: string;\n /** Portable digest of exact refs and descriptor semantics across runtimes. */\n semanticDigest: string;\n bindings: Record<string, FabricCapabilityBindingView>;\n}\n\nexport interface FabricCapabilityResolution {\n satisfied: boolean;\n missing: string[];\n optionalMissing: string[];\n view?: FabricCommittedCapabilityView;\n}\n\nexport interface FabricCapabilityCatalog {\n kind: \"pi-fabric.capability-catalog\";\n version: 1;\n root: {\n key: \"capability:fabric\";\n name: \"Fabric capabilities\";\n description: string;\n descriptorHash: string;\n };\n providers: FabricCapabilityProviderHead[];\n totalActions: number;\n indexedActions: number;\n complete: boolean;\n reasons: string[];\n}\n\nexport interface FabricProviderListRequest {\n namespace?: string;\n query?: string;\n limit?: number;\n}\n\n/** One named action whose arguments should be typed in guest declarations. */\nexport interface FabricNamedActionTypeSource {\n name: string;\n inputSchema: Record<string, unknown>;\n}\n\n/** One MCP server plus the tools to type for `mcp.<server>.*` guest calls. */\nexport interface FabricMcpServerTypeSource {\n server: string;\n tools: FabricNamedActionTypeSource[];\n}\n\nexport type {\n FabricKernel,\n FabricKernelRuntime,\n FabricHostCall,\n FabricSandboxOptions,\n FabricSandboxResult,\n FabricSandboxTerminationReason,\n} from \"./runtime/kernel.js\";\nexport type { FabricPythonRuntime } from \"./config.js\";\n\n/**\n * Live descriptor snapshot the registry hands to the guest declaration\n * builder so dynamic surfaces (mcp, extensions) get argument checking before\n * the sandbox runs. Empty/absent sections keep the loose static declarations.\n */\nexport interface FabricGuestTypeSources {\n mcpServers?: FabricMcpServerTypeSource[];\n extensionTools?: FabricNamedActionTypeSource[];\n}\n\n/**\n * Pre-rendered `declare const` blocks replacing the loose mcp/extensions\n * declaration lines. Values are full replacement text (helpers + declare).\n */\nexport interface FabricDynamicGuestDeclarations {\n mcp?: string;\n extensions?: string;\n}\n\nexport interface FabricInvocationContext {\n cwd: string;\n signal: AbortSignal | undefined;\n parentToolCallId: string;\n nestedToolCallId: string;\n extensionContext: ExtensionContext;\n update(message: string): void;\n activity?(update: FabricInvocationActivityUpdate): void;\n /** Host-supplied inside fabric_exec so agents.handoff schedules the outer-call boundary. */\n deferHandoff?(args: Record<string, unknown>): Record<string, unknown>;\n // Out-of-band image content blocks a provider (currently only pi.read of an\n // image file) wants attached to the call audit, so the single-call render can\n // re-attach them to the fabric_exec result content for pi core's kitty image\n // preview. Bypasses the result char bound that would truncate the base64.\n // `note` is the read tool's own text output (e.g. \"Read image file [image/png]\"),\n // captured after any tool_result patch so a handoff that strips pi's\n // non-vision note has run; used as the single-call body + content text so the\n // preview shows the clean note instead of the swapped description.\n attachMedia?(blocks: FabricMediaBlock[], note?: string): void;\n // Providers call this after mutable tool_call middleware has run so live and\n // durable audit surfaces reflect the arguments actually passed to the tool.\n updateArguments?(args: Record<string, unknown>): void;\n // Ephemeral renderer-only metadata. It is exposed to live Fabric previews but\n // never projected into the durable execution trace.\n attachPreview?(preview: unknown): void;\n capabilityView?: FabricCommittedCapabilityView;\n /** Advisory for ordinary calls; strict components reject concurrent conflicting effects. */\n effectPolicy?: \"advisory\" | \"strict\";\n}\n\nexport interface FabricScopedProviderResult {\n value: unknown;\n dispose(): void | Promise<void>;\n}\n\nexport interface FabricProvider {\n name: string;\n description: string;\n list(\n request: FabricProviderListRequest,\n context: FabricInvocationContext,\n ): Promise<FabricActionDescriptor[]>;\n describe(\n actionName: string,\n context: FabricInvocationContext,\n ): Promise<FabricActionDescriptor | undefined>;\n prepareArguments?(\n actionName: string,\n args: Record<string, unknown>,\n context: FabricInvocationContext,\n ): Record<string, unknown> | Promise<Record<string, unknown>>;\n invoke(\n actionName: string,\n args: Record<string, unknown>,\n context: FabricInvocationContext,\n ): Promise<unknown>;\n acquire?(\n actionName: string,\n args: Record<string, unknown>,\n context: FabricInvocationContext,\n ): Promise<FabricScopedProviderResult>;\n invocationEnded?(parentToolCallId: string): Promise<void>;\n subscribeCatalog?(listener: () => void): () => void;\n close?(): Promise<void>;\n}\n\nexport interface FabricProviderRegistration {\n version: 1;\n provider: FabricProvider;\n overwrite?: boolean;\n}\n\nexport interface FabricProviderDiscovery {\n version: 1;\n register(provider: FabricProvider, options?: { overwrite?: boolean }): void;\n}\n\nexport type {\n ComponentChangeRequest as FabricComponentChangeRequest,\n ComponentChangePlan as FabricComponentChangePlan,\n} from \"./components/control.js\";\n\nexport type {\n FabricCapabilityRequirement,\n FabricComponentChildOptions,\n FabricComponentContext,\n FabricComponentDefinition,\n FabricComponentDiscovery,\n FabricComponentDisposer,\n FabricComponentEffect,\n FabricComponentEffectConflict,\n FabricComponentEffectInfo,\n FabricComponentEffectOptions,\n FabricComponentEffectRegistration,\n FabricComponentEntry,\n FabricComponentGraph,\n FabricComponentGuarantee,\n FabricComponentHandle,\n FabricComponentInfo,\n FabricComponentProviderLease,\n FabricModelGuidance,\n FabricModelGuidanceInfo,\n FabricModelGuidancePlacement,\n FabricModelGuidanceTarget,\n FabricComponentProvision,\n FabricComponentRegistration,\n FabricComponentState,\n FabricComponentStopOptions,\n} from \"./components/types.js\";\n\nexport {\n FABRIC_EXECUTION_GUIDANCE_SLOT,\n MAX_FABRIC_MODEL_GUIDANCE_CONTENT_CHARS,\n MAX_FABRIC_MODEL_GUIDANCE_PER_COMPONENT,\n MAX_FABRIC_MODEL_GUIDANCE_REGISTRATIONS,\n MAX_FABRIC_MODEL_GUIDANCE_SNAPSHOT_CHARS,\n MAX_FABRIC_MODEL_GUIDANCE_TOTAL_CHARS,\n} from \"./components/model-guidance.js\";\n"],
|
|
5
|
+
"mappings": ";AAGO,IAAM,yBAAyB,OAAO,IAAI,8BAA8B;AAUxE,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,kCAAkC;AACxC,IAAM,kCAAkC;AACxC,IAAM,+BAA+B;AAcrC,IAAM,6BAA6B,CACxC,UACuC;AACvC,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,SAAS;AACf,MACE,OAAO,YAAY,KACnB,OAAO,OAAO,YAAY,YAC1B,OAAO,YAAY,QACnB,OAAO,OAAO,UAAU,cACxB,OAAO,OAAO,YAAY,YAC1B;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;AA2BvC,IAAM,+BAA+B,CAC1C,UACyC;AACzC,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,SAAS;AACf,MACE,OAAO,YAAY,KACnB,OAAO,OAAO,YAAY,YAC1B,OAAO,YAAY,QACnB,OAAO,OAAO,UAAU,cACxB,OAAO,OAAO,YAAY,YAC1B;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AA4BO,IAAM,qCAAqC,CAChD,UAC+C;AAC/C,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,SAAS;AACf,QAAM,SAAS,OAAO;AACtB,MACE,OAAO,YAAY,KACnB,OAAO,OAAO,YAAY,YAC1B,OAAO,YAAY,QACnB,OAAO,OAAO,UAAU,cACxB,OAAO,OAAO,YAAY,cACzB,OAAO,aAAa,UAAa,OAAO,OAAO,aAAa,YAC5D,OAAO,iBAAiB,UAAa,OAAO,OAAO,iBAAiB,YACpE,WAAW,UAAa,OAAO,OAAO,YAAY,aAClD,OAAO,WAAW,UAAa,OAAO,OAAO,WAAW,YACzD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,IAAM,oCAAoC;AAG1C,IAAM,gCAAgC;AAatC,IAAM,qCAAqC,CAChD,UAC+C;AAC/C,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,SAAS;AACf,MACE,OAAO,SAAS,iCAChB,OAAO,OAAO,QAAQ,YACtB,CAAC,OAAO,UAAU,eAAe,KAAK,QAAQ,QAAQ,GACtD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
ActionRegistry,
|
|
3
3
|
NESTED_TOOL_CALL_ID_PREFIX,
|
|
4
4
|
fabricActionListLimit
|
|
5
|
-
} from "../chunks/chunk-
|
|
5
|
+
} from "../chunks/chunk-DLLIRB63.js";
|
|
6
6
|
import "../chunks/chunk-LMAVZN7J.js";
|
|
7
7
|
import "../chunks/chunk-7TB7NXSL.js";
|
|
8
8
|
import "../chunks/chunk-PSNXUZMY.js";
|
|
9
|
-
import "../chunks/chunk-
|
|
9
|
+
import "../chunks/chunk-IJL3QK3J.js";
|
|
10
10
|
import "../chunks/chunk-D5WKZONW.js";
|
|
11
11
|
import "../chunks/chunk-G4LADAYY.js";
|
|
12
12
|
import "../chunks/chunk-YU62DDKK.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type FabricBashMiddlewareV1 } from "../protocol.js";
|
|
2
|
+
/** Invalid opt-ins fail closed: never silently run without an extension's filters. */
|
|
3
|
+
export declare const readFabricBashMiddleware: (definition: object | undefined) => FabricBashMiddlewareV1 | undefined;
|
|
4
|
+
//# sourceMappingURL=shell-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-middleware.d.ts","sourceRoot":"","sources":["../../src/core/shell-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAErF,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,GAAG,SAAS,KAAG,sBAAsB,GAAG,SAkBlG,CAAC"}
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
expandSkillDirMarkersForRead,
|
|
34
34
|
resolveFabricIdentity,
|
|
35
35
|
runFabricHandoffAtBoundary
|
|
36
|
-
} from "./chunks/chunk-
|
|
36
|
+
} from "./chunks/chunk-CEXO6ELQ.js";
|
|
37
37
|
import {
|
|
38
38
|
AgentTranscriptReader,
|
|
39
39
|
MAX_WRITE_DIFF_BYTES,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
ActionRegistry,
|
|
47
47
|
fabricActionListLimit,
|
|
48
48
|
repairActionName
|
|
49
|
-
} from "./chunks/chunk-
|
|
49
|
+
} from "./chunks/chunk-DLLIRB63.js";
|
|
50
50
|
import {
|
|
51
51
|
formatFabricEffectConflict
|
|
52
52
|
} from "./chunks/chunk-LMAVZN7J.js";
|
|
@@ -93,11 +93,12 @@ import {
|
|
|
93
93
|
validationMessage
|
|
94
94
|
} from "./chunks/chunk-PSNXUZMY.js";
|
|
95
95
|
import {
|
|
96
|
+
FABRIC_BASH_MIDDLEWARE,
|
|
96
97
|
FABRIC_COMPONENT_DISCOVER_EVENT,
|
|
97
98
|
FABRIC_PROVIDER_DISCOVER_EVENT,
|
|
98
99
|
FABRIC_TOOL_RESULT_PROXY_KIND,
|
|
99
100
|
readFabricToolResultProxyDetailsV1
|
|
100
|
-
} from "./chunks/chunk-
|
|
101
|
+
} from "./chunks/chunk-IJL3QK3J.js";
|
|
101
102
|
import {
|
|
102
103
|
sanitizeFabricMediaText,
|
|
103
104
|
sanitizeFabricMediaValue
|
|
@@ -7240,6 +7241,32 @@ var tryExecuteGitWorktreeAdd = async (args, sessionCwd) => {
|
|
|
7240
7241
|
};
|
|
7241
7242
|
};
|
|
7242
7243
|
|
|
7244
|
+
// src/core/shell-middleware.ts
|
|
7245
|
+
var readFabricBashMiddleware = (definition) => {
|
|
7246
|
+
if (!definition || !(FABRIC_BASH_MIDDLEWARE in definition)) return void 0;
|
|
7247
|
+
const value = Reflect.get(definition, FABRIC_BASH_MIDDLEWARE);
|
|
7248
|
+
const invalid = () => {
|
|
7249
|
+
throw new Error("Invalid Fabric bash middleware v1; refusing to bypass shell protection");
|
|
7250
|
+
};
|
|
7251
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return invalid();
|
|
7252
|
+
const record = value;
|
|
7253
|
+
if (record.version !== 1 || typeof record.wrapOperations !== "function") return invalid();
|
|
7254
|
+
if (record.options !== void 0) {
|
|
7255
|
+
if (!record.options || typeof record.options !== "object" || Array.isArray(record.options)) return invalid();
|
|
7256
|
+
const options = record.options;
|
|
7257
|
+
const fields = {
|
|
7258
|
+
commandPrefix: "string",
|
|
7259
|
+
shellPath: "string",
|
|
7260
|
+
exposeSessionEnvironment: "boolean",
|
|
7261
|
+
spawnHook: "function"
|
|
7262
|
+
};
|
|
7263
|
+
for (const [key, option] of Object.entries(options)) {
|
|
7264
|
+
if (!Object.hasOwn(fields, key) || option !== void 0 && typeof option !== fields[key]) return invalid();
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
return value;
|
|
7268
|
+
};
|
|
7269
|
+
|
|
7243
7270
|
// src/providers/pi-bash-cwd.ts
|
|
7244
7271
|
import { accessSync, constants, statSync } from "node:fs";
|
|
7245
7272
|
import path7 from "node:path";
|
|
@@ -7588,17 +7615,28 @@ var PiToolsProvider = class {
|
|
|
7588
7615
|
const name = actionName;
|
|
7589
7616
|
if (this.#allowedTools && !this.#allowedTools.has(name)) return void 0;
|
|
7590
7617
|
const override = await this.#capturedTools?.describe(name, _context);
|
|
7591
|
-
if (override)
|
|
7618
|
+
if (override) {
|
|
7619
|
+
if (this.#bashMiddleware(name)) {
|
|
7620
|
+
return {
|
|
7621
|
+
...override,
|
|
7622
|
+
description: `${override.description} Shell execution and background jobs are managed by Fabric with the extension's middleware.`,
|
|
7623
|
+
inputSchema: this.#descriptor(name, this.#tools[name]).inputSchema,
|
|
7624
|
+
namespace: "extension-middleware"
|
|
7625
|
+
};
|
|
7626
|
+
}
|
|
7627
|
+
return { ...override, namespace: "extension-override" };
|
|
7628
|
+
}
|
|
7592
7629
|
const tool = this.#tools[name];
|
|
7593
7630
|
if (!tool || this.#requireCapturedOverrides) return void 0;
|
|
7594
7631
|
return this.#descriptor(name, tool);
|
|
7595
7632
|
}
|
|
7596
7633
|
prepareArguments(actionName, args) {
|
|
7597
7634
|
this.#assertAllowed(actionName);
|
|
7598
|
-
const
|
|
7635
|
+
const middleware = this.#bashMiddleware(actionName);
|
|
7636
|
+
const definition = (middleware ? void 0 : this.#catalog?.get(actionName)?.definition) ?? this.#tools[actionName];
|
|
7599
7637
|
const properties = definition?.parameters?.properties ?? {};
|
|
7600
7638
|
args = normalizePiArguments(actionName, args, Object.keys(properties));
|
|
7601
|
-
if (this.#catalog?.get(actionName)) {
|
|
7639
|
+
if (this.#catalog?.get(actionName) && !middleware) {
|
|
7602
7640
|
return this.#capturedTools.prepareArguments(actionName, args);
|
|
7603
7641
|
}
|
|
7604
7642
|
const tool = this.#tools[actionName];
|
|
@@ -7669,15 +7707,26 @@ var PiToolsProvider = class {
|
|
|
7669
7707
|
const cwd = args[PI_BASH_CWD_KEY];
|
|
7670
7708
|
return isPiShellToolName(name) && typeof cwd === "string" ? { ...context, cwd } : context;
|
|
7671
7709
|
}
|
|
7710
|
+
#bashMiddleware(name) {
|
|
7711
|
+
if (name !== "bash" || this.#requireCapturedOverrides) return void 0;
|
|
7712
|
+
return readFabricBashMiddleware(this.#catalog?.get(name)?.definition);
|
|
7713
|
+
}
|
|
7672
7714
|
#shellHangMs() {
|
|
7673
7715
|
const value = this.#getShellHangMs?.() ?? DEFAULT_SHELL_HANG_MS;
|
|
7674
7716
|
return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : DEFAULT_SHELL_HANG_MS;
|
|
7675
7717
|
}
|
|
7676
|
-
#trackedShellDefinition(name, args, job) {
|
|
7718
|
+
#trackedShellDefinition(name, args, job, middleware) {
|
|
7677
7719
|
const cwd = typeof args[PI_BASH_CWD_KEY] === "string" ? args[PI_BASH_CWD_KEY] : this.#cwd;
|
|
7678
7720
|
if (name === "bash") {
|
|
7721
|
+
const options = middleware?.options;
|
|
7722
|
+
const local = createLocalBashOperations(options?.shellPath !== void 0 ? { shellPath: options.shellPath } : void 0);
|
|
7723
|
+
const operations = middleware ? middleware.wrapOperations(local) : local;
|
|
7724
|
+
if (!operations || typeof operations.exec !== "function") {
|
|
7725
|
+
throw new Error("Invalid Fabric bash middleware operations; refusing to bypass shell protection");
|
|
7726
|
+
}
|
|
7679
7727
|
return createBashToolDefinition2(cwd, {
|
|
7680
|
-
|
|
7728
|
+
...options,
|
|
7729
|
+
operations: trackShellOperations(operations, job, "bash")
|
|
7681
7730
|
});
|
|
7682
7731
|
}
|
|
7683
7732
|
const create = Reflect.get(PiCodingAgent2, "createPowerShellToolDefinition");
|
|
@@ -7689,7 +7738,7 @@ var PiToolsProvider = class {
|
|
|
7689
7738
|
operations: trackShellOperations(operationsFactory(), job, "powershell")
|
|
7690
7739
|
});
|
|
7691
7740
|
}
|
|
7692
|
-
async #runExecute(name, tool, args, context, onUpdate) {
|
|
7741
|
+
async #runExecute(name, tool, args, context, onUpdate, middleware) {
|
|
7693
7742
|
if (!isPiShellToolName(name) || this.#requireCapturedOverrides) {
|
|
7694
7743
|
return await runAbortable(
|
|
7695
7744
|
context.signal,
|
|
@@ -7702,15 +7751,21 @@ var PiToolsProvider = class {
|
|
|
7702
7751
|
)
|
|
7703
7752
|
);
|
|
7704
7753
|
}
|
|
7705
|
-
return this.#executeHungShell(name, args, context, onUpdate);
|
|
7754
|
+
return this.#executeHungShell(name, args, context, onUpdate, middleware);
|
|
7706
7755
|
}
|
|
7707
|
-
async #executeHungShell(name, args, context, onUpdate) {
|
|
7756
|
+
async #executeHungShell(name, args, context, onUpdate, middleware) {
|
|
7708
7757
|
const command = typeof args.command === "string" ? args.command : "";
|
|
7709
7758
|
const background = args.background === true;
|
|
7710
7759
|
const executeArgs = background || "background" in args ? (({ background: _ignored, ...rest }) => rest)(args) : args;
|
|
7711
7760
|
const job = this.#shellJobs.begin(name, command);
|
|
7761
|
+
let tool;
|
|
7762
|
+
try {
|
|
7763
|
+
tool = this.#trackedShellDefinition(name, executeArgs, job, middleware);
|
|
7764
|
+
} catch (error) {
|
|
7765
|
+
await job.finish(null);
|
|
7766
|
+
throw error;
|
|
7767
|
+
}
|
|
7712
7768
|
void job.readPid();
|
|
7713
|
-
const tool = this.#trackedShellDefinition(name, executeArgs, job);
|
|
7714
7769
|
let spilled = false;
|
|
7715
7770
|
const outcome = await raceShellHang({
|
|
7716
7771
|
hangMs: background ? 0 : this.#shellHangMs(),
|
|
@@ -7762,14 +7817,15 @@ var PiToolsProvider = class {
|
|
|
7762
7817
|
const name = actionName;
|
|
7763
7818
|
this.#assertAllowed(name);
|
|
7764
7819
|
if (!this.#requireCapturedOverrides && !this.#tools[name]) throw new Error(`Unknown Pi tool: ${actionName}`);
|
|
7765
|
-
if (name === "bash" && !this.#requireCapturedOverrides) {
|
|
7820
|
+
if (name === "bash" && !this.#requireCapturedOverrides && !this.#catalog?.get(name)) {
|
|
7766
7821
|
const intercepted = await tryExecuteGitWorktreeAdd(args, this.#cwd);
|
|
7767
7822
|
if (intercepted) {
|
|
7768
7823
|
this.#attachPreview(name, intercepted, args, context);
|
|
7769
7824
|
return this.#normalizeResult(name, intercepted, args);
|
|
7770
7825
|
}
|
|
7771
7826
|
}
|
|
7772
|
-
|
|
7827
|
+
const middleware = this.#bashMiddleware(name);
|
|
7828
|
+
if (this.#catalog?.get(name) && !middleware) {
|
|
7773
7829
|
const result = await this.#capturedTools.invoke(name, args, context);
|
|
7774
7830
|
this.#attachReadMedia(name, result, context);
|
|
7775
7831
|
this.#attachReadNote(name, result, context);
|
|
@@ -7784,7 +7840,8 @@ var PiToolsProvider = class {
|
|
|
7784
7840
|
tool,
|
|
7785
7841
|
args,
|
|
7786
7842
|
context,
|
|
7787
|
-
(partialResult) => this.#attachPartialPreview(name, partialResult, args, context)
|
|
7843
|
+
(partialResult) => this.#attachPartialPreview(name, partialResult, args, context),
|
|
7844
|
+
middleware
|
|
7788
7845
|
).catch((error) => {
|
|
7789
7846
|
throwIfAborted(context.signal);
|
|
7790
7847
|
throw isPiShellToolName(name) ? classifyPiBashError(error) : error;
|
|
@@ -7794,7 +7851,7 @@ var PiToolsProvider = class {
|
|
|
7794
7851
|
this.#attachPreview(name, result, args, context);
|
|
7795
7852
|
return this.#normalizeResult(name, result, args);
|
|
7796
7853
|
}
|
|
7797
|
-
return this.#invokeWithEvents(name, tool, args, context, runner);
|
|
7854
|
+
return this.#invokeWithEvents(name, tool, args, context, runner, middleware);
|
|
7798
7855
|
}
|
|
7799
7856
|
// Replay the agent-core tool-execution lifecycle for a nested pi.* call, so
|
|
7800
7857
|
// extensions that hook tool_call / tool_result / tool_execution_* see pi
|
|
@@ -7804,7 +7861,7 @@ var PiToolsProvider = class {
|
|
|
7804
7861
|
// tools. tool_result patches (content/details/isError) are applied, so
|
|
7805
7862
|
// extensions like pi-vision-handoff can replace image blocks with text
|
|
7806
7863
|
// descriptions before the result returns to the sandbox.
|
|
7807
|
-
async #invokeWithEvents(name, tool, args, context, runner) {
|
|
7864
|
+
async #invokeWithEvents(name, tool, args, context, runner, middleware) {
|
|
7808
7865
|
const toolCallId = context.nestedToolCallId;
|
|
7809
7866
|
await runAbortable(context.signal, () => runner.emit({
|
|
7810
7867
|
type: "tool_execution_start",
|
|
@@ -7845,7 +7902,8 @@ var PiToolsProvider = class {
|
|
|
7845
7902
|
partialResult
|
|
7846
7903
|
}))
|
|
7847
7904
|
).catch(() => void 0);
|
|
7848
|
-
}
|
|
7905
|
+
},
|
|
7906
|
+
middleware
|
|
7849
7907
|
);
|
|
7850
7908
|
} catch (error) {
|
|
7851
7909
|
thrown = isPiShellToolName(name) && executionStarted ? classifyPiBashError(error) : error;
|