@kaged/plugin-host

JSON-RPC stdio transport, plugin process lifecycle with health checks and rate limiting, multi-plugin supervisor with role enforcement and tool registry

15
source files
14
test files
~7.4k
lines
✓ 322 pass
tests
pass
typecheck
clean
lint

Test results 322

parseCapability: filesystem > read:fs parses correctly [0.150ms]
parseCapability: filesystem > write:fs parses correctly [0.030ms]
parseCapability: filesystem > read:fs rejects relative path [0.100ms]
parseCapability: filesystem > write:fs rejects relative path [0.050ms]
parseCapability: exec > exec parses correctly [0.040ms]
parseCapability: exec > exec with full binary path [0.030ms]
parseCapability: exec > exec rejects missing path [0.040ms]
parseCapability: exec > exec rejects relative path [0.030ms]
parseCapability: exec > exec rejects empty binary [0.030ms]
parseCapability: net > net:[] → none [0.030ms]
parseCapability: net > net:* → all [0.020ms]
parseCapability: net > net:host:port → host_port [0.090ms]
parseCapability: net > net:host:* → host_all [0.030ms]
parseCapability: net > net rejects invalid port [0.030ms]
parseCapability: net > net rejects port 0 [0.030ms]
parseCapability: net > net rejects port 70000 [0.040ms]
parseCapability: net > net rejects empty host [0.060ms]
parseCapability: storage > kaged:storage:read [0.020ms]
parseCapability: storage > kaged:storage:write [0.010ms]
parseCapability: unrecognized > unknown format throws [0.030ms]
parseCapability: unrecognized > error includes the offending capability string [0.050ms]
parseCapabilities > parses array of capabilities [0.110ms]
parseCapabilities > empty array returns empty [0.020ms]
validateCapabilitiesUsed > all used capabilities are declared → empty violations [0.090ms]
validateCapabilitiesUsed > extra used capabilities → returns violations [0.020ms]
validateCapabilitiesUsed > empty used → no violations [0.020ms]
validateCapabilitiesUsed > empty declared, non-empty used → all are violations [0.020ms]
mergePluginConfig > merges disjoint project and system config [1.29ms]
mergePluginConfig > empty configs merge to empty object [0.080ms]
mergePluginConfig > project-only config (no system schema) passes through [0.050ms]
mergePluginConfig > system-only config (no project schema) passes through [0.040ms]
mergePluginConfig > rejects project config containing system-only fields [0.070ms]
mergePluginConfig > multiple system-only fields in project config produce multiple errors [0.090ms]
mergePluginConfig > system config fields not in system schema are still merged [0.050ms]
mergePluginConfig > system config values take precedence over project config for non-system-schema fields [0.040ms]
mergePluginConfigWithAgentOverrides > agent overrides project config fields [0.110ms]
mergePluginConfigWithAgentOverrides > empty agent overrides preserves base config [0.040ms]
mergePluginConfigWithAgentOverrides > rejects agent overrides that touch system config fields [0.050ms]
mergePluginConfigWithAgentOverrides > agent overrides add new project-side fields [0.040ms]
JsonRpcConnection: sendRequest > sends valid JSON-RPC request with incrementing ids [2.32ms]
JsonRpcConnection: sendRequest > resolves when response arrives [0.680ms]
JsonRpcConnection: sendRequest > rejects on error response [0.280ms]
JsonRpcConnection: sendRequest > rejects on timeout [51.42ms]
JsonRpcConnection: sendRequest > rejects when connection is closed [0.160ms]
JsonRpcConnection: sendNotification > sends notification without id [0.130ms]
JsonRpcConnection: sendNotification > skips sending when closed [0.050ms]
JsonRpcConnection: sendResponse > sends success response [0.180ms]
JsonRpcConnection: sendErrorResponse > sends error response [0.150ms]
JsonRpcConnection: incoming message routing > routes notifications to onNotification callback [10.36ms]
JsonRpcConnection: incoming message routing > routes requests to onRequest callback [11.91ms]
JsonRpcConnection: incoming message routing > reports protocol error for batch messages [12.22ms]
JsonRpcConnection: incoming message routing > reports protocol error for invalid JSON [10.88ms]
JsonRpcConnection: incoming message routing > reports protocol error for response with unknown id [12.23ms]
JsonRpcConnection: multi-line buffering > handles multiple messages in one chunk [12.40ms]
JsonRpcConnection: multi-line buffering > handles message split across chunks [17.86ms]
JsonRpcConnection: multi-line buffering > skips empty lines [12.20ms]
JsonRpcConnection: oversize message rejection > rejects messages exceeding max size [10.87ms]
JsonRpcConnection: close behavior > isClosed returns true after close() [0.360ms]
JsonRpcConnection: close behavior > close() rejects pending requests [0.590ms]
JsonRpcConnection: close behavior > close() is idempotent [0.200ms]
JsonRpcConnection: close behavior > stream close triggers onClose and rejects pending [0.640ms]
JsonRpcConnection: concurrent requests > routes responses to correct pending requests [1.18ms]
validateKnobValue — range > accepts value within bounds [0.460ms]
validateKnobValue — range > accepts min boundary [0.070ms]
validateKnobValue — range > accepts max boundary [0.060ms]
validateKnobValue — range > rejects below min [0.300ms]
validateKnobValue — range > rejects above max [0.080ms]
validateKnobValue — range > rejects non-number [0.080ms]
validateKnobValue — range > rejects NaN [0.060ms]
validateKnobValue — range > rejects invalid step [0.070ms]
validateKnobValue — range > accepts valid step 0.3 [0.080ms]
validateKnobValue — int_range > accepts integer within bounds [0.210ms]
validateKnobValue — int_range > rejects float [0.110ms]
validateKnobValue — int_range > rejects below min [0.090ms]
validateKnobValue — int_range > rejects above max [0.060ms]
validateKnobValue — int_range > rejects non-number [0.060ms]
validateKnobValue — int_range > validates step alignment [0.120ms]
validateKnobValue — enum > accepts valid value [0.190ms]
validateKnobValue — enum > rejects invalid value [0.080ms]
validateKnobValue — enum > rejects non-string [0.060ms]
validateKnobValue — boolean > accepts true [0.100ms]
validateKnobValue — boolean > accepts false [0.040ms]
validateKnobValue — boolean > rejects string 'true' [0.080ms]
validateKnobValue — text > accepts valid short lowercase string [0.240ms]
validateKnobValue — text > rejects exceeding max_length [0.080ms]
validateKnobValue — text > rejects pattern mismatch [0.070ms]
validateKnobValue — text > rejects non-string [0.050ms]
validateKnobValue — text > text without constraints accepts any string [0.080ms]
validateKnobValue — multiline > accepts multiline string [0.120ms]
validateKnobValue — multiline > rejects exceeding max_length [0.090ms]
validateKnobValue — multiline > rejects non-string [0.060ms]
validateKnobValue — model_alias > accepts null [0.110ms]
validateKnobValue — model_alias > accepts valid string [0.070ms]
validateKnobValue — model_alias > rejects empty string [0.070ms]
validateKnobValue — model_alias > rejects non-string non-null [0.060ms]
validateKnobValue — path > accepts config: prefix [0.310ms]
validateKnobValue — path > accepts project: prefix [0.070ms]
validateKnobValue — path > rejects other prefix [0.110ms]
validateKnobValue — path > rejects non-string [0.070ms]
validateKnobValue — path > path without prefixes constraint accepts anything [0.070ms]
validateAllKnobValues > validates all values successfully [0.270ms]
validateAllKnobValues > collects multiple errors [0.110ms]
validateAllKnobValues > reports unknown knob names [0.090ms]
validateAllKnobValues > empty values returns no errors [0.070ms]
parseManifest: roles field (ADR-0024) > accepts roles: [observer] [45.11ms]
parseManifest: roles field (ADR-0024) > accepts roles: [observer, compactor] [3.58ms]
parseManifest: roles field (ADR-0024) > defaults roles to [observer] when hooks is non-empty and roles omitted [2.52ms]
parseManifest: roles field (ADR-0024) > defaults roles to [] when no hooks are subscribed [2.05ms]
parseManifest: roles field (ADR-0024) > rejects unknown role [3.56ms]
parseManifest: roles field (ADR-0024) > rejects compactor role without pre_compact hook subscription [2.04ms]
parseManifest: roles field (ADR-0024) > rejects duplicate roles [1.18ms]
parseManifest: hooks field (ADR-0023) > accepts on_session_start [0.720ms]
parseManifest: hooks field (ADR-0023) > accepts on_session_idle [0.640ms]
parseManifest: hooks field (ADR-0023) > accepts pre_compact [0.600ms]
parseManifest: hooks field (ADR-0023) > accepts all four hooks together [0.660ms]
parseManifest: hooks field (ADR-0023) > defaults hooks to [] when omitted [0.590ms]
parseManifest: hooks field (ADR-0023) > rejects unknown hook name [0.620ms]
parseManifest: hooks field (ADR-0023) > rejects duplicate hook entries [0.670ms]
parseManifest: tools field (ADR-0023) > accepts tools declaration [2.44ms]
parseManifest: tools field (ADR-0023) > defaults tools to [] when omitted [0.550ms]
parseManifest: tools field (ADR-0023) > rejects tool name with uppercase [0.800ms]
parseManifest: tools field (ADR-0023) > rejects tool name with dots (must be single segment; prefix is applied at registration) [0.890ms]
parseManifest: tools field (ADR-0023) > rejects duplicate tool names within same manifest [0.930ms]
parseManifest: tools field (ADR-0023) > rejects tool missing required parameters_schema [0.600ms]
parseManifest: methods optional when tools or hooks present (ADR-0023) > methods empty + tools non-empty is OK [0.740ms]
parseManifest: methods optional when tools or hooks present (ADR-0023) > methods empty + hooks non-empty is OK [0.510ms]
parseManifest: methods optional when tools or hooks present (ADR-0023) > methods omitted + tools non-empty is OK [0.610ms]
parseManifest: system_config_schema (ADR-0023) > accepts system_config_schema [0.730ms]
parseManifest: system_config_schema (ADR-0023) > defaults systemConfigSchema to undefined when omitted [0.460ms]
parseManifest: system_config_schema (ADR-0023) > rejects field-name collision between config_schema and system_config_schema [0.870ms]
parseManifest: knobs (ADR-0024) > accepts knob with type=range [1.33ms]
parseManifest: knobs (ADR-0024) > accepts knob with type=enum + labels map [1.06ms]
parseManifest: knobs (ADR-0024) > accepts knob with type=int_range [0.890ms]
parseManifest: knobs (ADR-0024) > accepts knob with type=boolean [0.820ms]
parseManifest: knobs (ADR-0024) > accepts knob with type=text [0.800ms]
parseManifest: knobs (ADR-0024) > accepts knob with type=path + prefixes [0.890ms]
parseManifest: knobs (ADR-0024) > accepts knob with type=model_alias [0.830ms]
parseManifest: knobs (ADR-0024) > rejects knob with unknown type [0.900ms]
parseManifest: knobs (ADR-0024) > rejects knob with binds_to referencing a non-existent config_schema field [0.980ms]
parseManifest: knobs (ADR-0024) > rejects knob with binds_to pointing into system_config_schema [1.10ms]
parseManifest: knobs (ADR-0024) > rejects knob with binds_to that does not start with 'config.' [0.890ms]
parseManifest: knobs (ADR-0024) > defaults knobs to empty record when omitted [0.450ms]
parseManifest: hook_timeout_sec (ADR-0023) > accepts a valid hook_timeout_sec [0.480ms]
parseManifest: hook_timeout_sec (ADR-0023) > defaults hook_timeout_sec to 10 [0.660ms]
parseManifest: hook_timeout_sec (ADR-0023) > rejects hook_timeout_sec greater than 60 [0.490ms]
parseManifest: memory-markdown manifest integration > the actual memory-markdown manifest at plugins/project/memory-markdown/kaged-plugin.yaml parses [17.23ms]
parseManifest: valid manifests > parses full manifest [4.92ms]
parseManifest: valid manifests > parses minimal manifest with defaults [0.680ms]
parseManifest: invalid YAML > throws ManifestValidationError on broken YAML [0.820ms]
parseManifest: schema violations > missing name [0.460ms]
parseManifest: schema violations > invalid name format (uppercase) [0.460ms]
parseManifest: schema violations > name too long [0.460ms]
parseManifest: schema violations > missing methods AND missing hooks AND missing tools (plugin does nothing) [0.400ms]
parseManifest: schema violations > empty methods array AND no hooks AND no tools (plugin does nothing) [0.440ms]
parseManifest: schema violations > invalid method name (reserved prefix) [0.510ms]
parseManifest: schema violations > invalid method name (single segment) [0.430ms]
parseManifest: schema violations > description too long [0.520ms]
parseManifest: schema violations > shutdown_timeout_sec too high [0.490ms]
parseManifest: schema violations > health_interval_sec too low [0.470ms]
parseManifest: schema violations > invalid homepage URL [0.940ms]
parseManifest: schema violations > error includes issues array [0.350ms]
PluginCallContext: canonical shape > daemon-level context has all agent fields null [0.150ms]
PluginCallContext: canonical shape > agent-run context has all four agent fields populated [0.050ms]
PluginCallContext: canonical shape > nested subagent path is accepted [0.040ms]
PluginCallContext: canonical shape > operator_id may be null in insecure-mode daemon-level call [0.040ms]
PluginCallContext: canonical shape > request_id is always required (non-empty string) [0.080ms]
PluginCallContext: invariant — agent fields are all-or-none > project_id set but agent_path null is a contract violation [0.060ms]
PluginCallContext: invariant — agent fields are all-or-none > agent_path set but project_id null is a contract violation [0.060ms]
PluginCallContext: invariant — agent fields are all-or-none > session_id set but agent_path null is a contract violation [0.050ms]
PluginCallContext: invariant — agent fields are all-or-none > project_id+agent_path set but session_id null is a contract violation [0.050ms]
PluginCallContext: invariant — agent fields are all-or-none > error message names which fields are inconsistent [0.070ms]
buildPluginCallContext: helper builder > daemon-level call: operator + request_id only [0.060ms]
buildPluginCallContext: helper builder > agent-run: all four fields propagated [0.030ms]
buildPluginCallContext: helper builder > builder validates the invariant — partial agent fields throw [0.060ms]
buildPluginCallContext: helper builder > missing request_id throws [0.030ms]
buildPluginCallContext: helper builder > null operator_id is accepted (insecure-mode daemon-level call) [0.040ms]
PluginProcess.fireHook: gating > returns not_running when plugin is disabled [0.710ms]
PluginProcess.fireHook: gating > returns not_subscribed when plugin does not list the hook [26.54ms]
PluginProcess.fireHook: gating > returns not_subscribed for pre_compact when only on_session_start subscribed [23.08ms]
PluginProcess.fireHook: successful dispatch > on_session_start sends kaged.hook.on_session_start with _context and returns inject [35.96ms]
PluginProcess.fireHook: successful dispatch > on_session_idle sends transcript params and returns ok with null result [33.70ms]
PluginProcess.fireHook: successful dispatch > pre_compact passes role and strategy params [33.89ms]
PluginProcess.fireHook: failure handling > JSON-RPC error response returns error status with audit [35.77ms]
PluginProcess.fireHook: failure handling > timeout returns timeout status with audit [1.03s]
PluginProcess.fireHook: failure handling > uses hookTimeoutSec from manifest (not default METHOD_CALL_TIMEOUT_MS) [1.02s]
PluginSupervisor.fireHook > returns empty array for empty pluginNames [1.11ms]
PluginSupervisor.fireHook > returns not_found for unknown plugin [0.380ms]
PluginSupervisor.fireHook > fires hooks in order on registered plugins (not_running since disabled) [1.03ms]
PluginSupervisor.fireHook > mixed results: found + not_found + not_subscribed [0.560ms]
plugin machine: disabled → spawning (enable) > disabled + enable → spawning [0.120ms]
plugin machine: disabled → spawning (enable) > emits spawn_process, send_initialize, audit [0.180ms]
plugin machine: disabled → spawning (enable) > running + enable → TransitionError [0.300ms]
plugin machine: spawning → running (handshake_ok) > spawning + handshake_ok → running [0.110ms]
plugin machine: spawning → running (handshake_ok) > emits send_initialized, reset_failure_counter, audit [0.120ms]
plugin machine: spawning → running (handshake_ok) > running + handshake_ok → TransitionError [0.130ms]
plugin machine: spawning → failed (handshake_fail) > spawning + handshake_fail → failed [0.210ms]
plugin machine: spawning → failed (handshake_fail) > emits kill_process, mark_failed, audit [0.150ms]
plugin machine: crash with backoff > running + crash (first failure) → crashed with 1s backoff [0.200ms]
plugin machine: crash with backoff > running + crash (2nd failure) → crashed with 2s backoff [0.180ms]
plugin machine: crash with backoff > running + crash (4th failure) → crashed with 8s backoff [0.080ms]
plugin machine: crash with backoff > running + crash (5th failure) → failed [0.120ms]
plugin machine: crash with backoff > spawning + crash → crashed (process died during handshake) [0.090ms]
plugin machine: crash with backoff > disabled + crash → TransitionError [0.120ms]
plugin machine: health_fail_limit > running + health_fail_limit (first) → crashed [0.290ms]
plugin machine: health_fail_limit > running + health_fail_limit (5th) → failed [0.080ms]
plugin machine: health_fail_limit > disabled + health_fail_limit → TransitionError [0.130ms]
plugin machine: crashed → spawning (restart) > crashed + restart → spawning [0.130ms]
plugin machine: crashed → spawning (restart) > running + restart → TransitionError [0.130ms]
plugin machine: running → stopped (shutdown) > running + shutdown → stopped [0.160ms]
plugin machine: running → stopped (shutdown) > disabled + shutdown → TransitionError [0.100ms]
plugin machine: any → disabled (disable) > running + disable → disabled (kills process) [0.200ms]
plugin machine: any → disabled (disable) > spawning + disable → disabled (kills process) [0.110ms]
plugin machine: any → disabled (disable) > crashed + disable → disabled (no kill needed) [0.090ms]
plugin machine: any → disabled (disable) > failed + disable → disabled [0.050ms]
plugin machine: any → disabled (disable) > stopped + disable → disabled [0.050ms]
plugin machine: any → disabled (disable) > disabled + disable → TransitionError [0.110ms]
plugin machine: failed → spawning (operator_enable) > failed + operator_enable → spawning [0.220ms]
plugin machine: failed → spawning (operator_enable) > running + operator_enable → TransitionError [0.090ms]
plugin machine: failed → spawning (operator_enable) > disabled + operator_enable → TransitionError [0.120ms]
plugin machine: full lifecycle > disabled → enable → handshake → running → shutdown → stopped [0.140ms]
plugin machine: full lifecycle > crash → restart → handshake → running [0.120ms]
plugin machine: full lifecycle > repeated crashes → failed → operator_enable → spawning [0.090ms]
PluginTransitionError properties > includes from and event [0.170ms]
PluginProcess: initial state > starts in disabled state [0.360ms]
PluginProcess: enable + handshake > enable transitions to spawning and sends initialize [26.43ms]
PluginProcess: enable + handshake > handshake failure on name mismatch → failed state [23.48ms]
PluginProcess: enable + handshake > handshake failure on api_version mismatch → failed state [24.03ms]
PluginProcess: enable + handshake > handshake failure on capability overreach → failed state [22.62ms]
PluginProcess: spawn environment > builds correct spawn env with protected keys [13.27ms]
PluginProcess: method calls > callMethod sends request with _context and returns result [36.28ms]
PluginProcess: method calls > callMethod throws when not running [0.580ms]
PluginProcess: notification handling > forwards plugin notifications via callback [37.24ms]
PluginProcess: state change tracking > fires onStateChange for each transition [23.84ms]
PluginProcess: shutdown > sends shutdown notification [25.74ms]
PluginProcess: shutdown > shutdown on non-running state is no-op [0.100ms]
PluginProcess: disable > disable from running kills process [23.18ms]
PluginSupervisor: registration > registerPlugin adds a plugin [0.500ms]
PluginSupervisor: registration > registerPlugin rejects duplicate names [0.320ms]
PluginSupervisor: registration > registerPlugin rejects after startAll [1.29ms]
PluginSupervisor: registration > registerFromYaml parses YAML and registers [1.93ms]
PluginSupervisor: listing > listPlugins returns sorted list [1.59ms]
PluginSupervisor: listing > listPlugins returns empty for fresh supervisor [0.120ms]
PluginSupervisor: listing > getPluginInfo returns correct details [0.280ms]
PluginSupervisor: listing > getPluginInfo returns null for unknown plugin [0.070ms]
PluginSupervisor: listing > getPluginState returns state for registered plugin [0.170ms]
PluginSupervisor: listing > getPluginState returns null for unknown plugin [0.060ms]
PluginSupervisor: hasPlugin > returns true for registered plugin [0.180ms]
PluginSupervisor: hasPlugin > returns false for unregistered plugin [0.060ms]
PluginSupervisor: enable/disable > enablePlugin throws for unknown plugin [0.380ms]
PluginSupervisor: enable/disable > disablePlugin throws for unknown plugin [0.330ms]
PluginSupervisor: callMethod > callMethod throws for unknown plugin [0.230ms]
PluginSupervisor: isStarted flag > isStarted is false initially [0.080ms]
PluginSupervisor: isStarted flag > isStarted is true after startAll [0.240ms]
PluginSupervisor: isStarted flag > isStarted is false after stopAll [0.230ms]
PluginSupervisor: isStarted flag > startAll is idempotent [0.260ms]
PluginSupervisor: audit events > emits plugin.disabled audit for disabled plugins on register [0.320ms]
PluginSupervisor: multiple plugins > registers and lists multiple plugins [0.330ms]
PluginSupervisor: stopAll with no plugins > stopAll on empty supervisor completes [0.270ms]
isValidMethodName > valid: two segments [1.49ms]
isValidMethodName > valid: three segments [0.100ms]
isValidMethodName > valid: four segments [0.050ms]
isValidMethodName > valid: with underscores [0.050ms]
isValidMethodName > valid: with digits [0.040ms]
isValidMethodName > invalid: single segment [0.030ms]
isValidMethodName > invalid: five segments [0.050ms]
isValidMethodName > invalid: uppercase [0.050ms]
isValidMethodName > invalid: starts with digit [0.050ms]
isValidMethodName > invalid: hyphens [0.040ms]
isValidMethodName > invalid: empty [0.030ms]
isValidMethodName > invalid: segment starts with digit [0.040ms]
isReservedMethod > kaged.* is reserved [0.170ms]
isReservedMethod > system.* is reserved [0.060ms]
isReservedMethod > presets.list is not reserved [0.050ms]
validatePluginMethodName > valid method passes [0.140ms]
validatePluginMethodName > invalid format throws ProtocolError [0.130ms]
validatePluginMethodName > reserved name throws ProtocolError [0.090ms]
validatePluginMethodName > error code is -32600 [0.130ms]
validatePluginMethods > all valid passes [0.200ms]
validatePluginMethods > one invalid throws [0.180ms]
JSON-RPC message classification > request [0.150ms]
JSON-RPC message classification > notification (no id) [0.110ms]
JSON-RPC message classification > success response [0.090ms]
JSON-RPC message classification > error response [0.070ms]
JSON-RPC message classification > batch [0.080ms]
JSON-RPC message classification > null is not any type [0.080ms]
classifyMessage > classifies request [0.130ms]
classifyMessage > classifies notification [0.090ms]
classifyMessage > classifies response [0.090ms]
classifyMessage > classifies batch [0.080ms]
classifyMessage > invalid JSON → invalid [0.060ms]
classifyMessage > valid JSON but not JSON-RPC → invalid [0.090ms]
JSON_RPC_ERRORS > has expected codes [0.210ms]
pluginStoragePrefix > simple name [0.110ms]
pluginStoragePrefix > hyphenated name converted to underscores [0.070ms]
pluginStoragePrefix > name with no hyphens [0.040ms]
validateAgentPluginRoles > empty manifests list returns no errors [0.210ms]
validateAgentPluginRoles > single observer returns no errors [0.220ms]
validateAgentPluginRoles > single compactor returns no errors [0.090ms]
validateAgentPluginRoles > multiple observers returns no errors [0.130ms]
validateAgentPluginRoles > two compactors returns error on the second [0.170ms]
validateAgentPluginRoles > three compactors returns errors on second and third [0.170ms]
validateAgentPluginRoles > compactor + observers returns no errors [0.090ms]
validateAgentPluginRoles > observers + two compactors returns error only on second compactor [0.120ms]
validateAgentPluginRoles > plugins with empty roles are fine [0.130ms]
validateAgentPluginRoles > dual-role plugin (observer+compactor) counts as the compactor [0.130ms]
prefixToolName > joins plugin name and tool name with dot [0.100ms]
prefixToolName > single-segment plugin name [0.050ms]
checkBuiltInNamespaceCollision > returns null for non-colliding names [0.180ms]
checkBuiltInNamespaceCollision > returns warning for 'file' [0.100ms]
checkBuiltInNamespaceCollision > returns warning for 'search' [0.050ms]
checkBuiltInNamespaceCollision > returns warning for 'lsp' [0.050ms]
checkBuiltInNamespaceCollision > returns warning for 'dap' [0.040ms]
checkBuiltInNamespaceCollision > returns warning for 'kaged' [0.050ms]
checkBuiltInNamespaceCollision > does not match partial overlaps like 'file-utils' [0.050ms]
buildToolRegistry > empty manifests list returns empty result [0.360ms]
buildToolRegistry > registers tools with prefixed names [0.420ms]
buildToolRegistry > detects tool name collision between plugins [0.200ms]
buildToolRegistry > first plugin wins on collision — second is rejected [0.130ms]
buildToolRegistry > multiple plugins with different tools coexist [0.160ms]
buildToolRegistry > emits warning for built-in namespace collision [0.120ms]
buildToolRegistry > plugin with no tools contributes nothing [0.100ms]
buildToolRegistry > rejects prefixed names that don't match the pattern [0.110ms]

Mentioned in

Type Document
adr ADR-0008: Plugins are subprocesses over JSON-RPC on stdio
adr ADR-0023: Project-plugin lifecycle hooks, per-agent declaration, isolation as a core principle
adr ADR-0024: Context compaction is kaged-owned, layered, observable, and operator-tunable
adr ADR-0028: 3rd-party OAuth provider auth — token lifecycle and credential management
spec Spec: Agent Tooling
spec Spec: Agent Harness
spec Spec: Daemon
spec Spec: HTTP + WebSocket API
spec Spec: Local config
spec Spec: Plugin Host
spec Spec: Project DSL
spec Spec: Sandbox
spec Spec: Session Manager