@petriflow/gate 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -288,6 +288,7 @@ async function composedToolCall(getNets, getStates, event, ctx) {
288
288
  }
289
289
 
290
290
  // src/manager.ts
291
+ var import_engine4 = require("@petriflow/engine");
291
292
  function createGateManager(input, opts) {
292
293
  const manager = Array.isArray(input) ? createArrayManager(input) : createRegistryManager(input);
293
294
  if (opts) {
@@ -303,6 +304,40 @@ function createGateManager(input, opts) {
303
304
  }
304
305
  return manager;
305
306
  }
307
+ function normalizeEntries(entries) {
308
+ if (entries.length === 0) return [];
309
+ if (typeof entries[0] === "string") {
310
+ return entries.map((toolName) => ({ toolName, isError: false }));
311
+ }
312
+ return entries;
313
+ }
314
+ function replayNets(nets, states, entries) {
315
+ for (const entry of entries) {
316
+ if (entry.isError) continue;
317
+ for (let i = 0; i < nets.length; i++) {
318
+ const net = nets[i];
319
+ const state = states[i];
320
+ const resolved = resolveTool(net, { toolName: entry.toolName, input: entry.input ?? {} });
321
+ if (net.freeTools.includes(resolved)) continue;
322
+ const enabled = getEnabledToolTransitions(net, state.marking);
323
+ const matching = enabled.filter((t) => t.tools.includes(resolved));
324
+ if (matching.length === 0) continue;
325
+ const transition = matching[0];
326
+ if ((0, import_engine4.canFire)(state.marking, transition)) {
327
+ state.marking = (0, import_engine4.fire)(state.marking, transition);
328
+ if (transition.deferred && net.onDeferredResult) {
329
+ net.onDeferredResult(
330
+ { toolCallId: `replay-${i}`, input: entry.input ?? {}, isError: false },
331
+ resolved,
332
+ transition,
333
+ state
334
+ );
335
+ }
336
+ state.marking = autoAdvance(net, state.marking);
337
+ }
338
+ }
339
+ }
340
+ }
306
341
  function createArrayManager(nets) {
307
342
  const states = nets.map(
308
343
  (net) => createGateState(autoAdvance(net, { ...net.initialMarking }))
@@ -318,6 +353,9 @@ function createArrayManager(nets) {
318
353
  handleToolResult(event, nets[i], states[i]);
319
354
  }
320
355
  },
356
+ replay(entries) {
357
+ replayNets(nets, states, normalizeEntries(entries));
358
+ },
321
359
  addNet() {
322
360
  return { ok: false, message: "Static composition does not support dynamic nets" };
323
361
  },
@@ -359,6 +397,11 @@ function createRegistryManager(config) {
359
397
  handleToolResult(event, net, state);
360
398
  }
361
399
  },
400
+ replay(entries) {
401
+ const activeNets = getActiveNets();
402
+ const activeStates = getActiveStates();
403
+ replayNets(activeNets, activeStates, normalizeEntries(entries));
404
+ },
362
405
  addNet(name) {
363
406
  if (!registry.has(name)) {
364
407
  return { ok: false, message: `Unknown net '${name}'. Available: ${[...registry.keys()].join(", ")}` };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/format.ts","../src/advance.ts","../src/gate.ts","../src/compose.ts","../src/manager.ts"],"sourcesContent":["// Types\nexport { defineSkillNet } from \"./types.js\";\nexport type { SkillNet, GatedTransition, ToolEvent, RuleMetadata } from \"./types.js\";\n\n// Block reason formatting\nexport { formatBlockReason } from \"./format.js\";\n\n// Generic event types\nexport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\n\n// Auto-advance\nexport { autoAdvance } from \"./advance.js\";\n\n// Single-net gating\nexport {\n handleToolCall,\n handleToolResult,\n formatMarking,\n getEnabledToolTransitions,\n createGateState,\n resolveTool,\n} from \"./gate.js\";\nexport type { GateState } from \"./gate.js\";\n\n// Multi-net composition\nexport { classifyNets, composedToolCall } from \"./compose.js\";\nexport type { ComposeConfig, NetVerdict } from \"./compose.js\";\n\n// Manager\nexport { createGateManager } from \"./manager.js\";\nexport type { GateManager, GateManagerOptions } from \"./manager.js\";\n","import type { Marking } from \"@petriflow/engine\";\n\n/** Structured metadata for generating user-facing block messages */\nexport type RuleMetadata =\n | { kind: \"sequence\"; prerequisite: string; dependent: string }\n | { kind: \"approval\"; tool: string }\n | { kind: \"block\"; tool: string }\n | { kind: \"limit\"; tool: string; limit: number; scope: \"session\" | string };\n\n/** A transition that optionally gates tool access */\nexport type GatedTransition<Place extends string> = {\n name: string;\n type: \"auto\" | \"manual\";\n inputs: Place[];\n outputs: Place[];\n guard?: string | null;\n tools?: string[];\n /**\n * When true, the transition allows the tool call immediately but\n * only fires (consumes/produces tokens) when the tool_result\n * comes back successfully (isError === false).\n * Use this for transitions where the tool must succeed before\n * the net advances (e.g. backup must succeed before delete unlocks).\n */\n deferred?: boolean;\n};\n\n/** Minimal tool event shape for toolMapper */\nexport type ToolEvent = { toolName: string; input: Record<string, unknown> };\n\n/** A Petri net that gates a skill's tool access */\nexport type SkillNet<Place extends string> = {\n name: string;\n places: Place[];\n transitions: GatedTransition<Place>[];\n initialMarking: Marking<Place>;\n terminalPlaces: Place[];\n freeTools: string[];\n /**\n * Maps a tool call to a virtual tool name before gating.\n * Use this to split one tool (e.g. \"bash\") into multiple gated\n * variants (e.g. \"bash\", \"git-commit\", \"git-push\") based on input.\n * If not provided, event.toolName is used as-is.\n */\n toolMapper?: (event: ToolEvent) => string;\n /**\n * Additional validation before a gated tool call is allowed.\n * Called after the net confirms a matching transition exists.\n * Return { block, reason } to reject, or void to allow.\n * Use this for domain-specific checks (e.g. path coverage).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n validateToolCall?(\n event: ToolEvent,\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): { block: true; reason: string } | void;\n /**\n * Called when a deferred transition's tool_result arrives.\n * Use this to record metadata (e.g. backed-up paths).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n onDeferredResult?(\n event: { toolCallId: string; input: Record<string, unknown>; isError: boolean },\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): void;\n /** Structured rule metadata for generating constraint-stating block messages */\n ruleMetadata?: RuleMetadata;\n};\n\n/** Type-safe helper — validates places/marking at the type level */\nexport function defineSkillNet<Place extends string>(\n net: SkillNet<Place>,\n): SkillNet<Place> {\n return net;\n}\n","import type { SkillNet } from \"./types.js\";\n\n/**\n * Generate a user-facing block reason from a net's rule metadata.\n *\n * With metadata (from the rules compiler), returns a constraint-stating message:\n * - sequence: \"deploy requires a successful call to test first.\"\n * - limit: \"deploy has reached its limit of 3 calls per session.\"\n * - block: \"rm is blocked and cannot be called.\"\n * - approval: \"deploy requires human approval.\"\n *\n * Without metadata (hand-built nets), falls back to a generic message.\n */\nexport function formatBlockReason(\n net: SkillNet<string>,\n resolvedTool: string,\n): string {\n const meta = net.ruleMetadata;\n\n if (meta) {\n switch (meta.kind) {\n case \"sequence\":\n return `${meta.dependent} requires a successful call to ${meta.prerequisite} first.`;\n case \"limit\":\n return meta.scope === \"session\"\n ? `${meta.tool} has reached its limit of ${meta.limit} calls per session.`\n : `${meta.tool} has reached its limit of ${meta.limit} calls per ${meta.scope}.`;\n case \"block\":\n return `${meta.tool} is blocked and cannot be called.`;\n case \"approval\":\n return `${meta.tool} requires human approval.`;\n }\n }\n\n return `Tool '${resolvedTool}' is not available in the current state.`;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\n\n/** A structural transition: type=auto, no tools property */\nfunction isStructural<P extends string>(t: GatedTransition<P>): boolean {\n return t.type === \"auto\" && (t.tools === undefined || t.tools.length === 0);\n}\n\n/**\n * Check if two transitions compete for the same input token.\n * Two transitions conflict if they share an input place and the\n * marking doesn't have enough tokens for both.\n */\nfunction hasInputConflict<P extends string>(\n a: GatedTransition<P>,\n b: GatedTransition<P>,\n marking: Marking<P>,\n): boolean {\n for (const place of a.inputs) {\n if (b.inputs.includes(place)) {\n // Count how many tokens each needs from this place\n const aNeeds = a.inputs.filter((p) => p === place).length;\n const bNeeds = b.inputs.filter((p) => p === place).length;\n if ((marking[place] ?? 0) < aNeeds + bNeeds) return true;\n }\n }\n return false;\n}\n\n/**\n * Auto-advance: fire all enabled structural transitions (type=auto,\n * no tools) in a loop until quiescent.\n *\n * When multiple structural transitions compete for the same input\n * token, none of them fire (avoids ambiguous choices).\n */\nexport function autoAdvance<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): Marking<P> {\n let current = { ...marking };\n\n for (;;) {\n const structural = net.transitions.filter(\n (t) => isStructural(t) && canFire(current, t),\n );\n if (structural.length === 0) break;\n\n // Filter out transitions that conflict with another enabled one\n const unambiguous = structural.filter((t) =>\n structural.every((other) => other === t || !hasInputConflict(t, other, current)),\n );\n if (unambiguous.length === 0) break;\n\n for (const t of unambiguous) {\n // Re-check enablement — earlier firings in this batch may have consumed tokens\n if (canFire(current, t)) {\n current = fire(current, t);\n }\n }\n }\n\n return current;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Resolve the virtual tool name for a tool call event */\nexport function resolveTool<P extends string>(\n net: SkillNet<P>,\n event: { toolName: string; input: Record<string, unknown> },\n): string {\n if (net.toolMapper) {\n return net.toolMapper({\n toolName: event.toolName,\n input: event.input,\n });\n }\n return event.toolName;\n}\n\n/** Return transitions that are structurally enabled and have a tools list */\nfunction enabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return net.transitions.filter(\n (t) => t.tools !== undefined && t.tools.length > 0 && canFire(marking, t),\n );\n}\n\n/** Public: get tool transitions the agent can currently use */\nexport function getEnabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return enabledToolTransitions(net, marking);\n}\n\n/** Format marking for display */\nexport function formatMarking<P extends string>(marking: Marking<P>): string {\n return Object.entries(marking)\n .filter(([, v]) => (v as number) > 0)\n .map(([k, v]) => `${k}:${v}`)\n .join(\", \");\n}\n\n/** A pending deferred transition awaiting tool_result */\ntype PendingDeferred<P extends string> = {\n toolCallId: string;\n transition: GatedTransition<P>;\n resolvedTool: string;\n};\n\nexport type GateState<P extends string> = {\n marking: Marking<P>;\n /** Skill-specific metadata (e.g. backed-up paths) */\n meta: Record<string, unknown>;\n /** Deferred transitions waiting for tool_result */\n pending: Map<string, PendingDeferred<P>>;\n};\n\nexport function createGateState<P extends string>(marking: Marking<P>): GateState<P> {\n return { marking, meta: {}, pending: new Map() };\n}\n\n/**\n * Core gating logic for a tool_call event.\n * Mutates state.marking when a non-deferred transition fires.\n * For deferred transitions, records pending and fires on tool_result.\n */\nexport async function handleToolCall<P extends string>(\n event: GateToolCall,\n ctx: GateContext,\n net: SkillNet<P>,\n state: GateState<P>,\n): Promise<GateDecision> {\n const resolvedTool = resolveTool(net, event);\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return undefined;\n }\n\n const enabled = enabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n block: true,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n const transition = matching[0]!;\n\n // Skill-specific validation (e.g. path coverage)\n if (net.validateToolCall) {\n const rejection = net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n resolvedTool,\n transition,\n state,\n );\n if (rejection) return rejection;\n }\n\n if (transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${transition.name}`,\n `Allow '${resolvedTool}' via transition '${transition.name}'?`,\n );\n if (!approved) {\n return { block: true, reason: `${resolvedTool} was rejected by human review.` };\n }\n }\n\n if (transition.deferred) {\n // Allow the tool call but don't fire yet — wait for tool_result\n state.pending.set(event.toolCallId, { toolCallId: event.toolCallId, transition, resolvedTool });\n return undefined;\n }\n\n // Fire immediately\n state.marking = fire(state.marking, transition);\n state.marking = autoAdvance(net, state.marking);\n\n return undefined;\n}\n\n/**\n * Handle a tool_result event. Fires deferred transitions on success.\n * Returns void (tool_result handler doesn't block).\n */\nexport function handleToolResult<P extends string>(\n event: GateToolResult,\n net: SkillNet<P>,\n state: GateState<P>,\n): void {\n const pending = state.pending.get(event.toolCallId);\n if (!pending) return;\n\n state.pending.delete(event.toolCallId);\n\n if (event.isError) {\n // Tool failed — don't fire the transition, marking unchanged\n return;\n }\n\n // Tool succeeded — fire the deferred transition\n if (canFire(state.marking, pending.transition)) {\n state.marking = fire(state.marking, pending.transition);\n\n // Notify the skill of the successful deferred result\n if (net.onDeferredResult) {\n net.onDeferredResult(\n {\n toolCallId: event.toolCallId,\n input: event.input,\n isError: event.isError,\n },\n pending.resolvedTool,\n pending.transition,\n state,\n );\n }\n\n state.marking = autoAdvance(net, state.marking);\n }\n}\n","import { fire } from \"@petriflow/engine\";\nimport type { GateToolCall, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport {\n getEnabledToolTransitions,\n resolveTool,\n} from \"./gate.js\";\nimport type { GateState } from \"./gate.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Classification of a net's opinion on a tool call */\nexport type NetVerdict<P extends string> = {\n net: SkillNet<P>;\n state: GateState<P>;\n resolvedTool: string;\n} & (\n | { kind: \"free\" }\n | { kind: \"abstain\" }\n | { kind: \"blocked\"; reason: string }\n | { kind: \"gated\"; transition: SkillNet<P>[\"transitions\"][number] }\n);\n\n/** Registry-based config for dynamic net management */\nexport type ComposeConfig = {\n registry: Record<string, SkillNet<string>>;\n active?: string[];\n};\n\n/**\n * Check if a net has jurisdiction over a tool — i.e. the tool appears\n * in at least one transition's tools list (enabled or not).\n */\nfunction hasJurisdiction<P extends string>(\n net: SkillNet<P>,\n resolvedTool: string,\n): boolean {\n return net.transitions.some(\n (t) => t.tools !== undefined && t.tools.includes(resolvedTool),\n );\n}\n\n/**\n * Phase 1 — Structural check (non-mutating).\n * Classify each net as free, gated, blocked, or abstain.\n */\nexport function classifyNets<P extends string>(\n nets: SkillNet<P>[],\n states: GateState<P>[],\n event: { toolName: string; input: Record<string, unknown> },\n): NetVerdict<P>[] {\n return nets.map((net, i) => {\n const state = states[i]!;\n const resolvedTool = resolveTool(net, event);\n const base = { net, state, resolvedTool };\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return { ...base, kind: \"free\" as const };\n }\n\n // No jurisdiction → abstain\n if (!hasJurisdiction(net, resolvedTool)) {\n return { ...base, kind: \"abstain\" as const };\n }\n\n // Has jurisdiction — check enabled transitions\n const enabled = getEnabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n ...base,\n kind: \"blocked\" as const,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n return { ...base, kind: \"gated\" as const, transition: matching[0]! };\n });\n}\n\n/**\n * 4-phase tool call handler for composed nets.\n */\nexport async function composedToolCall(\n getNets: () => SkillNet<string>[],\n getStates: () => GateState<string>[],\n event: GateToolCall,\n ctx: GateContext,\n): Promise<GateDecision> {\n const nets = getNets();\n const states = getStates();\n\n // --- Phase 1: Structural check ---\n const verdicts = classifyNets(nets, states, {\n toolName: event.toolName,\n input: event.input,\n });\n\n // If any net blocks, reject immediately\n const blocked = verdicts.find((v) => v.kind === \"blocked\");\n if (blocked) {\n return { block: true, reason: blocked.reason };\n }\n\n const gated = verdicts.filter(\n (v): v is Extract<NetVerdict<string>, { kind: \"gated\" }> => v.kind === \"gated\",\n );\n\n // No gated nets → all free/abstain → allow\n if (gated.length === 0) {\n return undefined;\n }\n\n // --- Phase 2: Manual approvals ---\n for (const v of gated) {\n if (v.transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = v.net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${v.resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${v.transition.name} (${v.net.name})`,\n `Allow '${v.resolvedTool}' via transition '${v.transition.name}' in net '${v.net.name}'?`,\n );\n if (!approved) {\n return {\n block: true,\n reason: `${v.resolvedTool} was rejected by human review.`,\n };\n }\n }\n }\n\n // --- Phase 3: Semantic validation with meta rollback ---\n // Snapshot all meta for rollback\n const metaSnapshots = gated.map((v) => structuredClone(v.state.meta));\n\n for (let i = 0; i < gated.length; i++) {\n const v = gated[i]!;\n if (v.net.validateToolCall) {\n const rejection = v.net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n v.resolvedTool,\n v.transition,\n v.state,\n );\n if (rejection) {\n // Rollback all meta that may have been mutated by earlier validates\n for (let j = 0; j < i; j++) {\n gated[j]!.state.meta = metaSnapshots[j]!;\n }\n return rejection;\n }\n }\n }\n\n // --- Phase 4: Commit ---\n for (const v of gated) {\n if (v.transition.deferred) {\n v.state.pending.set(event.toolCallId, {\n toolCallId: event.toolCallId,\n transition: v.transition,\n resolvedTool: v.resolvedTool,\n });\n } else {\n v.state.marking = fire(v.state.marking, v.transition);\n v.state.marking = autoAdvance(v.net, v.state.marking);\n }\n }\n\n return undefined;\n}\n","import type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport type { GateState } from \"./gate.js\";\nimport {\n createGateState,\n formatMarking,\n getEnabledToolTransitions,\n handleToolResult as handleToolResultSingle,\n} from \"./gate.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { composedToolCall } from \"./compose.js\";\nimport type { ComposeConfig } from \"./compose.js\";\n\nexport type GateManager = {\n handleToolCall: (event: GateToolCall, ctx: GateContext) => Promise<GateDecision>;\n handleToolResult: (event: GateToolResult) => void;\n addNet: (name: string) => { ok: boolean; message: string };\n removeNet: (name: string) => { ok: boolean; message: string };\n getActiveNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string> }>;\n getAllNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string>; active: boolean }>;\n formatStatus: () => string;\n formatSystemPrompt: () => string;\n isDynamic: boolean;\n};\n\nexport type GateManagerOptions = {\n /** \"enforce\" blocks disallowed tools. \"shadow\" logs but never blocks. */\n mode: \"enforce\" | \"shadow\";\n /** Called after every gating decision. Use for logging, metrics, debugging. */\n onDecision?: (event: GateToolCall, decision: GateDecision) => void;\n};\n\nexport function createGateManager(input: SkillNet<string>[] | ComposeConfig, opts?: GateManagerOptions): GateManager {\n const manager = Array.isArray(input) ? createArrayManager(input) : createRegistryManager(input);\n\n if (opts) {\n const original = manager.handleToolCall;\n manager.handleToolCall = async (event, ctx) => {\n const decision = await original.call(manager, event, ctx);\n opts.onDecision?.(event, decision);\n if (opts.mode === \"shadow\" && decision?.block) {\n return undefined;\n }\n return decision;\n };\n }\n\n return manager;\n}\n\nfunction createArrayManager(nets: SkillNet<string>[]): GateManager {\n const states = nets.map((net) =>\n createGateState(autoAdvance(net, { ...net.initialMarking })),\n );\n\n const getNets = () => nets;\n const getStates = () => states;\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getNets, getStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (let i = 0; i < nets.length; i++) {\n handleToolResultSingle(event, nets[i]!, states[i]!);\n }\n },\n\n addNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n removeNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n getActiveNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]! }));\n },\n\n getAllNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]!, active: true }));\n },\n\n formatStatus() {\n return nets\n .map((n, i) => `${n.name}: ${formatMarking(states[i]!.marking)}`)\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(nets, states);\n },\n\n isDynamic: false,\n };\n}\n\nfunction createRegistryManager(config: ComposeConfig): GateManager {\n const registry = new Map<string, { net: SkillNet<string>; state: GateState<string> }>();\n for (const [name, net] of Object.entries(config.registry)) {\n registry.set(name, {\n net,\n state: createGateState(autoAdvance(net, { ...net.initialMarking })),\n });\n }\n\n const activeNames = new Set<string>(config.active ?? Object.keys(config.registry));\n\n const getActiveNets = () => [...activeNames].map((n) => registry.get(n)!.net);\n const getActiveStates = () => [...activeNames].map((n) => registry.get(n)!.state);\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getActiveNets, getActiveStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (const { net, state } of registry.values()) {\n handleToolResultSingle(event, net, state);\n }\n },\n\n addNet(name) {\n if (!registry.has(name)) {\n return { ok: false, message: `Unknown net '${name}'. Available: ${[...registry.keys()].join(\", \")}` };\n }\n if (activeNames.has(name)) {\n return { ok: false, message: `'${name}' is already active` };\n }\n activeNames.add(name);\n return { ok: true, message: `Activated '${name}'` };\n },\n\n removeNet(name) {\n if (!activeNames.has(name)) {\n return { ok: false, message: `'${name}' is not active. Active: ${[...activeNames].join(\", \")}` };\n }\n activeNames.delete(name);\n return { ok: true, message: `Deactivated '${name}' (state preserved)` };\n },\n\n getActiveNets() {\n return [...activeNames].map((name) => {\n const entry = registry.get(name)!;\n return { name, net: entry.net, state: entry.state };\n });\n },\n\n getAllNets() {\n return [...registry.entries()].map(([name, { net, state }]) => ({\n name,\n net,\n state,\n active: activeNames.has(name),\n }));\n },\n\n formatStatus() {\n return [...registry.entries()]\n .map(([name, { state }]) => {\n const status = activeNames.has(name) ? \"active\" : \"inactive\";\n return `${name} (${status}): ${formatMarking(state.marking)}`;\n })\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(getActiveNets(), getActiveStates());\n },\n\n isDynamic: true,\n };\n}\n\nfunction formatPromptForNets(nets: SkillNet<string>[], states: GateState<string>[]): string {\n const sections = nets.map((net, i) => {\n const enabled = getEnabledToolTransitions(net, states[i]!.marking);\n const toolList = enabled.flatMap((t) => t.tools ?? []);\n return `### ${net.name}\\nAvailable gated tools: ${toolList.join(\", \") || \"none\"}\\nFree tools: ${net.freeTools.join(\", \")}\\nState: ${formatMarking(states[i]!.marking)}`;\n });\n return `## Active Petri Nets (composed)\\n${sections.join(\"\\n\\n\")}`;\n}\n"],"mappings":"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","names":["import_engine","import_engine"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/format.ts","../src/advance.ts","../src/gate.ts","../src/compose.ts","../src/manager.ts"],"sourcesContent":["// Types\nexport { defineSkillNet } from \"./types.js\";\nexport type { SkillNet, GatedTransition, ToolEvent, RuleMetadata } from \"./types.js\";\n\n// Block reason formatting\nexport { formatBlockReason } from \"./format.js\";\n\n// Generic event types\nexport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\n\n// Auto-advance\nexport { autoAdvance } from \"./advance.js\";\n\n// Single-net gating\nexport {\n handleToolCall,\n handleToolResult,\n formatMarking,\n getEnabledToolTransitions,\n createGateState,\n resolveTool,\n} from \"./gate.js\";\nexport type { GateState } from \"./gate.js\";\n\n// Multi-net composition\nexport { classifyNets, composedToolCall } from \"./compose.js\";\nexport type { ComposeConfig, NetVerdict } from \"./compose.js\";\n\n// Manager\nexport { createGateManager } from \"./manager.js\";\nexport type { GateManager, GateManagerOptions, ReplayEntry } from \"./manager.js\";\n","import type { Marking } from \"@petriflow/engine\";\n\n/** Structured metadata for generating user-facing block messages */\nexport type RuleMetadata =\n | { kind: \"sequence\"; prerequisite: string; dependent: string }\n | { kind: \"approval\"; tool: string }\n | { kind: \"block\"; tool: string }\n | { kind: \"limit\"; tool: string; limit: number; scope: \"session\" | string };\n\n/** A transition that optionally gates tool access */\nexport type GatedTransition<Place extends string> = {\n name: string;\n type: \"auto\" | \"manual\";\n inputs: Place[];\n outputs: Place[];\n guard?: string | null;\n tools?: string[];\n /**\n * When true, the transition allows the tool call immediately but\n * only fires (consumes/produces tokens) when the tool_result\n * comes back successfully (isError === false).\n * Use this for transitions where the tool must succeed before\n * the net advances (e.g. backup must succeed before delete unlocks).\n */\n deferred?: boolean;\n};\n\n/** Minimal tool event shape for toolMapper */\nexport type ToolEvent = { toolName: string; input: Record<string, unknown> };\n\n/** A Petri net that gates a skill's tool access */\nexport type SkillNet<Place extends string> = {\n name: string;\n places: Place[];\n transitions: GatedTransition<Place>[];\n initialMarking: Marking<Place>;\n terminalPlaces: Place[];\n freeTools: string[];\n /**\n * Maps a tool call to a virtual tool name before gating.\n * Use this to split one tool (e.g. \"bash\") into multiple gated\n * variants (e.g. \"bash\", \"git-commit\", \"git-push\") based on input.\n * If not provided, event.toolName is used as-is.\n */\n toolMapper?: (event: ToolEvent) => string;\n /**\n * Additional validation before a gated tool call is allowed.\n * Called after the net confirms a matching transition exists.\n * Return { block, reason } to reject, or void to allow.\n * Use this for domain-specific checks (e.g. path coverage).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n validateToolCall?(\n event: ToolEvent,\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): { block: true; reason: string } | void;\n /**\n * Called when a deferred transition's tool_result arrives.\n * Use this to record metadata (e.g. backed-up paths).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n onDeferredResult?(\n event: { toolCallId: string; input: Record<string, unknown>; isError: boolean },\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): void;\n /** Structured rule metadata for generating constraint-stating block messages */\n ruleMetadata?: RuleMetadata;\n};\n\n/** Type-safe helper — validates places/marking at the type level */\nexport function defineSkillNet<Place extends string>(\n net: SkillNet<Place>,\n): SkillNet<Place> {\n return net;\n}\n","import type { SkillNet } from \"./types.js\";\n\n/**\n * Generate a user-facing block reason from a net's rule metadata.\n *\n * With metadata (from the rules compiler), returns a constraint-stating message:\n * - sequence: \"deploy requires a successful call to test first.\"\n * - limit: \"deploy has reached its limit of 3 calls per session.\"\n * - block: \"rm is blocked and cannot be called.\"\n * - approval: \"deploy requires human approval.\"\n *\n * Without metadata (hand-built nets), falls back to a generic message.\n */\nexport function formatBlockReason(\n net: SkillNet<string>,\n resolvedTool: string,\n): string {\n const meta = net.ruleMetadata;\n\n if (meta) {\n switch (meta.kind) {\n case \"sequence\":\n return `${meta.dependent} requires a successful call to ${meta.prerequisite} first.`;\n case \"limit\":\n return meta.scope === \"session\"\n ? `${meta.tool} has reached its limit of ${meta.limit} calls per session.`\n : `${meta.tool} has reached its limit of ${meta.limit} calls per ${meta.scope}.`;\n case \"block\":\n return `${meta.tool} is blocked and cannot be called.`;\n case \"approval\":\n return `${meta.tool} requires human approval.`;\n }\n }\n\n return `Tool '${resolvedTool}' is not available in the current state.`;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\n\n/** A structural transition: type=auto, no tools property */\nfunction isStructural<P extends string>(t: GatedTransition<P>): boolean {\n return t.type === \"auto\" && (t.tools === undefined || t.tools.length === 0);\n}\n\n/**\n * Check if two transitions compete for the same input token.\n * Two transitions conflict if they share an input place and the\n * marking doesn't have enough tokens for both.\n */\nfunction hasInputConflict<P extends string>(\n a: GatedTransition<P>,\n b: GatedTransition<P>,\n marking: Marking<P>,\n): boolean {\n for (const place of a.inputs) {\n if (b.inputs.includes(place)) {\n // Count how many tokens each needs from this place\n const aNeeds = a.inputs.filter((p) => p === place).length;\n const bNeeds = b.inputs.filter((p) => p === place).length;\n if ((marking[place] ?? 0) < aNeeds + bNeeds) return true;\n }\n }\n return false;\n}\n\n/**\n * Auto-advance: fire all enabled structural transitions (type=auto,\n * no tools) in a loop until quiescent.\n *\n * When multiple structural transitions compete for the same input\n * token, none of them fire (avoids ambiguous choices).\n */\nexport function autoAdvance<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): Marking<P> {\n let current = { ...marking };\n\n for (;;) {\n const structural = net.transitions.filter(\n (t) => isStructural(t) && canFire(current, t),\n );\n if (structural.length === 0) break;\n\n // Filter out transitions that conflict with another enabled one\n const unambiguous = structural.filter((t) =>\n structural.every((other) => other === t || !hasInputConflict(t, other, current)),\n );\n if (unambiguous.length === 0) break;\n\n for (const t of unambiguous) {\n // Re-check enablement — earlier firings in this batch may have consumed tokens\n if (canFire(current, t)) {\n current = fire(current, t);\n }\n }\n }\n\n return current;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Resolve the virtual tool name for a tool call event */\nexport function resolveTool<P extends string>(\n net: SkillNet<P>,\n event: { toolName: string; input: Record<string, unknown> },\n): string {\n if (net.toolMapper) {\n return net.toolMapper({\n toolName: event.toolName,\n input: event.input,\n });\n }\n return event.toolName;\n}\n\n/** Return transitions that are structurally enabled and have a tools list */\nfunction enabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return net.transitions.filter(\n (t) => t.tools !== undefined && t.tools.length > 0 && canFire(marking, t),\n );\n}\n\n/** Public: get tool transitions the agent can currently use */\nexport function getEnabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return enabledToolTransitions(net, marking);\n}\n\n/** Format marking for display */\nexport function formatMarking<P extends string>(marking: Marking<P>): string {\n return Object.entries(marking)\n .filter(([, v]) => (v as number) > 0)\n .map(([k, v]) => `${k}:${v}`)\n .join(\", \");\n}\n\n/** A pending deferred transition awaiting tool_result */\ntype PendingDeferred<P extends string> = {\n toolCallId: string;\n transition: GatedTransition<P>;\n resolvedTool: string;\n};\n\nexport type GateState<P extends string> = {\n marking: Marking<P>;\n /** Skill-specific metadata (e.g. backed-up paths) */\n meta: Record<string, unknown>;\n /** Deferred transitions waiting for tool_result */\n pending: Map<string, PendingDeferred<P>>;\n};\n\nexport function createGateState<P extends string>(marking: Marking<P>): GateState<P> {\n return { marking, meta: {}, pending: new Map() };\n}\n\n/**\n * Core gating logic for a tool_call event.\n * Mutates state.marking when a non-deferred transition fires.\n * For deferred transitions, records pending and fires on tool_result.\n */\nexport async function handleToolCall<P extends string>(\n event: GateToolCall,\n ctx: GateContext,\n net: SkillNet<P>,\n state: GateState<P>,\n): Promise<GateDecision> {\n const resolvedTool = resolveTool(net, event);\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return undefined;\n }\n\n const enabled = enabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n block: true,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n const transition = matching[0]!;\n\n // Skill-specific validation (e.g. path coverage)\n if (net.validateToolCall) {\n const rejection = net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n resolvedTool,\n transition,\n state,\n );\n if (rejection) return rejection;\n }\n\n if (transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${transition.name}`,\n `Allow '${resolvedTool}' via transition '${transition.name}'?`,\n );\n if (!approved) {\n return { block: true, reason: `${resolvedTool} was rejected by human review.` };\n }\n }\n\n if (transition.deferred) {\n // Allow the tool call but don't fire yet — wait for tool_result\n state.pending.set(event.toolCallId, { toolCallId: event.toolCallId, transition, resolvedTool });\n return undefined;\n }\n\n // Fire immediately\n state.marking = fire(state.marking, transition);\n state.marking = autoAdvance(net, state.marking);\n\n return undefined;\n}\n\n/**\n * Handle a tool_result event. Fires deferred transitions on success.\n * Returns void (tool_result handler doesn't block).\n */\nexport function handleToolResult<P extends string>(\n event: GateToolResult,\n net: SkillNet<P>,\n state: GateState<P>,\n): void {\n const pending = state.pending.get(event.toolCallId);\n if (!pending) return;\n\n state.pending.delete(event.toolCallId);\n\n if (event.isError) {\n // Tool failed — don't fire the transition, marking unchanged\n return;\n }\n\n // Tool succeeded — fire the deferred transition\n if (canFire(state.marking, pending.transition)) {\n state.marking = fire(state.marking, pending.transition);\n\n // Notify the skill of the successful deferred result\n if (net.onDeferredResult) {\n net.onDeferredResult(\n {\n toolCallId: event.toolCallId,\n input: event.input,\n isError: event.isError,\n },\n pending.resolvedTool,\n pending.transition,\n state,\n );\n }\n\n state.marking = autoAdvance(net, state.marking);\n }\n}\n","import { fire } from \"@petriflow/engine\";\nimport type { GateToolCall, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport {\n getEnabledToolTransitions,\n resolveTool,\n} from \"./gate.js\";\nimport type { GateState } from \"./gate.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Classification of a net's opinion on a tool call */\nexport type NetVerdict<P extends string> = {\n net: SkillNet<P>;\n state: GateState<P>;\n resolvedTool: string;\n} & (\n | { kind: \"free\" }\n | { kind: \"abstain\" }\n | { kind: \"blocked\"; reason: string }\n | { kind: \"gated\"; transition: SkillNet<P>[\"transitions\"][number] }\n);\n\n/** Registry-based config for dynamic net management */\nexport type ComposeConfig = {\n registry: Record<string, SkillNet<string>>;\n active?: string[];\n};\n\n/**\n * Check if a net has jurisdiction over a tool — i.e. the tool appears\n * in at least one transition's tools list (enabled or not).\n */\nfunction hasJurisdiction<P extends string>(\n net: SkillNet<P>,\n resolvedTool: string,\n): boolean {\n return net.transitions.some(\n (t) => t.tools !== undefined && t.tools.includes(resolvedTool),\n );\n}\n\n/**\n * Phase 1 — Structural check (non-mutating).\n * Classify each net as free, gated, blocked, or abstain.\n */\nexport function classifyNets<P extends string>(\n nets: SkillNet<P>[],\n states: GateState<P>[],\n event: { toolName: string; input: Record<string, unknown> },\n): NetVerdict<P>[] {\n return nets.map((net, i) => {\n const state = states[i]!;\n const resolvedTool = resolveTool(net, event);\n const base = { net, state, resolvedTool };\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return { ...base, kind: \"free\" as const };\n }\n\n // No jurisdiction → abstain\n if (!hasJurisdiction(net, resolvedTool)) {\n return { ...base, kind: \"abstain\" as const };\n }\n\n // Has jurisdiction — check enabled transitions\n const enabled = getEnabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n ...base,\n kind: \"blocked\" as const,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n return { ...base, kind: \"gated\" as const, transition: matching[0]! };\n });\n}\n\n/**\n * 4-phase tool call handler for composed nets.\n */\nexport async function composedToolCall(\n getNets: () => SkillNet<string>[],\n getStates: () => GateState<string>[],\n event: GateToolCall,\n ctx: GateContext,\n): Promise<GateDecision> {\n const nets = getNets();\n const states = getStates();\n\n // --- Phase 1: Structural check ---\n const verdicts = classifyNets(nets, states, {\n toolName: event.toolName,\n input: event.input,\n });\n\n // If any net blocks, reject immediately\n const blocked = verdicts.find((v) => v.kind === \"blocked\");\n if (blocked) {\n return { block: true, reason: blocked.reason };\n }\n\n const gated = verdicts.filter(\n (v): v is Extract<NetVerdict<string>, { kind: \"gated\" }> => v.kind === \"gated\",\n );\n\n // No gated nets → all free/abstain → allow\n if (gated.length === 0) {\n return undefined;\n }\n\n // --- Phase 2: Manual approvals ---\n for (const v of gated) {\n if (v.transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = v.net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${v.resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${v.transition.name} (${v.net.name})`,\n `Allow '${v.resolvedTool}' via transition '${v.transition.name}' in net '${v.net.name}'?`,\n );\n if (!approved) {\n return {\n block: true,\n reason: `${v.resolvedTool} was rejected by human review.`,\n };\n }\n }\n }\n\n // --- Phase 3: Semantic validation with meta rollback ---\n // Snapshot all meta for rollback\n const metaSnapshots = gated.map((v) => structuredClone(v.state.meta));\n\n for (let i = 0; i < gated.length; i++) {\n const v = gated[i]!;\n if (v.net.validateToolCall) {\n const rejection = v.net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n v.resolvedTool,\n v.transition,\n v.state,\n );\n if (rejection) {\n // Rollback all meta that may have been mutated by earlier validates\n for (let j = 0; j < i; j++) {\n gated[j]!.state.meta = metaSnapshots[j]!;\n }\n return rejection;\n }\n }\n }\n\n // --- Phase 4: Commit ---\n for (const v of gated) {\n if (v.transition.deferred) {\n v.state.pending.set(event.toolCallId, {\n toolCallId: event.toolCallId,\n transition: v.transition,\n resolvedTool: v.resolvedTool,\n });\n } else {\n v.state.marking = fire(v.state.marking, v.transition);\n v.state.marking = autoAdvance(v.net, v.state.marking);\n }\n }\n\n return undefined;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport type { GateState } from \"./gate.js\";\nimport {\n createGateState,\n formatMarking,\n getEnabledToolTransitions,\n handleToolResult as handleToolResultSingle,\n resolveTool,\n} from \"./gate.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { composedToolCall } from \"./compose.js\";\nimport type { ComposeConfig } from \"./compose.js\";\n\nexport type ReplayEntry = {\n toolName: string;\n input?: Record<string, unknown>;\n isError: boolean;\n};\n\nexport type GateManager = {\n handleToolCall: (event: GateToolCall, ctx: GateContext) => Promise<GateDecision>;\n handleToolResult: (event: GateToolResult) => void;\n /**\n * Replay a sequence of completed tool results to advance net state.\n * Skips failed results (isError: true). Idempotent — if a transition\n * can't fire (already advanced past it), it is skipped silently.\n * Accepts an array of ReplayEntry objects or plain tool name strings\n * (treated as successful calls).\n */\n replay: (entries: ReplayEntry[] | string[]) => void;\n addNet: (name: string) => { ok: boolean; message: string };\n removeNet: (name: string) => { ok: boolean; message: string };\n getActiveNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string> }>;\n getAllNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string>; active: boolean }>;\n formatStatus: () => string;\n formatSystemPrompt: () => string;\n isDynamic: boolean;\n};\n\nexport type GateManagerOptions = {\n /** \"enforce\" blocks disallowed tools. \"shadow\" logs but never blocks. */\n mode: \"enforce\" | \"shadow\";\n /** Called after every gating decision. Use for logging, metrics, debugging. */\n onDecision?: (event: GateToolCall, decision: GateDecision) => void;\n};\n\nexport function createGateManager(input: SkillNet<string>[] | ComposeConfig, opts?: GateManagerOptions): GateManager {\n const manager = Array.isArray(input) ? createArrayManager(input) : createRegistryManager(input);\n\n if (opts) {\n const original = manager.handleToolCall;\n manager.handleToolCall = async (event, ctx) => {\n const decision = await original.call(manager, event, ctx);\n opts.onDecision?.(event, decision);\n if (opts.mode === \"shadow\" && decision?.block) {\n return undefined;\n }\n return decision;\n };\n }\n\n return manager;\n}\n\nfunction normalizeEntries(entries: ReplayEntry[] | string[]): ReplayEntry[] {\n if (entries.length === 0) return [];\n if (typeof entries[0] === \"string\") {\n return (entries as string[]).map((toolName) => ({ toolName, isError: false }));\n }\n return entries as ReplayEntry[];\n}\n\nfunction replayNets(\n nets: SkillNet<string>[],\n states: GateState<string>[],\n entries: ReplayEntry[],\n): void {\n for (const entry of entries) {\n if (entry.isError) continue;\n for (let i = 0; i < nets.length; i++) {\n const net = nets[i]!;\n const state = states[i]!;\n const resolved = resolveTool(net, { toolName: entry.toolName, input: entry.input ?? {} });\n\n if (net.freeTools.includes(resolved)) continue;\n\n const enabled = getEnabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolved));\n if (matching.length === 0) continue;\n\n const transition = matching[0]!;\n if (canFire(state.marking, transition)) {\n state.marking = fire(state.marking, transition);\n\n if (transition.deferred && net.onDeferredResult) {\n net.onDeferredResult(\n { toolCallId: `replay-${i}`, input: entry.input ?? {}, isError: false },\n resolved,\n transition,\n state,\n );\n }\n\n state.marking = autoAdvance(net, state.marking);\n }\n }\n }\n}\n\nfunction createArrayManager(nets: SkillNet<string>[]): GateManager {\n const states = nets.map((net) =>\n createGateState(autoAdvance(net, { ...net.initialMarking })),\n );\n\n const getNets = () => nets;\n const getStates = () => states;\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getNets, getStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (let i = 0; i < nets.length; i++) {\n handleToolResultSingle(event, nets[i]!, states[i]!);\n }\n },\n\n replay(entries) {\n replayNets(nets, states, normalizeEntries(entries));\n },\n\n addNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n removeNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n getActiveNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]! }));\n },\n\n getAllNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]!, active: true }));\n },\n\n formatStatus() {\n return nets\n .map((n, i) => `${n.name}: ${formatMarking(states[i]!.marking)}`)\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(nets, states);\n },\n\n isDynamic: false,\n };\n}\n\nfunction createRegistryManager(config: ComposeConfig): GateManager {\n const registry = new Map<string, { net: SkillNet<string>; state: GateState<string> }>();\n for (const [name, net] of Object.entries(config.registry)) {\n registry.set(name, {\n net,\n state: createGateState(autoAdvance(net, { ...net.initialMarking })),\n });\n }\n\n const activeNames = new Set<string>(config.active ?? Object.keys(config.registry));\n\n const getActiveNets = () => [...activeNames].map((n) => registry.get(n)!.net);\n const getActiveStates = () => [...activeNames].map((n) => registry.get(n)!.state);\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getActiveNets, getActiveStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (const { net, state } of registry.values()) {\n handleToolResultSingle(event, net, state);\n }\n },\n\n replay(entries) {\n const activeNets = getActiveNets();\n const activeStates = getActiveStates();\n replayNets(activeNets, activeStates, normalizeEntries(entries));\n },\n\n addNet(name) {\n if (!registry.has(name)) {\n return { ok: false, message: `Unknown net '${name}'. Available: ${[...registry.keys()].join(\", \")}` };\n }\n if (activeNames.has(name)) {\n return { ok: false, message: `'${name}' is already active` };\n }\n activeNames.add(name);\n return { ok: true, message: `Activated '${name}'` };\n },\n\n removeNet(name) {\n if (!activeNames.has(name)) {\n return { ok: false, message: `'${name}' is not active. Active: ${[...activeNames].join(\", \")}` };\n }\n activeNames.delete(name);\n return { ok: true, message: `Deactivated '${name}' (state preserved)` };\n },\n\n getActiveNets() {\n return [...activeNames].map((name) => {\n const entry = registry.get(name)!;\n return { name, net: entry.net, state: entry.state };\n });\n },\n\n getAllNets() {\n return [...registry.entries()].map(([name, { net, state }]) => ({\n name,\n net,\n state,\n active: activeNames.has(name),\n }));\n },\n\n formatStatus() {\n return [...registry.entries()]\n .map(([name, { state }]) => {\n const status = activeNames.has(name) ? \"active\" : \"inactive\";\n return `${name} (${status}): ${formatMarking(state.marking)}`;\n })\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(getActiveNets(), getActiveStates());\n },\n\n isDynamic: true,\n };\n}\n\nfunction formatPromptForNets(nets: SkillNet<string>[], states: GateState<string>[]): string {\n const sections = nets.map((net, i) => {\n const enabled = getEnabledToolTransitions(net, states[i]!.marking);\n const toolList = enabled.flatMap((t) => t.tools ?? []);\n return `### ${net.name}\\nAvailable gated tools: ${toolList.join(\", \") || \"none\"}\\nFree tools: ${net.freeTools.join(\", \")}\\nState: ${formatMarking(states[i]!.marking)}`;\n });\n return `## Active Petri Nets (composed)\\n${sections.join(\"\\n\\n\")}`;\n}\n"],"mappings":"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","names":["import_engine","import_engine","import_engine"]}
package/dist/index.d.cts CHANGED
@@ -204,9 +204,22 @@ declare function classifyNets<P extends string>(nets: SkillNet<P>[], states: Gat
204
204
  */
205
205
  declare function composedToolCall(getNets: () => SkillNet<string>[], getStates: () => GateState<string>[], event: GateToolCall, ctx: GateContext): Promise<GateDecision>;
206
206
 
207
+ type ReplayEntry = {
208
+ toolName: string;
209
+ input?: Record<string, unknown>;
210
+ isError: boolean;
211
+ };
207
212
  type GateManager = {
208
213
  handleToolCall: (event: GateToolCall, ctx: GateContext) => Promise<GateDecision>;
209
214
  handleToolResult: (event: GateToolResult) => void;
215
+ /**
216
+ * Replay a sequence of completed tool results to advance net state.
217
+ * Skips failed results (isError: true). Idempotent — if a transition
218
+ * can't fire (already advanced past it), it is skipped silently.
219
+ * Accepts an array of ReplayEntry objects or plain tool name strings
220
+ * (treated as successful calls).
221
+ */
222
+ replay: (entries: ReplayEntry[] | string[]) => void;
210
223
  addNet: (name: string) => {
211
224
  ok: boolean;
212
225
  message: string;
@@ -238,4 +251,4 @@ type GateManagerOptions = {
238
251
  };
239
252
  declare function createGateManager(input: SkillNet<string>[] | ComposeConfig, opts?: GateManagerOptions): GateManager;
240
253
 
241
- export { type ComposeConfig, type GateContext, type GateDecision, type GateManager, type GateManagerOptions, type GateState, type GateToolCall, type GateToolResult, type GatedTransition, type NetVerdict, type RuleMetadata, type SkillNet, type ToolEvent, autoAdvance, classifyNets, composedToolCall, createGateManager, createGateState, defineSkillNet, formatBlockReason, formatMarking, getEnabledToolTransitions, handleToolCall, handleToolResult, resolveTool };
254
+ export { type ComposeConfig, type GateContext, type GateDecision, type GateManager, type GateManagerOptions, type GateState, type GateToolCall, type GateToolResult, type GatedTransition, type NetVerdict, type ReplayEntry, type RuleMetadata, type SkillNet, type ToolEvent, autoAdvance, classifyNets, composedToolCall, createGateManager, createGateState, defineSkillNet, formatBlockReason, formatMarking, getEnabledToolTransitions, handleToolCall, handleToolResult, resolveTool };
package/dist/index.d.ts CHANGED
@@ -204,9 +204,22 @@ declare function classifyNets<P extends string>(nets: SkillNet<P>[], states: Gat
204
204
  */
205
205
  declare function composedToolCall(getNets: () => SkillNet<string>[], getStates: () => GateState<string>[], event: GateToolCall, ctx: GateContext): Promise<GateDecision>;
206
206
 
207
+ type ReplayEntry = {
208
+ toolName: string;
209
+ input?: Record<string, unknown>;
210
+ isError: boolean;
211
+ };
207
212
  type GateManager = {
208
213
  handleToolCall: (event: GateToolCall, ctx: GateContext) => Promise<GateDecision>;
209
214
  handleToolResult: (event: GateToolResult) => void;
215
+ /**
216
+ * Replay a sequence of completed tool results to advance net state.
217
+ * Skips failed results (isError: true). Idempotent — if a transition
218
+ * can't fire (already advanced past it), it is skipped silently.
219
+ * Accepts an array of ReplayEntry objects or plain tool name strings
220
+ * (treated as successful calls).
221
+ */
222
+ replay: (entries: ReplayEntry[] | string[]) => void;
210
223
  addNet: (name: string) => {
211
224
  ok: boolean;
212
225
  message: string;
@@ -238,4 +251,4 @@ type GateManagerOptions = {
238
251
  };
239
252
  declare function createGateManager(input: SkillNet<string>[] | ComposeConfig, opts?: GateManagerOptions): GateManager;
240
253
 
241
- export { type ComposeConfig, type GateContext, type GateDecision, type GateManager, type GateManagerOptions, type GateState, type GateToolCall, type GateToolResult, type GatedTransition, type NetVerdict, type RuleMetadata, type SkillNet, type ToolEvent, autoAdvance, classifyNets, composedToolCall, createGateManager, createGateState, defineSkillNet, formatBlockReason, formatMarking, getEnabledToolTransitions, handleToolCall, handleToolResult, resolveTool };
254
+ export { type ComposeConfig, type GateContext, type GateDecision, type GateManager, type GateManagerOptions, type GateState, type GateToolCall, type GateToolResult, type GatedTransition, type NetVerdict, type ReplayEntry, type RuleMetadata, type SkillNet, type ToolEvent, autoAdvance, classifyNets, composedToolCall, createGateManager, createGateState, defineSkillNet, formatBlockReason, formatMarking, getEnabledToolTransitions, handleToolCall, handleToolResult, resolveTool };
package/dist/index.js CHANGED
@@ -251,6 +251,7 @@ async function composedToolCall(getNets, getStates, event, ctx) {
251
251
  }
252
252
 
253
253
  // src/manager.ts
254
+ import { canFire as canFire3, fire as fire4 } from "@petriflow/engine";
254
255
  function createGateManager(input, opts) {
255
256
  const manager = Array.isArray(input) ? createArrayManager(input) : createRegistryManager(input);
256
257
  if (opts) {
@@ -266,6 +267,40 @@ function createGateManager(input, opts) {
266
267
  }
267
268
  return manager;
268
269
  }
270
+ function normalizeEntries(entries) {
271
+ if (entries.length === 0) return [];
272
+ if (typeof entries[0] === "string") {
273
+ return entries.map((toolName) => ({ toolName, isError: false }));
274
+ }
275
+ return entries;
276
+ }
277
+ function replayNets(nets, states, entries) {
278
+ for (const entry of entries) {
279
+ if (entry.isError) continue;
280
+ for (let i = 0; i < nets.length; i++) {
281
+ const net = nets[i];
282
+ const state = states[i];
283
+ const resolved = resolveTool(net, { toolName: entry.toolName, input: entry.input ?? {} });
284
+ if (net.freeTools.includes(resolved)) continue;
285
+ const enabled = getEnabledToolTransitions(net, state.marking);
286
+ const matching = enabled.filter((t) => t.tools.includes(resolved));
287
+ if (matching.length === 0) continue;
288
+ const transition = matching[0];
289
+ if (canFire3(state.marking, transition)) {
290
+ state.marking = fire4(state.marking, transition);
291
+ if (transition.deferred && net.onDeferredResult) {
292
+ net.onDeferredResult(
293
+ { toolCallId: `replay-${i}`, input: entry.input ?? {}, isError: false },
294
+ resolved,
295
+ transition,
296
+ state
297
+ );
298
+ }
299
+ state.marking = autoAdvance(net, state.marking);
300
+ }
301
+ }
302
+ }
303
+ }
269
304
  function createArrayManager(nets) {
270
305
  const states = nets.map(
271
306
  (net) => createGateState(autoAdvance(net, { ...net.initialMarking }))
@@ -281,6 +316,9 @@ function createArrayManager(nets) {
281
316
  handleToolResult(event, nets[i], states[i]);
282
317
  }
283
318
  },
319
+ replay(entries) {
320
+ replayNets(nets, states, normalizeEntries(entries));
321
+ },
284
322
  addNet() {
285
323
  return { ok: false, message: "Static composition does not support dynamic nets" };
286
324
  },
@@ -322,6 +360,11 @@ function createRegistryManager(config) {
322
360
  handleToolResult(event, net, state);
323
361
  }
324
362
  },
363
+ replay(entries) {
364
+ const activeNets = getActiveNets();
365
+ const activeStates = getActiveStates();
366
+ replayNets(activeNets, activeStates, normalizeEntries(entries));
367
+ },
325
368
  addNet(name) {
326
369
  if (!registry.has(name)) {
327
370
  return { ok: false, message: `Unknown net '${name}'. Available: ${[...registry.keys()].join(", ")}` };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/format.ts","../src/advance.ts","../src/gate.ts","../src/compose.ts","../src/manager.ts"],"sourcesContent":["import type { Marking } from \"@petriflow/engine\";\n\n/** Structured metadata for generating user-facing block messages */\nexport type RuleMetadata =\n | { kind: \"sequence\"; prerequisite: string; dependent: string }\n | { kind: \"approval\"; tool: string }\n | { kind: \"block\"; tool: string }\n | { kind: \"limit\"; tool: string; limit: number; scope: \"session\" | string };\n\n/** A transition that optionally gates tool access */\nexport type GatedTransition<Place extends string> = {\n name: string;\n type: \"auto\" | \"manual\";\n inputs: Place[];\n outputs: Place[];\n guard?: string | null;\n tools?: string[];\n /**\n * When true, the transition allows the tool call immediately but\n * only fires (consumes/produces tokens) when the tool_result\n * comes back successfully (isError === false).\n * Use this for transitions where the tool must succeed before\n * the net advances (e.g. backup must succeed before delete unlocks).\n */\n deferred?: boolean;\n};\n\n/** Minimal tool event shape for toolMapper */\nexport type ToolEvent = { toolName: string; input: Record<string, unknown> };\n\n/** A Petri net that gates a skill's tool access */\nexport type SkillNet<Place extends string> = {\n name: string;\n places: Place[];\n transitions: GatedTransition<Place>[];\n initialMarking: Marking<Place>;\n terminalPlaces: Place[];\n freeTools: string[];\n /**\n * Maps a tool call to a virtual tool name before gating.\n * Use this to split one tool (e.g. \"bash\") into multiple gated\n * variants (e.g. \"bash\", \"git-commit\", \"git-push\") based on input.\n * If not provided, event.toolName is used as-is.\n */\n toolMapper?: (event: ToolEvent) => string;\n /**\n * Additional validation before a gated tool call is allowed.\n * Called after the net confirms a matching transition exists.\n * Return { block, reason } to reject, or void to allow.\n * Use this for domain-specific checks (e.g. path coverage).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n validateToolCall?(\n event: ToolEvent,\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): { block: true; reason: string } | void;\n /**\n * Called when a deferred transition's tool_result arrives.\n * Use this to record metadata (e.g. backed-up paths).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n onDeferredResult?(\n event: { toolCallId: string; input: Record<string, unknown>; isError: boolean },\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): void;\n /** Structured rule metadata for generating constraint-stating block messages */\n ruleMetadata?: RuleMetadata;\n};\n\n/** Type-safe helper — validates places/marking at the type level */\nexport function defineSkillNet<Place extends string>(\n net: SkillNet<Place>,\n): SkillNet<Place> {\n return net;\n}\n","import type { SkillNet } from \"./types.js\";\n\n/**\n * Generate a user-facing block reason from a net's rule metadata.\n *\n * With metadata (from the rules compiler), returns a constraint-stating message:\n * - sequence: \"deploy requires a successful call to test first.\"\n * - limit: \"deploy has reached its limit of 3 calls per session.\"\n * - block: \"rm is blocked and cannot be called.\"\n * - approval: \"deploy requires human approval.\"\n *\n * Without metadata (hand-built nets), falls back to a generic message.\n */\nexport function formatBlockReason(\n net: SkillNet<string>,\n resolvedTool: string,\n): string {\n const meta = net.ruleMetadata;\n\n if (meta) {\n switch (meta.kind) {\n case \"sequence\":\n return `${meta.dependent} requires a successful call to ${meta.prerequisite} first.`;\n case \"limit\":\n return meta.scope === \"session\"\n ? `${meta.tool} has reached its limit of ${meta.limit} calls per session.`\n : `${meta.tool} has reached its limit of ${meta.limit} calls per ${meta.scope}.`;\n case \"block\":\n return `${meta.tool} is blocked and cannot be called.`;\n case \"approval\":\n return `${meta.tool} requires human approval.`;\n }\n }\n\n return `Tool '${resolvedTool}' is not available in the current state.`;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\n\n/** A structural transition: type=auto, no tools property */\nfunction isStructural<P extends string>(t: GatedTransition<P>): boolean {\n return t.type === \"auto\" && (t.tools === undefined || t.tools.length === 0);\n}\n\n/**\n * Check if two transitions compete for the same input token.\n * Two transitions conflict if they share an input place and the\n * marking doesn't have enough tokens for both.\n */\nfunction hasInputConflict<P extends string>(\n a: GatedTransition<P>,\n b: GatedTransition<P>,\n marking: Marking<P>,\n): boolean {\n for (const place of a.inputs) {\n if (b.inputs.includes(place)) {\n // Count how many tokens each needs from this place\n const aNeeds = a.inputs.filter((p) => p === place).length;\n const bNeeds = b.inputs.filter((p) => p === place).length;\n if ((marking[place] ?? 0) < aNeeds + bNeeds) return true;\n }\n }\n return false;\n}\n\n/**\n * Auto-advance: fire all enabled structural transitions (type=auto,\n * no tools) in a loop until quiescent.\n *\n * When multiple structural transitions compete for the same input\n * token, none of them fire (avoids ambiguous choices).\n */\nexport function autoAdvance<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): Marking<P> {\n let current = { ...marking };\n\n for (;;) {\n const structural = net.transitions.filter(\n (t) => isStructural(t) && canFire(current, t),\n );\n if (structural.length === 0) break;\n\n // Filter out transitions that conflict with another enabled one\n const unambiguous = structural.filter((t) =>\n structural.every((other) => other === t || !hasInputConflict(t, other, current)),\n );\n if (unambiguous.length === 0) break;\n\n for (const t of unambiguous) {\n // Re-check enablement — earlier firings in this batch may have consumed tokens\n if (canFire(current, t)) {\n current = fire(current, t);\n }\n }\n }\n\n return current;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Resolve the virtual tool name for a tool call event */\nexport function resolveTool<P extends string>(\n net: SkillNet<P>,\n event: { toolName: string; input: Record<string, unknown> },\n): string {\n if (net.toolMapper) {\n return net.toolMapper({\n toolName: event.toolName,\n input: event.input,\n });\n }\n return event.toolName;\n}\n\n/** Return transitions that are structurally enabled and have a tools list */\nfunction enabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return net.transitions.filter(\n (t) => t.tools !== undefined && t.tools.length > 0 && canFire(marking, t),\n );\n}\n\n/** Public: get tool transitions the agent can currently use */\nexport function getEnabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return enabledToolTransitions(net, marking);\n}\n\n/** Format marking for display */\nexport function formatMarking<P extends string>(marking: Marking<P>): string {\n return Object.entries(marking)\n .filter(([, v]) => (v as number) > 0)\n .map(([k, v]) => `${k}:${v}`)\n .join(\", \");\n}\n\n/** A pending deferred transition awaiting tool_result */\ntype PendingDeferred<P extends string> = {\n toolCallId: string;\n transition: GatedTransition<P>;\n resolvedTool: string;\n};\n\nexport type GateState<P extends string> = {\n marking: Marking<P>;\n /** Skill-specific metadata (e.g. backed-up paths) */\n meta: Record<string, unknown>;\n /** Deferred transitions waiting for tool_result */\n pending: Map<string, PendingDeferred<P>>;\n};\n\nexport function createGateState<P extends string>(marking: Marking<P>): GateState<P> {\n return { marking, meta: {}, pending: new Map() };\n}\n\n/**\n * Core gating logic for a tool_call event.\n * Mutates state.marking when a non-deferred transition fires.\n * For deferred transitions, records pending and fires on tool_result.\n */\nexport async function handleToolCall<P extends string>(\n event: GateToolCall,\n ctx: GateContext,\n net: SkillNet<P>,\n state: GateState<P>,\n): Promise<GateDecision> {\n const resolvedTool = resolveTool(net, event);\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return undefined;\n }\n\n const enabled = enabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n block: true,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n const transition = matching[0]!;\n\n // Skill-specific validation (e.g. path coverage)\n if (net.validateToolCall) {\n const rejection = net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n resolvedTool,\n transition,\n state,\n );\n if (rejection) return rejection;\n }\n\n if (transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${transition.name}`,\n `Allow '${resolvedTool}' via transition '${transition.name}'?`,\n );\n if (!approved) {\n return { block: true, reason: `${resolvedTool} was rejected by human review.` };\n }\n }\n\n if (transition.deferred) {\n // Allow the tool call but don't fire yet — wait for tool_result\n state.pending.set(event.toolCallId, { toolCallId: event.toolCallId, transition, resolvedTool });\n return undefined;\n }\n\n // Fire immediately\n state.marking = fire(state.marking, transition);\n state.marking = autoAdvance(net, state.marking);\n\n return undefined;\n}\n\n/**\n * Handle a tool_result event. Fires deferred transitions on success.\n * Returns void (tool_result handler doesn't block).\n */\nexport function handleToolResult<P extends string>(\n event: GateToolResult,\n net: SkillNet<P>,\n state: GateState<P>,\n): void {\n const pending = state.pending.get(event.toolCallId);\n if (!pending) return;\n\n state.pending.delete(event.toolCallId);\n\n if (event.isError) {\n // Tool failed — don't fire the transition, marking unchanged\n return;\n }\n\n // Tool succeeded — fire the deferred transition\n if (canFire(state.marking, pending.transition)) {\n state.marking = fire(state.marking, pending.transition);\n\n // Notify the skill of the successful deferred result\n if (net.onDeferredResult) {\n net.onDeferredResult(\n {\n toolCallId: event.toolCallId,\n input: event.input,\n isError: event.isError,\n },\n pending.resolvedTool,\n pending.transition,\n state,\n );\n }\n\n state.marking = autoAdvance(net, state.marking);\n }\n}\n","import { fire } from \"@petriflow/engine\";\nimport type { GateToolCall, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport {\n getEnabledToolTransitions,\n resolveTool,\n} from \"./gate.js\";\nimport type { GateState } from \"./gate.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Classification of a net's opinion on a tool call */\nexport type NetVerdict<P extends string> = {\n net: SkillNet<P>;\n state: GateState<P>;\n resolvedTool: string;\n} & (\n | { kind: \"free\" }\n | { kind: \"abstain\" }\n | { kind: \"blocked\"; reason: string }\n | { kind: \"gated\"; transition: SkillNet<P>[\"transitions\"][number] }\n);\n\n/** Registry-based config for dynamic net management */\nexport type ComposeConfig = {\n registry: Record<string, SkillNet<string>>;\n active?: string[];\n};\n\n/**\n * Check if a net has jurisdiction over a tool — i.e. the tool appears\n * in at least one transition's tools list (enabled or not).\n */\nfunction hasJurisdiction<P extends string>(\n net: SkillNet<P>,\n resolvedTool: string,\n): boolean {\n return net.transitions.some(\n (t) => t.tools !== undefined && t.tools.includes(resolvedTool),\n );\n}\n\n/**\n * Phase 1 — Structural check (non-mutating).\n * Classify each net as free, gated, blocked, or abstain.\n */\nexport function classifyNets<P extends string>(\n nets: SkillNet<P>[],\n states: GateState<P>[],\n event: { toolName: string; input: Record<string, unknown> },\n): NetVerdict<P>[] {\n return nets.map((net, i) => {\n const state = states[i]!;\n const resolvedTool = resolveTool(net, event);\n const base = { net, state, resolvedTool };\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return { ...base, kind: \"free\" as const };\n }\n\n // No jurisdiction → abstain\n if (!hasJurisdiction(net, resolvedTool)) {\n return { ...base, kind: \"abstain\" as const };\n }\n\n // Has jurisdiction — check enabled transitions\n const enabled = getEnabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n ...base,\n kind: \"blocked\" as const,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n return { ...base, kind: \"gated\" as const, transition: matching[0]! };\n });\n}\n\n/**\n * 4-phase tool call handler for composed nets.\n */\nexport async function composedToolCall(\n getNets: () => SkillNet<string>[],\n getStates: () => GateState<string>[],\n event: GateToolCall,\n ctx: GateContext,\n): Promise<GateDecision> {\n const nets = getNets();\n const states = getStates();\n\n // --- Phase 1: Structural check ---\n const verdicts = classifyNets(nets, states, {\n toolName: event.toolName,\n input: event.input,\n });\n\n // If any net blocks, reject immediately\n const blocked = verdicts.find((v) => v.kind === \"blocked\");\n if (blocked) {\n return { block: true, reason: blocked.reason };\n }\n\n const gated = verdicts.filter(\n (v): v is Extract<NetVerdict<string>, { kind: \"gated\" }> => v.kind === \"gated\",\n );\n\n // No gated nets → all free/abstain → allow\n if (gated.length === 0) {\n return undefined;\n }\n\n // --- Phase 2: Manual approvals ---\n for (const v of gated) {\n if (v.transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = v.net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${v.resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${v.transition.name} (${v.net.name})`,\n `Allow '${v.resolvedTool}' via transition '${v.transition.name}' in net '${v.net.name}'?`,\n );\n if (!approved) {\n return {\n block: true,\n reason: `${v.resolvedTool} was rejected by human review.`,\n };\n }\n }\n }\n\n // --- Phase 3: Semantic validation with meta rollback ---\n // Snapshot all meta for rollback\n const metaSnapshots = gated.map((v) => structuredClone(v.state.meta));\n\n for (let i = 0; i < gated.length; i++) {\n const v = gated[i]!;\n if (v.net.validateToolCall) {\n const rejection = v.net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n v.resolvedTool,\n v.transition,\n v.state,\n );\n if (rejection) {\n // Rollback all meta that may have been mutated by earlier validates\n for (let j = 0; j < i; j++) {\n gated[j]!.state.meta = metaSnapshots[j]!;\n }\n return rejection;\n }\n }\n }\n\n // --- Phase 4: Commit ---\n for (const v of gated) {\n if (v.transition.deferred) {\n v.state.pending.set(event.toolCallId, {\n toolCallId: event.toolCallId,\n transition: v.transition,\n resolvedTool: v.resolvedTool,\n });\n } else {\n v.state.marking = fire(v.state.marking, v.transition);\n v.state.marking = autoAdvance(v.net, v.state.marking);\n }\n }\n\n return undefined;\n}\n","import type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport type { GateState } from \"./gate.js\";\nimport {\n createGateState,\n formatMarking,\n getEnabledToolTransitions,\n handleToolResult as handleToolResultSingle,\n} from \"./gate.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { composedToolCall } from \"./compose.js\";\nimport type { ComposeConfig } from \"./compose.js\";\n\nexport type GateManager = {\n handleToolCall: (event: GateToolCall, ctx: GateContext) => Promise<GateDecision>;\n handleToolResult: (event: GateToolResult) => void;\n addNet: (name: string) => { ok: boolean; message: string };\n removeNet: (name: string) => { ok: boolean; message: string };\n getActiveNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string> }>;\n getAllNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string>; active: boolean }>;\n formatStatus: () => string;\n formatSystemPrompt: () => string;\n isDynamic: boolean;\n};\n\nexport type GateManagerOptions = {\n /** \"enforce\" blocks disallowed tools. \"shadow\" logs but never blocks. */\n mode: \"enforce\" | \"shadow\";\n /** Called after every gating decision. Use for logging, metrics, debugging. */\n onDecision?: (event: GateToolCall, decision: GateDecision) => void;\n};\n\nexport function createGateManager(input: SkillNet<string>[] | ComposeConfig, opts?: GateManagerOptions): GateManager {\n const manager = Array.isArray(input) ? createArrayManager(input) : createRegistryManager(input);\n\n if (opts) {\n const original = manager.handleToolCall;\n manager.handleToolCall = async (event, ctx) => {\n const decision = await original.call(manager, event, ctx);\n opts.onDecision?.(event, decision);\n if (opts.mode === \"shadow\" && decision?.block) {\n return undefined;\n }\n return decision;\n };\n }\n\n return manager;\n}\n\nfunction createArrayManager(nets: SkillNet<string>[]): GateManager {\n const states = nets.map((net) =>\n createGateState(autoAdvance(net, { ...net.initialMarking })),\n );\n\n const getNets = () => nets;\n const getStates = () => states;\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getNets, getStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (let i = 0; i < nets.length; i++) {\n handleToolResultSingle(event, nets[i]!, states[i]!);\n }\n },\n\n addNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n removeNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n getActiveNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]! }));\n },\n\n getAllNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]!, active: true }));\n },\n\n formatStatus() {\n return nets\n .map((n, i) => `${n.name}: ${formatMarking(states[i]!.marking)}`)\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(nets, states);\n },\n\n isDynamic: false,\n };\n}\n\nfunction createRegistryManager(config: ComposeConfig): GateManager {\n const registry = new Map<string, { net: SkillNet<string>; state: GateState<string> }>();\n for (const [name, net] of Object.entries(config.registry)) {\n registry.set(name, {\n net,\n state: createGateState(autoAdvance(net, { ...net.initialMarking })),\n });\n }\n\n const activeNames = new Set<string>(config.active ?? Object.keys(config.registry));\n\n const getActiveNets = () => [...activeNames].map((n) => registry.get(n)!.net);\n const getActiveStates = () => [...activeNames].map((n) => registry.get(n)!.state);\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getActiveNets, getActiveStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (const { net, state } of registry.values()) {\n handleToolResultSingle(event, net, state);\n }\n },\n\n addNet(name) {\n if (!registry.has(name)) {\n return { ok: false, message: `Unknown net '${name}'. Available: ${[...registry.keys()].join(\", \")}` };\n }\n if (activeNames.has(name)) {\n return { ok: false, message: `'${name}' is already active` };\n }\n activeNames.add(name);\n return { ok: true, message: `Activated '${name}'` };\n },\n\n removeNet(name) {\n if (!activeNames.has(name)) {\n return { ok: false, message: `'${name}' is not active. Active: ${[...activeNames].join(\", \")}` };\n }\n activeNames.delete(name);\n return { ok: true, message: `Deactivated '${name}' (state preserved)` };\n },\n\n getActiveNets() {\n return [...activeNames].map((name) => {\n const entry = registry.get(name)!;\n return { name, net: entry.net, state: entry.state };\n });\n },\n\n getAllNets() {\n return [...registry.entries()].map(([name, { net, state }]) => ({\n name,\n net,\n state,\n active: activeNames.has(name),\n }));\n },\n\n formatStatus() {\n return [...registry.entries()]\n .map(([name, { state }]) => {\n const status = activeNames.has(name) ? \"active\" : \"inactive\";\n return `${name} (${status}): ${formatMarking(state.marking)}`;\n })\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(getActiveNets(), getActiveStates());\n },\n\n isDynamic: true,\n };\n}\n\nfunction formatPromptForNets(nets: SkillNet<string>[], states: GateState<string>[]): string {\n const sections = nets.map((net, i) => {\n const enabled = getEnabledToolTransitions(net, states[i]!.marking);\n const toolList = enabled.flatMap((t) => t.tools ?? []);\n return `### ${net.name}\\nAvailable gated tools: ${toolList.join(\", \") || \"none\"}\\nFree tools: ${net.freeTools.join(\", \")}\\nState: ${formatMarking(states[i]!.marking)}`;\n });\n return `## Active Petri Nets (composed)\\n${sections.join(\"\\n\\n\")}`;\n}\n"],"mappings":"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","names":["canFire","fire","canFire","fire","fire","fire"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/format.ts","../src/advance.ts","../src/gate.ts","../src/compose.ts","../src/manager.ts"],"sourcesContent":["import type { Marking } from \"@petriflow/engine\";\n\n/** Structured metadata for generating user-facing block messages */\nexport type RuleMetadata =\n | { kind: \"sequence\"; prerequisite: string; dependent: string }\n | { kind: \"approval\"; tool: string }\n | { kind: \"block\"; tool: string }\n | { kind: \"limit\"; tool: string; limit: number; scope: \"session\" | string };\n\n/** A transition that optionally gates tool access */\nexport type GatedTransition<Place extends string> = {\n name: string;\n type: \"auto\" | \"manual\";\n inputs: Place[];\n outputs: Place[];\n guard?: string | null;\n tools?: string[];\n /**\n * When true, the transition allows the tool call immediately but\n * only fires (consumes/produces tokens) when the tool_result\n * comes back successfully (isError === false).\n * Use this for transitions where the tool must succeed before\n * the net advances (e.g. backup must succeed before delete unlocks).\n */\n deferred?: boolean;\n};\n\n/** Minimal tool event shape for toolMapper */\nexport type ToolEvent = { toolName: string; input: Record<string, unknown> };\n\n/** A Petri net that gates a skill's tool access */\nexport type SkillNet<Place extends string> = {\n name: string;\n places: Place[];\n transitions: GatedTransition<Place>[];\n initialMarking: Marking<Place>;\n terminalPlaces: Place[];\n freeTools: string[];\n /**\n * Maps a tool call to a virtual tool name before gating.\n * Use this to split one tool (e.g. \"bash\") into multiple gated\n * variants (e.g. \"bash\", \"git-commit\", \"git-push\") based on input.\n * If not provided, event.toolName is used as-is.\n */\n toolMapper?: (event: ToolEvent) => string;\n /**\n * Additional validation before a gated tool call is allowed.\n * Called after the net confirms a matching transition exists.\n * Return { block, reason } to reject, or void to allow.\n * Use this for domain-specific checks (e.g. path coverage).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n validateToolCall?(\n event: ToolEvent,\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): { block: true; reason: string } | void;\n /**\n * Called when a deferred transition's tool_result arrives.\n * Use this to record metadata (e.g. backed-up paths).\n *\n * Method syntax is intentional — bivariant so SkillNet<Place> widens to SkillNet<string>.\n */\n onDeferredResult?(\n event: { toolCallId: string; input: Record<string, unknown>; isError: boolean },\n resolvedTool: string,\n transition: GatedTransition<Place>,\n state: { marking: Marking<Place>; meta: Record<string, unknown> },\n ): void;\n /** Structured rule metadata for generating constraint-stating block messages */\n ruleMetadata?: RuleMetadata;\n};\n\n/** Type-safe helper — validates places/marking at the type level */\nexport function defineSkillNet<Place extends string>(\n net: SkillNet<Place>,\n): SkillNet<Place> {\n return net;\n}\n","import type { SkillNet } from \"./types.js\";\n\n/**\n * Generate a user-facing block reason from a net's rule metadata.\n *\n * With metadata (from the rules compiler), returns a constraint-stating message:\n * - sequence: \"deploy requires a successful call to test first.\"\n * - limit: \"deploy has reached its limit of 3 calls per session.\"\n * - block: \"rm is blocked and cannot be called.\"\n * - approval: \"deploy requires human approval.\"\n *\n * Without metadata (hand-built nets), falls back to a generic message.\n */\nexport function formatBlockReason(\n net: SkillNet<string>,\n resolvedTool: string,\n): string {\n const meta = net.ruleMetadata;\n\n if (meta) {\n switch (meta.kind) {\n case \"sequence\":\n return `${meta.dependent} requires a successful call to ${meta.prerequisite} first.`;\n case \"limit\":\n return meta.scope === \"session\"\n ? `${meta.tool} has reached its limit of ${meta.limit} calls per session.`\n : `${meta.tool} has reached its limit of ${meta.limit} calls per ${meta.scope}.`;\n case \"block\":\n return `${meta.tool} is blocked and cannot be called.`;\n case \"approval\":\n return `${meta.tool} requires human approval.`;\n }\n }\n\n return `Tool '${resolvedTool}' is not available in the current state.`;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\n\n/** A structural transition: type=auto, no tools property */\nfunction isStructural<P extends string>(t: GatedTransition<P>): boolean {\n return t.type === \"auto\" && (t.tools === undefined || t.tools.length === 0);\n}\n\n/**\n * Check if two transitions compete for the same input token.\n * Two transitions conflict if they share an input place and the\n * marking doesn't have enough tokens for both.\n */\nfunction hasInputConflict<P extends string>(\n a: GatedTransition<P>,\n b: GatedTransition<P>,\n marking: Marking<P>,\n): boolean {\n for (const place of a.inputs) {\n if (b.inputs.includes(place)) {\n // Count how many tokens each needs from this place\n const aNeeds = a.inputs.filter((p) => p === place).length;\n const bNeeds = b.inputs.filter((p) => p === place).length;\n if ((marking[place] ?? 0) < aNeeds + bNeeds) return true;\n }\n }\n return false;\n}\n\n/**\n * Auto-advance: fire all enabled structural transitions (type=auto,\n * no tools) in a loop until quiescent.\n *\n * When multiple structural transitions compete for the same input\n * token, none of them fire (avoids ambiguous choices).\n */\nexport function autoAdvance<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): Marking<P> {\n let current = { ...marking };\n\n for (;;) {\n const structural = net.transitions.filter(\n (t) => isStructural(t) && canFire(current, t),\n );\n if (structural.length === 0) break;\n\n // Filter out transitions that conflict with another enabled one\n const unambiguous = structural.filter((t) =>\n structural.every((other) => other === t || !hasInputConflict(t, other, current)),\n );\n if (unambiguous.length === 0) break;\n\n for (const t of unambiguous) {\n // Re-check enablement — earlier firings in this batch may have consumed tokens\n if (canFire(current, t)) {\n current = fire(current, t);\n }\n }\n }\n\n return current;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { Marking } from \"@petriflow/engine\";\nimport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { GatedTransition, SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Resolve the virtual tool name for a tool call event */\nexport function resolveTool<P extends string>(\n net: SkillNet<P>,\n event: { toolName: string; input: Record<string, unknown> },\n): string {\n if (net.toolMapper) {\n return net.toolMapper({\n toolName: event.toolName,\n input: event.input,\n });\n }\n return event.toolName;\n}\n\n/** Return transitions that are structurally enabled and have a tools list */\nfunction enabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return net.transitions.filter(\n (t) => t.tools !== undefined && t.tools.length > 0 && canFire(marking, t),\n );\n}\n\n/** Public: get tool transitions the agent can currently use */\nexport function getEnabledToolTransitions<P extends string>(\n net: SkillNet<P>,\n marking: Marking<P>,\n): GatedTransition<P>[] {\n return enabledToolTransitions(net, marking);\n}\n\n/** Format marking for display */\nexport function formatMarking<P extends string>(marking: Marking<P>): string {\n return Object.entries(marking)\n .filter(([, v]) => (v as number) > 0)\n .map(([k, v]) => `${k}:${v}`)\n .join(\", \");\n}\n\n/** A pending deferred transition awaiting tool_result */\ntype PendingDeferred<P extends string> = {\n toolCallId: string;\n transition: GatedTransition<P>;\n resolvedTool: string;\n};\n\nexport type GateState<P extends string> = {\n marking: Marking<P>;\n /** Skill-specific metadata (e.g. backed-up paths) */\n meta: Record<string, unknown>;\n /** Deferred transitions waiting for tool_result */\n pending: Map<string, PendingDeferred<P>>;\n};\n\nexport function createGateState<P extends string>(marking: Marking<P>): GateState<P> {\n return { marking, meta: {}, pending: new Map() };\n}\n\n/**\n * Core gating logic for a tool_call event.\n * Mutates state.marking when a non-deferred transition fires.\n * For deferred transitions, records pending and fires on tool_result.\n */\nexport async function handleToolCall<P extends string>(\n event: GateToolCall,\n ctx: GateContext,\n net: SkillNet<P>,\n state: GateState<P>,\n): Promise<GateDecision> {\n const resolvedTool = resolveTool(net, event);\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return undefined;\n }\n\n const enabled = enabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n block: true,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n const transition = matching[0]!;\n\n // Skill-specific validation (e.g. path coverage)\n if (net.validateToolCall) {\n const rejection = net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n resolvedTool,\n transition,\n state,\n );\n if (rejection) return rejection;\n }\n\n if (transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${transition.name}`,\n `Allow '${resolvedTool}' via transition '${transition.name}'?`,\n );\n if (!approved) {\n return { block: true, reason: `${resolvedTool} was rejected by human review.` };\n }\n }\n\n if (transition.deferred) {\n // Allow the tool call but don't fire yet — wait for tool_result\n state.pending.set(event.toolCallId, { toolCallId: event.toolCallId, transition, resolvedTool });\n return undefined;\n }\n\n // Fire immediately\n state.marking = fire(state.marking, transition);\n state.marking = autoAdvance(net, state.marking);\n\n return undefined;\n}\n\n/**\n * Handle a tool_result event. Fires deferred transitions on success.\n * Returns void (tool_result handler doesn't block).\n */\nexport function handleToolResult<P extends string>(\n event: GateToolResult,\n net: SkillNet<P>,\n state: GateState<P>,\n): void {\n const pending = state.pending.get(event.toolCallId);\n if (!pending) return;\n\n state.pending.delete(event.toolCallId);\n\n if (event.isError) {\n // Tool failed — don't fire the transition, marking unchanged\n return;\n }\n\n // Tool succeeded — fire the deferred transition\n if (canFire(state.marking, pending.transition)) {\n state.marking = fire(state.marking, pending.transition);\n\n // Notify the skill of the successful deferred result\n if (net.onDeferredResult) {\n net.onDeferredResult(\n {\n toolCallId: event.toolCallId,\n input: event.input,\n isError: event.isError,\n },\n pending.resolvedTool,\n pending.transition,\n state,\n );\n }\n\n state.marking = autoAdvance(net, state.marking);\n }\n}\n","import { fire } from \"@petriflow/engine\";\nimport type { GateToolCall, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport {\n getEnabledToolTransitions,\n resolveTool,\n} from \"./gate.js\";\nimport type { GateState } from \"./gate.js\";\nimport { formatBlockReason } from \"./format.js\";\n\n/** Classification of a net's opinion on a tool call */\nexport type NetVerdict<P extends string> = {\n net: SkillNet<P>;\n state: GateState<P>;\n resolvedTool: string;\n} & (\n | { kind: \"free\" }\n | { kind: \"abstain\" }\n | { kind: \"blocked\"; reason: string }\n | { kind: \"gated\"; transition: SkillNet<P>[\"transitions\"][number] }\n);\n\n/** Registry-based config for dynamic net management */\nexport type ComposeConfig = {\n registry: Record<string, SkillNet<string>>;\n active?: string[];\n};\n\n/**\n * Check if a net has jurisdiction over a tool — i.e. the tool appears\n * in at least one transition's tools list (enabled or not).\n */\nfunction hasJurisdiction<P extends string>(\n net: SkillNet<P>,\n resolvedTool: string,\n): boolean {\n return net.transitions.some(\n (t) => t.tools !== undefined && t.tools.includes(resolvedTool),\n );\n}\n\n/**\n * Phase 1 — Structural check (non-mutating).\n * Classify each net as free, gated, blocked, or abstain.\n */\nexport function classifyNets<P extends string>(\n nets: SkillNet<P>[],\n states: GateState<P>[],\n event: { toolName: string; input: Record<string, unknown> },\n): NetVerdict<P>[] {\n return nets.map((net, i) => {\n const state = states[i]!;\n const resolvedTool = resolveTool(net, event);\n const base = { net, state, resolvedTool };\n\n // Free tools always pass\n if (net.freeTools.includes(resolvedTool)) {\n return { ...base, kind: \"free\" as const };\n }\n\n // No jurisdiction → abstain\n if (!hasJurisdiction(net, resolvedTool)) {\n return { ...base, kind: \"abstain\" as const };\n }\n\n // Has jurisdiction — check enabled transitions\n const enabled = getEnabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolvedTool));\n\n if (matching.length === 0) {\n return {\n ...base,\n kind: \"blocked\" as const,\n reason: formatBlockReason(net as SkillNet<string>, resolvedTool),\n };\n }\n\n return { ...base, kind: \"gated\" as const, transition: matching[0]! };\n });\n}\n\n/**\n * 4-phase tool call handler for composed nets.\n */\nexport async function composedToolCall(\n getNets: () => SkillNet<string>[],\n getStates: () => GateState<string>[],\n event: GateToolCall,\n ctx: GateContext,\n): Promise<GateDecision> {\n const nets = getNets();\n const states = getStates();\n\n // --- Phase 1: Structural check ---\n const verdicts = classifyNets(nets, states, {\n toolName: event.toolName,\n input: event.input,\n });\n\n // If any net blocks, reject immediately\n const blocked = verdicts.find((v) => v.kind === \"blocked\");\n if (blocked) {\n return { block: true, reason: blocked.reason };\n }\n\n const gated = verdicts.filter(\n (v): v is Extract<NetVerdict<string>, { kind: \"gated\" }> => v.kind === \"gated\",\n );\n\n // No gated nets → all free/abstain → allow\n if (gated.length === 0) {\n return undefined;\n }\n\n // --- Phase 2: Manual approvals ---\n for (const v of gated) {\n if (v.transition.type === \"manual\") {\n if (!ctx.hasUI) {\n const meta = v.net.ruleMetadata;\n const reason = meta?.kind === \"approval\"\n ? `${meta.tool} requires human approval.`\n : `${v.resolvedTool} requires human approval.`;\n return { block: true, reason };\n }\n const approved = await ctx.confirm(\n `Approve: ${v.transition.name} (${v.net.name})`,\n `Allow '${v.resolvedTool}' via transition '${v.transition.name}' in net '${v.net.name}'?`,\n );\n if (!approved) {\n return {\n block: true,\n reason: `${v.resolvedTool} was rejected by human review.`,\n };\n }\n }\n }\n\n // --- Phase 3: Semantic validation with meta rollback ---\n // Snapshot all meta for rollback\n const metaSnapshots = gated.map((v) => structuredClone(v.state.meta));\n\n for (let i = 0; i < gated.length; i++) {\n const v = gated[i]!;\n if (v.net.validateToolCall) {\n const rejection = v.net.validateToolCall(\n { toolName: event.toolName, input: event.input },\n v.resolvedTool,\n v.transition,\n v.state,\n );\n if (rejection) {\n // Rollback all meta that may have been mutated by earlier validates\n for (let j = 0; j < i; j++) {\n gated[j]!.state.meta = metaSnapshots[j]!;\n }\n return rejection;\n }\n }\n }\n\n // --- Phase 4: Commit ---\n for (const v of gated) {\n if (v.transition.deferred) {\n v.state.pending.set(event.toolCallId, {\n toolCallId: event.toolCallId,\n transition: v.transition,\n resolvedTool: v.resolvedTool,\n });\n } else {\n v.state.marking = fire(v.state.marking, v.transition);\n v.state.marking = autoAdvance(v.net, v.state.marking);\n }\n }\n\n return undefined;\n}\n","import { canFire, fire } from \"@petriflow/engine\";\nimport type { GateToolCall, GateToolResult, GateContext, GateDecision } from \"./events.js\";\nimport type { SkillNet } from \"./types.js\";\nimport type { GateState } from \"./gate.js\";\nimport {\n createGateState,\n formatMarking,\n getEnabledToolTransitions,\n handleToolResult as handleToolResultSingle,\n resolveTool,\n} from \"./gate.js\";\nimport { autoAdvance } from \"./advance.js\";\nimport { composedToolCall } from \"./compose.js\";\nimport type { ComposeConfig } from \"./compose.js\";\n\nexport type ReplayEntry = {\n toolName: string;\n input?: Record<string, unknown>;\n isError: boolean;\n};\n\nexport type GateManager = {\n handleToolCall: (event: GateToolCall, ctx: GateContext) => Promise<GateDecision>;\n handleToolResult: (event: GateToolResult) => void;\n /**\n * Replay a sequence of completed tool results to advance net state.\n * Skips failed results (isError: true). Idempotent — if a transition\n * can't fire (already advanced past it), it is skipped silently.\n * Accepts an array of ReplayEntry objects or plain tool name strings\n * (treated as successful calls).\n */\n replay: (entries: ReplayEntry[] | string[]) => void;\n addNet: (name: string) => { ok: boolean; message: string };\n removeNet: (name: string) => { ok: boolean; message: string };\n getActiveNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string> }>;\n getAllNets: () => Array<{ name: string; net: SkillNet<string>; state: GateState<string>; active: boolean }>;\n formatStatus: () => string;\n formatSystemPrompt: () => string;\n isDynamic: boolean;\n};\n\nexport type GateManagerOptions = {\n /** \"enforce\" blocks disallowed tools. \"shadow\" logs but never blocks. */\n mode: \"enforce\" | \"shadow\";\n /** Called after every gating decision. Use for logging, metrics, debugging. */\n onDecision?: (event: GateToolCall, decision: GateDecision) => void;\n};\n\nexport function createGateManager(input: SkillNet<string>[] | ComposeConfig, opts?: GateManagerOptions): GateManager {\n const manager = Array.isArray(input) ? createArrayManager(input) : createRegistryManager(input);\n\n if (opts) {\n const original = manager.handleToolCall;\n manager.handleToolCall = async (event, ctx) => {\n const decision = await original.call(manager, event, ctx);\n opts.onDecision?.(event, decision);\n if (opts.mode === \"shadow\" && decision?.block) {\n return undefined;\n }\n return decision;\n };\n }\n\n return manager;\n}\n\nfunction normalizeEntries(entries: ReplayEntry[] | string[]): ReplayEntry[] {\n if (entries.length === 0) return [];\n if (typeof entries[0] === \"string\") {\n return (entries as string[]).map((toolName) => ({ toolName, isError: false }));\n }\n return entries as ReplayEntry[];\n}\n\nfunction replayNets(\n nets: SkillNet<string>[],\n states: GateState<string>[],\n entries: ReplayEntry[],\n): void {\n for (const entry of entries) {\n if (entry.isError) continue;\n for (let i = 0; i < nets.length; i++) {\n const net = nets[i]!;\n const state = states[i]!;\n const resolved = resolveTool(net, { toolName: entry.toolName, input: entry.input ?? {} });\n\n if (net.freeTools.includes(resolved)) continue;\n\n const enabled = getEnabledToolTransitions(net, state.marking);\n const matching = enabled.filter((t) => t.tools!.includes(resolved));\n if (matching.length === 0) continue;\n\n const transition = matching[0]!;\n if (canFire(state.marking, transition)) {\n state.marking = fire(state.marking, transition);\n\n if (transition.deferred && net.onDeferredResult) {\n net.onDeferredResult(\n { toolCallId: `replay-${i}`, input: entry.input ?? {}, isError: false },\n resolved,\n transition,\n state,\n );\n }\n\n state.marking = autoAdvance(net, state.marking);\n }\n }\n }\n}\n\nfunction createArrayManager(nets: SkillNet<string>[]): GateManager {\n const states = nets.map((net) =>\n createGateState(autoAdvance(net, { ...net.initialMarking })),\n );\n\n const getNets = () => nets;\n const getStates = () => states;\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getNets, getStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (let i = 0; i < nets.length; i++) {\n handleToolResultSingle(event, nets[i]!, states[i]!);\n }\n },\n\n replay(entries) {\n replayNets(nets, states, normalizeEntries(entries));\n },\n\n addNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n removeNet() {\n return { ok: false, message: \"Static composition does not support dynamic nets\" };\n },\n\n getActiveNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]! }));\n },\n\n getAllNets() {\n return nets.map((net, i) => ({ name: net.name, net, state: states[i]!, active: true }));\n },\n\n formatStatus() {\n return nets\n .map((n, i) => `${n.name}: ${formatMarking(states[i]!.marking)}`)\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(nets, states);\n },\n\n isDynamic: false,\n };\n}\n\nfunction createRegistryManager(config: ComposeConfig): GateManager {\n const registry = new Map<string, { net: SkillNet<string>; state: GateState<string> }>();\n for (const [name, net] of Object.entries(config.registry)) {\n registry.set(name, {\n net,\n state: createGateState(autoAdvance(net, { ...net.initialMarking })),\n });\n }\n\n const activeNames = new Set<string>(config.active ?? Object.keys(config.registry));\n\n const getActiveNets = () => [...activeNames].map((n) => registry.get(n)!.net);\n const getActiveStates = () => [...activeNames].map((n) => registry.get(n)!.state);\n\n return {\n handleToolCall(event, ctx) {\n return composedToolCall(getActiveNets, getActiveStates, event, ctx);\n },\n\n handleToolResult(event) {\n for (const { net, state } of registry.values()) {\n handleToolResultSingle(event, net, state);\n }\n },\n\n replay(entries) {\n const activeNets = getActiveNets();\n const activeStates = getActiveStates();\n replayNets(activeNets, activeStates, normalizeEntries(entries));\n },\n\n addNet(name) {\n if (!registry.has(name)) {\n return { ok: false, message: `Unknown net '${name}'. Available: ${[...registry.keys()].join(\", \")}` };\n }\n if (activeNames.has(name)) {\n return { ok: false, message: `'${name}' is already active` };\n }\n activeNames.add(name);\n return { ok: true, message: `Activated '${name}'` };\n },\n\n removeNet(name) {\n if (!activeNames.has(name)) {\n return { ok: false, message: `'${name}' is not active. Active: ${[...activeNames].join(\", \")}` };\n }\n activeNames.delete(name);\n return { ok: true, message: `Deactivated '${name}' (state preserved)` };\n },\n\n getActiveNets() {\n return [...activeNames].map((name) => {\n const entry = registry.get(name)!;\n return { name, net: entry.net, state: entry.state };\n });\n },\n\n getAllNets() {\n return [...registry.entries()].map(([name, { net, state }]) => ({\n name,\n net,\n state,\n active: activeNames.has(name),\n }));\n },\n\n formatStatus() {\n return [...registry.entries()]\n .map(([name, { state }]) => {\n const status = activeNames.has(name) ? \"active\" : \"inactive\";\n return `${name} (${status}): ${formatMarking(state.marking)}`;\n })\n .join(\"\\n\");\n },\n\n formatSystemPrompt() {\n return formatPromptForNets(getActiveNets(), getActiveStates());\n },\n\n isDynamic: true,\n };\n}\n\nfunction formatPromptForNets(nets: SkillNet<string>[], states: GateState<string>[]): string {\n const sections = nets.map((net, i) => {\n const enabled = getEnabledToolTransitions(net, states[i]!.marking);\n const toolList = enabled.flatMap((t) => t.tools ?? []);\n return `### ${net.name}\\nAvailable gated tools: ${toolList.join(\", \") || \"none\"}\\nFree tools: ${net.freeTools.join(\", \")}\\nState: ${formatMarking(states[i]!.marking)}`;\n });\n return `## Active Petri Nets (composed)\\n${sections.join(\"\\n\\n\")}`;\n}\n"],"mappings":";AA4EO,SAAS,eACd,KACiB;AACjB,SAAO;AACT;;;ACnEO,SAAS,kBACd,KACA,cACQ;AACR,QAAM,OAAO,IAAI;AAEjB,MAAI,MAAM;AACR,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO,GAAG,KAAK,SAAS,kCAAkC,KAAK,YAAY;AAAA,MAC7E,KAAK;AACH,eAAO,KAAK,UAAU,YAClB,GAAG,KAAK,IAAI,6BAA6B,KAAK,KAAK,wBACnD,GAAG,KAAK,IAAI,6BAA6B,KAAK,KAAK,cAAc,KAAK,KAAK;AAAA,MACjF,KAAK;AACH,eAAO,GAAG,KAAK,IAAI;AAAA,MACrB,KAAK;AACH,eAAO,GAAG,KAAK,IAAI;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,SAAS,YAAY;AAC9B;;;ACnCA,SAAS,SAAS,YAAY;AAK9B,SAAS,aAA+B,GAAgC;AACtE,SAAO,EAAE,SAAS,WAAW,EAAE,UAAU,UAAa,EAAE,MAAM,WAAW;AAC3E;AAOA,SAAS,iBACP,GACA,GACA,SACS;AACT,aAAW,SAAS,EAAE,QAAQ;AAC5B,QAAI,EAAE,OAAO,SAAS,KAAK,GAAG;AAE5B,YAAM,SAAS,EAAE,OAAO,OAAO,CAAC,MAAM,MAAM,KAAK,EAAE;AACnD,YAAM,SAAS,EAAE,OAAO,OAAO,CAAC,MAAM,MAAM,KAAK,EAAE;AACnD,WAAK,QAAQ,KAAK,KAAK,KAAK,SAAS,OAAQ,QAAO;AAAA,IACtD;AAAA,EACF;AACA,SAAO;AACT;AASO,SAAS,YACd,KACA,SACY;AACZ,MAAI,UAAU,EAAE,GAAG,QAAQ;AAE3B,aAAS;AACP,UAAM,aAAa,IAAI,YAAY;AAAA,MACjC,CAAC,MAAM,aAAa,CAAC,KAAK,QAAQ,SAAS,CAAC;AAAA,IAC9C;AACA,QAAI,WAAW,WAAW,EAAG;AAG7B,UAAM,cAAc,WAAW;AAAA,MAAO,CAAC,MACrC,WAAW,MAAM,CAAC,UAAU,UAAU,KAAK,CAAC,iBAAiB,GAAG,OAAO,OAAO,CAAC;AAAA,IACjF;AACA,QAAI,YAAY,WAAW,EAAG;AAE9B,eAAW,KAAK,aAAa;AAE3B,UAAI,QAAQ,SAAS,CAAC,GAAG;AACvB,kBAAU,KAAK,SAAS,CAAC;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AChEA,SAAS,WAAAA,UAAS,QAAAC,aAAY;AAQvB,SAAS,YACd,KACA,OACQ;AACR,MAAI,IAAI,YAAY;AAClB,WAAO,IAAI,WAAW;AAAA,MACpB,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,IACf,CAAC;AAAA,EACH;AACA,SAAO,MAAM;AACf;AAGA,SAAS,uBACP,KACA,SACsB;AACtB,SAAO,IAAI,YAAY;AAAA,IACrB,CAAC,MAAM,EAAE,UAAU,UAAa,EAAE,MAAM,SAAS,KAAKC,SAAQ,SAAS,CAAC;AAAA,EAC1E;AACF;AAGO,SAAS,0BACd,KACA,SACsB;AACtB,SAAO,uBAAuB,KAAK,OAAO;AAC5C;AAGO,SAAS,cAAgC,SAA6B;AAC3E,SAAO,OAAO,QAAQ,OAAO,EAC1B,OAAO,CAAC,CAAC,EAAE,CAAC,MAAO,IAAe,CAAC,EACnC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,EAC3B,KAAK,IAAI;AACd;AAiBO,SAAS,gBAAkC,SAAmC;AACnF,SAAO,EAAE,SAAS,MAAM,CAAC,GAAG,SAAS,oBAAI,IAAI,EAAE;AACjD;AAOA,eAAsB,eACpB,OACA,KACA,KACA,OACuB;AACvB,QAAM,eAAe,YAAY,KAAK,KAAK;AAG3C,MAAI,IAAI,UAAU,SAAS,YAAY,GAAG;AACxC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,uBAAuB,KAAK,MAAM,OAAO;AACzD,QAAM,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,MAAO,SAAS,YAAY,CAAC;AAEtE,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,kBAAkB,KAAyB,YAAY;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,aAAa,SAAS,CAAC;AAG7B,MAAI,IAAI,kBAAkB;AACxB,UAAM,YAAY,IAAI;AAAA,MACpB,EAAE,UAAU,MAAM,UAAU,OAAO,MAAM,MAAM;AAAA,MAC/C;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,UAAW,QAAO;AAAA,EACxB;AAEA,MAAI,WAAW,SAAS,UAAU;AAChC,QAAI,CAAC,IAAI,OAAO;AACd,YAAM,OAAO,IAAI;AACjB,YAAM,SAAS,MAAM,SAAS,aAC1B,GAAG,KAAK,IAAI,8BACZ,GAAG,YAAY;AACnB,aAAO,EAAE,OAAO,MAAM,OAAO;AAAA,IAC/B;AACA,UAAM,WAAW,MAAM,IAAI;AAAA,MACzB,YAAY,WAAW,IAAI;AAAA,MAC3B,UAAU,YAAY,qBAAqB,WAAW,IAAI;AAAA,IAC5D;AACA,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,OAAO,MAAM,QAAQ,GAAG,YAAY,iCAAiC;AAAA,IAChF;AAAA,EACF;AAEA,MAAI,WAAW,UAAU;AAEvB,UAAM,QAAQ,IAAI,MAAM,YAAY,EAAE,YAAY,MAAM,YAAY,YAAY,aAAa,CAAC;AAC9F,WAAO;AAAA,EACT;AAGA,QAAM,UAAUC,MAAK,MAAM,SAAS,UAAU;AAC9C,QAAM,UAAU,YAAY,KAAK,MAAM,OAAO;AAE9C,SAAO;AACT;AAMO,SAAS,iBACd,OACA,KACA,OACM;AACN,QAAM,UAAU,MAAM,QAAQ,IAAI,MAAM,UAAU;AAClD,MAAI,CAAC,QAAS;AAEd,QAAM,QAAQ,OAAO,MAAM,UAAU;AAErC,MAAI,MAAM,SAAS;AAEjB;AAAA,EACF;AAGA,MAAID,SAAQ,MAAM,SAAS,QAAQ,UAAU,GAAG;AAC9C,UAAM,UAAUC,MAAK,MAAM,SAAS,QAAQ,UAAU;AAGtD,QAAI,IAAI,kBAAkB;AACxB,UAAI;AAAA,QACF;AAAA,UACE,YAAY,MAAM;AAAA,UAClB,OAAO,MAAM;AAAA,UACb,SAAS,MAAM;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,YAAY,KAAK,MAAM,OAAO;AAAA,EAChD;AACF;;;AChLA,SAAS,QAAAC,aAAY;AAiCrB,SAAS,gBACP,KACA,cACS;AACT,SAAO,IAAI,YAAY;AAAA,IACrB,CAAC,MAAM,EAAE,UAAU,UAAa,EAAE,MAAM,SAAS,YAAY;AAAA,EAC/D;AACF;AAMO,SAAS,aACd,MACA,QACA,OACiB;AACjB,SAAO,KAAK,IAAI,CAAC,KAAK,MAAM;AAC1B,UAAM,QAAQ,OAAO,CAAC;AACtB,UAAM,eAAe,YAAY,KAAK,KAAK;AAC3C,UAAM,OAAO,EAAE,KAAK,OAAO,aAAa;AAGxC,QAAI,IAAI,UAAU,SAAS,YAAY,GAAG;AACxC,aAAO,EAAE,GAAG,MAAM,MAAM,OAAgB;AAAA,IAC1C;AAGA,QAAI,CAAC,gBAAgB,KAAK,YAAY,GAAG;AACvC,aAAO,EAAE,GAAG,MAAM,MAAM,UAAmB;AAAA,IAC7C;AAGA,UAAM,UAAU,0BAA0B,KAAK,MAAM,OAAO;AAC5D,UAAM,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,MAAO,SAAS,YAAY,CAAC;AAEtE,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,QAAQ,kBAAkB,KAAyB,YAAY;AAAA,MACjE;AAAA,IACF;AAEA,WAAO,EAAE,GAAG,MAAM,MAAM,SAAkB,YAAY,SAAS,CAAC,EAAG;AAAA,EACrE,CAAC;AACH;AAKA,eAAsB,iBACpB,SACA,WACA,OACA,KACuB;AACvB,QAAM,OAAO,QAAQ;AACrB,QAAM,SAAS,UAAU;AAGzB,QAAM,WAAW,aAAa,MAAM,QAAQ;AAAA,IAC1C,UAAU,MAAM;AAAA,IAChB,OAAO,MAAM;AAAA,EACf,CAAC;AAGD,QAAM,UAAU,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS;AACzD,MAAI,SAAS;AACX,WAAO,EAAE,OAAO,MAAM,QAAQ,QAAQ,OAAO;AAAA,EAC/C;AAEA,QAAM,QAAQ,SAAS;AAAA,IACrB,CAAC,MAA2D,EAAE,SAAS;AAAA,EACzE;AAGA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAGA,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,WAAW,SAAS,UAAU;AAClC,UAAI,CAAC,IAAI,OAAO;AACd,cAAM,OAAO,EAAE,IAAI;AACnB,cAAM,SAAS,MAAM,SAAS,aAC1B,GAAG,KAAK,IAAI,8BACZ,GAAG,EAAE,YAAY;AACrB,eAAO,EAAE,OAAO,MAAM,OAAO;AAAA,MAC/B;AACA,YAAM,WAAW,MAAM,IAAI;AAAA,QACzB,YAAY,EAAE,WAAW,IAAI,KAAK,EAAE,IAAI,IAAI;AAAA,QAC5C,UAAU,EAAE,YAAY,qBAAqB,EAAE,WAAW,IAAI,aAAa,EAAE,IAAI,IAAI;AAAA,MACvF;AACA,UAAI,CAAC,UAAU;AACb,eAAO;AAAA,UACL,OAAO;AAAA,UACP,QAAQ,GAAG,EAAE,YAAY;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAIA,QAAM,gBAAgB,MAAM,IAAI,CAAC,MAAM,gBAAgB,EAAE,MAAM,IAAI,CAAC;AAEpE,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,IAAI,MAAM,CAAC;AACjB,QAAI,EAAE,IAAI,kBAAkB;AAC1B,YAAM,YAAY,EAAE,IAAI;AAAA,QACtB,EAAE,UAAU,MAAM,UAAU,OAAO,MAAM,MAAM;AAAA,QAC/C,EAAE;AAAA,QACF,EAAE;AAAA,QACF,EAAE;AAAA,MACJ;AACA,UAAI,WAAW;AAEb,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,gBAAM,CAAC,EAAG,MAAM,OAAO,cAAc,CAAC;AAAA,QACxC;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,WAAW,UAAU;AACzB,QAAE,MAAM,QAAQ,IAAI,MAAM,YAAY;AAAA,QACpC,YAAY,MAAM;AAAA,QAClB,YAAY,EAAE;AAAA,QACd,cAAc,EAAE;AAAA,MAClB,CAAC;AAAA,IACH,OAAO;AACL,QAAE,MAAM,UAAUC,MAAK,EAAE,MAAM,SAAS,EAAE,UAAU;AACpD,QAAE,MAAM,UAAU,YAAY,EAAE,KAAK,EAAE,MAAM,OAAO;AAAA,IACtD;AAAA,EACF;AAEA,SAAO;AACT;;;AChLA,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAgDvB,SAAS,kBAAkB,OAA2C,MAAwC;AACnH,QAAM,UAAU,MAAM,QAAQ,KAAK,IAAI,mBAAmB,KAAK,IAAI,sBAAsB,KAAK;AAE9F,MAAI,MAAM;AACR,UAAM,WAAW,QAAQ;AACzB,YAAQ,iBAAiB,OAAO,OAAO,QAAQ;AAC7C,YAAM,WAAW,MAAM,SAAS,KAAK,SAAS,OAAO,GAAG;AACxD,WAAK,aAAa,OAAO,QAAQ;AACjC,UAAI,KAAK,SAAS,YAAY,UAAU,OAAO;AAC7C,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,iBAAiB,SAAkD;AAC1E,MAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAClC,MAAI,OAAO,QAAQ,CAAC,MAAM,UAAU;AAClC,WAAQ,QAAqB,IAAI,CAAC,cAAc,EAAE,UAAU,SAAS,MAAM,EAAE;AAAA,EAC/E;AACA,SAAO;AACT;AAEA,SAAS,WACP,MACA,QACA,SACM;AACN,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,QAAS;AACnB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,QAAQ,OAAO,CAAC;AACtB,YAAM,WAAW,YAAY,KAAK,EAAE,UAAU,MAAM,UAAU,OAAO,MAAM,SAAS,CAAC,EAAE,CAAC;AAExF,UAAI,IAAI,UAAU,SAAS,QAAQ,EAAG;AAEtC,YAAM,UAAU,0BAA0B,KAAK,MAAM,OAAO;AAC5D,YAAM,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,MAAO,SAAS,QAAQ,CAAC;AAClE,UAAI,SAAS,WAAW,EAAG;AAE3B,YAAM,aAAa,SAAS,CAAC;AAC7B,UAAIC,SAAQ,MAAM,SAAS,UAAU,GAAG;AACtC,cAAM,UAAUC,MAAK,MAAM,SAAS,UAAU;AAE9C,YAAI,WAAW,YAAY,IAAI,kBAAkB;AAC/C,cAAI;AAAA,YACF,EAAE,YAAY,UAAU,CAAC,IAAI,OAAO,MAAM,SAAS,CAAC,GAAG,SAAS,MAAM;AAAA,YACtE;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAEA,cAAM,UAAU,YAAY,KAAK,MAAM,OAAO;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,MAAuC;AACjE,QAAM,SAAS,KAAK;AAAA,IAAI,CAAC,QACvB,gBAAgB,YAAY,KAAK,EAAE,GAAG,IAAI,eAAe,CAAC,CAAC;AAAA,EAC7D;AAEA,QAAM,UAAU,MAAM;AACtB,QAAM,YAAY,MAAM;AAExB,SAAO;AAAA,IACL,eAAe,OAAO,KAAK;AACzB,aAAO,iBAAiB,SAAS,WAAW,OAAO,GAAG;AAAA,IACxD;AAAA,IAEA,iBAAiB,OAAO;AACtB,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,yBAAuB,OAAO,KAAK,CAAC,GAAI,OAAO,CAAC,CAAE;AAAA,MACpD;AAAA,IACF;AAAA,IAEA,OAAO,SAAS;AACd,iBAAW,MAAM,QAAQ,iBAAiB,OAAO,CAAC;AAAA,IACpD;AAAA,IAEA,SAAS;AACP,aAAO,EAAE,IAAI,OAAO,SAAS,mDAAmD;AAAA,IAClF;AAAA,IAEA,YAAY;AACV,aAAO,EAAE,IAAI,OAAO,SAAS,mDAAmD;AAAA,IAClF;AAAA,IAEA,gBAAgB;AACd,aAAO,KAAK,IAAI,CAAC,KAAK,OAAO,EAAE,MAAM,IAAI,MAAM,KAAK,OAAO,OAAO,CAAC,EAAG,EAAE;AAAA,IAC1E;AAAA,IAEA,aAAa;AACX,aAAO,KAAK,IAAI,CAAC,KAAK,OAAO,EAAE,MAAM,IAAI,MAAM,KAAK,OAAO,OAAO,CAAC,GAAI,QAAQ,KAAK,EAAE;AAAA,IACxF;AAAA,IAEA,eAAe;AACb,aAAO,KACJ,IAAI,CAAC,GAAG,MAAM,GAAG,EAAE,IAAI,KAAK,cAAc,OAAO,CAAC,EAAG,OAAO,CAAC,EAAE,EAC/D,KAAK,IAAI;AAAA,IACd;AAAA,IAEA,qBAAqB;AACnB,aAAO,oBAAoB,MAAM,MAAM;AAAA,IACzC;AAAA,IAEA,WAAW;AAAA,EACb;AACF;AAEA,SAAS,sBAAsB,QAAoC;AACjE,QAAM,WAAW,oBAAI,IAAiE;AACtF,aAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,OAAO,QAAQ,GAAG;AACzD,aAAS,IAAI,MAAM;AAAA,MACjB;AAAA,MACA,OAAO,gBAAgB,YAAY,KAAK,EAAE,GAAG,IAAI,eAAe,CAAC,CAAC;AAAA,IACpE,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,IAAI,IAAY,OAAO,UAAU,OAAO,KAAK,OAAO,QAAQ,CAAC;AAEjF,QAAM,gBAAgB,MAAM,CAAC,GAAG,WAAW,EAAE,IAAI,CAAC,MAAM,SAAS,IAAI,CAAC,EAAG,GAAG;AAC5E,QAAM,kBAAkB,MAAM,CAAC,GAAG,WAAW,EAAE,IAAI,CAAC,MAAM,SAAS,IAAI,CAAC,EAAG,KAAK;AAEhF,SAAO;AAAA,IACL,eAAe,OAAO,KAAK;AACzB,aAAO,iBAAiB,eAAe,iBAAiB,OAAO,GAAG;AAAA,IACpE;AAAA,IAEA,iBAAiB,OAAO;AACtB,iBAAW,EAAE,KAAK,MAAM,KAAK,SAAS,OAAO,GAAG;AAC9C,yBAAuB,OAAO,KAAK,KAAK;AAAA,MAC1C;AAAA,IACF;AAAA,IAEA,OAAO,SAAS;AACd,YAAM,aAAa,cAAc;AACjC,YAAM,eAAe,gBAAgB;AACrC,iBAAW,YAAY,cAAc,iBAAiB,OAAO,CAAC;AAAA,IAChE;AAAA,IAEA,OAAO,MAAM;AACX,UAAI,CAAC,SAAS,IAAI,IAAI,GAAG;AACvB,eAAO,EAAE,IAAI,OAAO,SAAS,gBAAgB,IAAI,iBAAiB,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG;AAAA,MACtG;AACA,UAAI,YAAY,IAAI,IAAI,GAAG;AACzB,eAAO,EAAE,IAAI,OAAO,SAAS,IAAI,IAAI,sBAAsB;AAAA,MAC7D;AACA,kBAAY,IAAI,IAAI;AACpB,aAAO,EAAE,IAAI,MAAM,SAAS,cAAc,IAAI,IAAI;AAAA,IACpD;AAAA,IAEA,UAAU,MAAM;AACd,UAAI,CAAC,YAAY,IAAI,IAAI,GAAG;AAC1B,eAAO,EAAE,IAAI,OAAO,SAAS,IAAI,IAAI,4BAA4B,CAAC,GAAG,WAAW,EAAE,KAAK,IAAI,CAAC,GAAG;AAAA,MACjG;AACA,kBAAY,OAAO,IAAI;AACvB,aAAO,EAAE,IAAI,MAAM,SAAS,gBAAgB,IAAI,sBAAsB;AAAA,IACxE;AAAA,IAEA,gBAAgB;AACd,aAAO,CAAC,GAAG,WAAW,EAAE,IAAI,CAAC,SAAS;AACpC,cAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,eAAO,EAAE,MAAM,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,IAEA,aAAa;AACX,aAAO,CAAC,GAAG,SAAS,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,MAAM,CAAC,OAAO;AAAA,QAC9D;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,YAAY,IAAI,IAAI;AAAA,MAC9B,EAAE;AAAA,IACJ;AAAA,IAEA,eAAe;AACb,aAAO,CAAC,GAAG,SAAS,QAAQ,CAAC,EAC1B,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM;AAC1B,cAAM,SAAS,YAAY,IAAI,IAAI,IAAI,WAAW;AAClD,eAAO,GAAG,IAAI,KAAK,MAAM,MAAM,cAAc,MAAM,OAAO,CAAC;AAAA,MAC7D,CAAC,EACA,KAAK,IAAI;AAAA,IACd;AAAA,IAEA,qBAAqB;AACnB,aAAO,oBAAoB,cAAc,GAAG,gBAAgB,CAAC;AAAA,IAC/D;AAAA,IAEA,WAAW;AAAA,EACb;AACF;AAEA,SAAS,oBAAoB,MAA0B,QAAqC;AAC1F,QAAM,WAAW,KAAK,IAAI,CAAC,KAAK,MAAM;AACpC,UAAM,UAAU,0BAA0B,KAAK,OAAO,CAAC,EAAG,OAAO;AACjE,UAAM,WAAW,QAAQ,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AACrD,WAAO,OAAO,IAAI,IAAI;AAAA,yBAA4B,SAAS,KAAK,IAAI,KAAK,MAAM;AAAA,cAAiB,IAAI,UAAU,KAAK,IAAI,CAAC;AAAA,SAAY,cAAc,OAAO,CAAC,EAAG,OAAO,CAAC;AAAA,EACvK,CAAC;AACD,SAAO;AAAA,EAAoC,SAAS,KAAK,MAAM,CAAC;AAClE;","names":["canFire","fire","canFire","fire","fire","fire","canFire","fire","canFire","fire"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@petriflow/gate",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",