actoviq-agent-sdk 0.4.21 → 0.4.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh.md +50 -113
- package/README.md +51 -164
- package/assets/hadamard-icon.ico +0 -0
- package/assets/hadamard-icon.png +0 -0
- package/bin/hadamard-gui.js +31 -12
- package/dist/src/codeIntel/codeIntelligenceService.d.ts +16 -0
- package/dist/src/codeIntel/codeIntelligenceService.d.ts.map +1 -1
- package/dist/src/codeIntel/codeIntelligenceService.js +87 -2
- package/dist/src/codeIntel/codeIntelligenceService.js.map +1 -1
- package/dist/src/codeIntel/codeIntelligenceTools.d.ts.map +1 -1
- package/dist/src/codeIntel/codeIntelligenceTools.js +6 -0
- package/dist/src/codeIntel/codeIntelligenceTools.js.map +1 -1
- package/dist/src/codeIntel/index.d.ts +1 -0
- package/dist/src/codeIntel/index.d.ts.map +1 -1
- package/dist/src/codeIntel/index.js +1 -0
- package/dist/src/codeIntel/index.js.map +1 -1
- package/dist/src/codeIntel/languageServerPresets.d.ts +13 -0
- package/dist/src/codeIntel/languageServerPresets.d.ts.map +1 -0
- package/dist/src/codeIntel/languageServerPresets.js +51 -0
- package/dist/src/codeIntel/languageServerPresets.js.map +1 -0
- package/dist/src/codeIntel/languageServerRegistry.d.ts +1 -0
- package/dist/src/codeIntel/languageServerRegistry.d.ts.map +1 -1
- package/dist/src/codeIntel/languageServerRegistry.js +2 -2
- package/dist/src/codeIntel/languageServerRegistry.js.map +1 -1
- package/dist/src/config/resolveRuntimeConfig.d.ts.map +1 -1
- package/dist/src/config/resolveRuntimeConfig.js +5 -0
- package/dist/src/config/resolveRuntimeConfig.js.map +1 -1
- package/dist/src/extensions/builtInExtensions.d.ts +61 -0
- package/dist/src/extensions/builtInExtensions.d.ts.map +1 -0
- package/dist/src/extensions/builtInExtensions.js +218 -0
- package/dist/src/extensions/builtInExtensions.js.map +1 -0
- package/dist/src/extensions/filterOutputPolicy.d.ts +21 -0
- package/dist/src/extensions/filterOutputPolicy.d.ts.map +1 -0
- package/dist/src/extensions/filterOutputPolicy.js +121 -0
- package/dist/src/extensions/filterOutputPolicy.js.map +1 -0
- package/dist/src/extensions/securityPolicy.d.ts +27 -0
- package/dist/src/extensions/securityPolicy.d.ts.map +1 -0
- package/dist/src/extensions/securityPolicy.js +238 -0
- package/dist/src/extensions/securityPolicy.js.map +1 -0
- package/dist/src/extensions/sessionCostTracker.d.ts +63 -0
- package/dist/src/extensions/sessionCostTracker.d.ts.map +1 -0
- package/dist/src/extensions/sessionCostTracker.js +213 -0
- package/dist/src/extensions/sessionCostTracker.js.map +1 -0
- package/dist/src/extensions/taskNotifications.d.ts +31 -0
- package/dist/src/extensions/taskNotifications.d.ts.map +1 -0
- package/dist/src/extensions/taskNotifications.js +50 -0
- package/dist/src/extensions/taskNotifications.js.map +1 -0
- package/dist/src/extensions/usageBar.d.ts +35 -0
- package/dist/src/extensions/usageBar.d.ts.map +1 -0
- package/dist/src/extensions/usageBar.js +67 -0
- package/dist/src/extensions/usageBar.js.map +1 -0
- package/dist/src/gui/contextRailStore.d.ts +13 -0
- package/dist/src/gui/contextRailStore.d.ts.map +1 -1
- package/dist/src/gui/contextRailStore.js +16 -0
- package/dist/src/gui/contextRailStore.js.map +1 -1
- package/dist/src/gui/electronMain.js +45 -5
- package/dist/src/gui/electronMain.js.map +1 -1
- package/dist/src/gui/guiDesignClientScript.d.ts.map +1 -1
- package/dist/src/gui/guiDesignClientScript.js +31 -0
- package/dist/src/gui/guiDesignClientScript.js.map +1 -1
- package/dist/src/gui/guiUsageRoutingAssets.d.ts +7 -0
- package/dist/src/gui/guiUsageRoutingAssets.d.ts.map +1 -0
- package/dist/src/gui/guiUsageRoutingAssets.js +509 -0
- package/dist/src/gui/guiUsageRoutingAssets.js.map +1 -0
- package/dist/src/gui/guiUsageRoutingHttpController.d.ts +11 -0
- package/dist/src/gui/guiUsageRoutingHttpController.d.ts.map +1 -0
- package/dist/src/gui/guiUsageRoutingHttpController.js +125 -0
- package/dist/src/gui/guiUsageRoutingHttpController.js.map +1 -0
- package/dist/src/gui/guiUsageRoutingRuntime.d.ts +36 -0
- package/dist/src/gui/guiUsageRoutingRuntime.d.ts.map +1 -0
- package/dist/src/gui/guiUsageRoutingRuntime.js +98 -0
- package/dist/src/gui/guiUsageRoutingRuntime.js.map +1 -0
- package/dist/src/gui/hadamardGui.d.ts +5 -0
- package/dist/src/gui/hadamardGui.d.ts.map +1 -1
- package/dist/src/gui/hadamardGui.js +159 -16
- package/dist/src/gui/hadamardGui.js.map +1 -1
- package/dist/src/gui/hadamardGuiAssets.d.ts.map +1 -1
- package/dist/src/gui/hadamardGuiAssets.js +297 -41
- package/dist/src/gui/hadamardGuiAssets.js.map +1 -1
- package/dist/src/index.d.ts +32 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +16 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/keyway/electronSecretStore.d.ts +37 -0
- package/dist/src/keyway/electronSecretStore.d.ts.map +1 -0
- package/dist/src/keyway/electronSecretStore.js +105 -0
- package/dist/src/keyway/electronSecretStore.js.map +1 -0
- package/dist/src/keyway/embeddedKeyway.d.ts +34 -0
- package/dist/src/keyway/embeddedKeyway.d.ts.map +1 -0
- package/dist/src/keyway/embeddedKeyway.js +81 -0
- package/dist/src/keyway/embeddedKeyway.js.map +1 -0
- package/dist/src/keyway/keywayLoopbackGateway.d.ts +30 -0
- package/dist/src/keyway/keywayLoopbackGateway.d.ts.map +1 -0
- package/dist/src/keyway/keywayLoopbackGateway.js +71 -0
- package/dist/src/keyway/keywayLoopbackGateway.js.map +1 -0
- package/dist/src/keyway/keywayMigrationService.d.ts +44 -0
- package/dist/src/keyway/keywayMigrationService.d.ts.map +1 -0
- package/dist/src/keyway/keywayMigrationService.js +219 -0
- package/dist/src/keyway/keywayMigrationService.js.map +1 -0
- package/dist/src/keyway/keywayModelApi.d.ts +24 -0
- package/dist/src/keyway/keywayModelApi.d.ts.map +1 -0
- package/dist/src/keyway/keywayModelApi.js +106 -0
- package/dist/src/keyway/keywayModelApi.js.map +1 -0
- package/dist/src/keyway/keywayPorts.d.ts +189 -0
- package/dist/src/keyway/keywayPorts.d.ts.map +1 -0
- package/dist/src/keyway/keywayPorts.js +2 -0
- package/dist/src/keyway/keywayPorts.js.map +1 -0
- package/dist/src/keyway/keywayProviderExecutor.d.ts +30 -0
- package/dist/src/keyway/keywayProviderExecutor.d.ts.map +1 -0
- package/dist/src/keyway/keywayProviderExecutor.js +257 -0
- package/dist/src/keyway/keywayProviderExecutor.js.map +1 -0
- package/dist/src/keyway/routingComposition.d.ts +18 -0
- package/dist/src/keyway/routingComposition.d.ts.map +1 -0
- package/dist/src/keyway/routingComposition.js +19 -0
- package/dist/src/keyway/routingComposition.js.map +1 -0
- package/dist/src/keyway/usageRoutingAdminService.d.ts +86 -0
- package/dist/src/keyway/usageRoutingAdminService.d.ts.map +1 -0
- package/dist/src/keyway/usageRoutingAdminService.js +384 -0
- package/dist/src/keyway/usageRoutingAdminService.js.map +1 -0
- package/dist/src/nativeCli/crushManagedClient.d.ts +84 -0
- package/dist/src/nativeCli/crushManagedClient.d.ts.map +1 -0
- package/dist/src/nativeCli/crushManagedClient.js +978 -0
- package/dist/src/nativeCli/crushManagedClient.js.map +1 -0
- package/dist/src/nativeCli/crushNativeCliClient.d.ts +19 -0
- package/dist/src/nativeCli/crushNativeCliClient.d.ts.map +1 -0
- package/dist/src/nativeCli/crushNativeCliClient.js +243 -0
- package/dist/src/nativeCli/crushNativeCliClient.js.map +1 -0
- package/dist/src/nativeCli/keywayNativeCliAdapter.d.ts +31 -0
- package/dist/src/nativeCli/keywayNativeCliAdapter.d.ts.map +1 -0
- package/dist/src/nativeCli/keywayNativeCliAdapter.js +35 -0
- package/dist/src/nativeCli/keywayNativeCliAdapter.js.map +1 -0
- package/dist/src/nativeCli/nativeCliAuth.d.ts +24 -0
- package/dist/src/nativeCli/nativeCliAuth.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliAuth.js +327 -0
- package/dist/src/nativeCli/nativeCliAuth.js.map +1 -0
- package/dist/src/nativeCli/nativeCliClient.d.ts +16 -0
- package/dist/src/nativeCli/nativeCliClient.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliClient.js +575 -0
- package/dist/src/nativeCli/nativeCliClient.js.map +1 -0
- package/dist/src/nativeCli/nativeCliCodewhaleProtocol.d.ts +18 -0
- package/dist/src/nativeCli/nativeCliCodewhaleProtocol.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliCodewhaleProtocol.js +376 -0
- package/dist/src/nativeCli/nativeCliCodewhaleProtocol.js.map +1 -0
- package/dist/src/nativeCli/nativeCliContracts.d.ts +22 -0
- package/dist/src/nativeCli/nativeCliContracts.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliContracts.js +2 -0
- package/dist/src/nativeCli/nativeCliContracts.js.map +1 -0
- package/dist/src/nativeCli/nativeCliCursorProtocol.d.ts +7 -0
- package/dist/src/nativeCli/nativeCliCursorProtocol.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliCursorProtocol.js +210 -0
- package/dist/src/nativeCli/nativeCliCursorProtocol.js.map +1 -0
- package/dist/src/nativeCli/nativeCliEnvironment.d.ts +3 -0
- package/dist/src/nativeCli/nativeCliEnvironment.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliEnvironment.js +17 -0
- package/dist/src/nativeCli/nativeCliEnvironment.js.map +1 -0
- package/dist/src/nativeCli/nativeCliExecResolver.d.ts +26 -0
- package/dist/src/nativeCli/nativeCliExecResolver.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliExecResolver.js +152 -0
- package/dist/src/nativeCli/nativeCliExecResolver.js.map +1 -0
- package/dist/src/nativeCli/nativeCliPiProtocol.d.ts +15 -0
- package/dist/src/nativeCli/nativeCliPiProtocol.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliPiProtocol.js +329 -0
- package/dist/src/nativeCli/nativeCliPiProtocol.js.map +1 -0
- package/dist/src/nativeCli/nativeCliProcessTree.d.ts +3 -0
- package/dist/src/nativeCli/nativeCliProcessTree.d.ts.map +1 -0
- package/dist/src/nativeCli/nativeCliProcessTree.js +104 -0
- package/dist/src/nativeCli/nativeCliProcessTree.js.map +1 -0
- package/dist/src/nativeCli/reasonixAcpSession.d.ts +35 -0
- package/dist/src/nativeCli/reasonixAcpSession.d.ts.map +1 -0
- package/dist/src/nativeCli/reasonixAcpSession.js +472 -0
- package/dist/src/nativeCli/reasonixAcpSession.js.map +1 -0
- package/dist/src/nativeCli/reasonixManagedClient.d.ts +56 -0
- package/dist/src/nativeCli/reasonixManagedClient.d.ts.map +1 -0
- package/dist/src/nativeCli/reasonixManagedClient.js +293 -0
- package/dist/src/nativeCli/reasonixManagedClient.js.map +1 -0
- package/dist/src/nativeCli/reasonixNativeCliClient.d.ts +20 -0
- package/dist/src/nativeCli/reasonixNativeCliClient.d.ts.map +1 -0
- package/dist/src/nativeCli/reasonixNativeCliClient.js +317 -0
- package/dist/src/nativeCli/reasonixNativeCliClient.js.map +1 -0
- package/dist/src/parity/bridgeExecResolver.d.ts +2 -25
- package/dist/src/parity/bridgeExecResolver.d.ts.map +1 -1
- package/dist/src/parity/bridgeExecResolver.js +2 -151
- package/dist/src/parity/bridgeExecResolver.js.map +1 -1
- package/dist/src/parity/bridgeProcessTree.d.ts +2 -2
- package/dist/src/parity/bridgeProcessTree.d.ts.map +1 -1
- package/dist/src/parity/bridgeProcessTree.js +2 -82
- package/dist/src/parity/bridgeProcessTree.js.map +1 -1
- package/dist/src/parity/crushManagedClient.d.ts +2 -83
- package/dist/src/parity/crushManagedClient.d.ts.map +1 -1
- package/dist/src/parity/crushManagedClient.js +2 -977
- package/dist/src/parity/crushManagedClient.js.map +1 -1
- package/dist/src/parity/externalCliAuth.d.ts +2 -22
- package/dist/src/parity/externalCliAuth.d.ts.map +1 -1
- package/dist/src/parity/externalCliAuth.js +2 -295
- package/dist/src/parity/externalCliAuth.js.map +1 -1
- package/dist/src/parity/hadamardBridgeSdk.d.ts.map +1 -1
- package/dist/src/parity/hadamardBridgeSdk.js +14 -1
- package/dist/src/parity/hadamardBridgeSdk.js.map +1 -1
- package/dist/src/parity/nativeCliBridgeAdapter.d.ts +6 -0
- package/dist/src/parity/nativeCliBridgeAdapter.d.ts.map +1 -0
- package/dist/src/parity/nativeCliBridgeAdapter.js +38 -0
- package/dist/src/parity/nativeCliBridgeAdapter.js.map +1 -0
- package/dist/src/parity/reasonixAcpSession.d.ts +2 -34
- package/dist/src/parity/reasonixAcpSession.d.ts.map +1 -1
- package/dist/src/parity/reasonixAcpSession.js +2 -471
- package/dist/src/parity/reasonixAcpSession.js.map +1 -1
- package/dist/src/parity/reasonixManagedClient.d.ts +2 -55
- package/dist/src/parity/reasonixManagedClient.d.ts.map +1 -1
- package/dist/src/parity/reasonixManagedClient.js +2 -292
- package/dist/src/parity/reasonixManagedClient.js.map +1 -1
- package/dist/src/provider/openai-client.js +2 -2
- package/dist/src/provider/openai-client.js.map +1 -1
- package/dist/src/provider/openai-model-api.d.ts.map +1 -1
- package/dist/src/provider/openai-model-api.js +5 -1
- package/dist/src/provider/openai-model-api.js.map +1 -1
- package/dist/src/runtime/agentClient.d.ts +14 -1
- package/dist/src/runtime/agentClient.d.ts.map +1 -1
- package/dist/src/runtime/agentClient.js +60 -6
- package/dist/src/runtime/agentClient.js.map +1 -1
- package/dist/src/runtime/toolPolicyPipeline.d.ts +32 -1
- package/dist/src/runtime/toolPolicyPipeline.d.ts.map +1 -1
- package/dist/src/runtime/toolPolicyPipeline.js +43 -3
- package/dist/src/runtime/toolPolicyPipeline.js.map +1 -1
- package/dist/src/tui/hadamardTuiController.d.ts.map +1 -1
- package/dist/src/tui/hadamardTuiController.js +62 -8
- package/dist/src/tui/hadamardTuiController.js.map +1 -1
- package/dist/src/tui/tuiBasicCommandHandler.d.ts +4 -0
- package/dist/src/tui/tuiBasicCommandHandler.d.ts.map +1 -1
- package/dist/src/tui/tuiBasicCommandHandler.js +23 -2
- package/dist/src/tui/tuiBasicCommandHandler.js.map +1 -1
- package/dist/src/tui/tuiCatalogCommandHandler.d.ts +2 -0
- package/dist/src/tui/tuiCatalogCommandHandler.d.ts.map +1 -1
- package/dist/src/tui/tuiCatalogCommandHandler.js +10 -1
- package/dist/src/tui/tuiCatalogCommandHandler.js.map +1 -1
- package/dist/src/tui/tuiUsageRoutingRuntime.d.ts +22 -0
- package/dist/src/tui/tuiUsageRoutingRuntime.d.ts.map +1 -0
- package/dist/src/tui/tuiUsageRoutingRuntime.js +81 -0
- package/dist/src/tui/tuiUsageRoutingRuntime.js.map +1 -0
- package/dist/src/types.d.ts +16 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/ui/commandSurface.d.ts.map +1 -1
- package/dist/src/ui/commandSurface.js +45 -1
- package/dist/src/ui/commandSurface.js.map +1 -1
- package/dist/src/ui/extensionsCommandView.d.ts +18 -0
- package/dist/src/ui/extensionsCommandView.d.ts.map +1 -0
- package/dist/src/ui/extensionsCommandView.js +82 -0
- package/dist/src/ui/extensionsCommandView.js.map +1 -0
- package/dist/src/ui/lspCommandView.d.ts +17 -0
- package/dist/src/ui/lspCommandView.d.ts.map +1 -0
- package/dist/src/ui/lspCommandView.js +25 -0
- package/dist/src/ui/lspCommandView.js.map +1 -0
- package/dist/src/ui/usageRoutingCommand.d.ts +13 -0
- package/dist/src/ui/usageRoutingCommand.d.ts.map +1 -0
- package/dist/src/ui/usageRoutingCommand.js +224 -0
- package/dist/src/ui/usageRoutingCommand.js.map +1 -0
- package/dist/src/usage/budgetService.d.ts +28 -0
- package/dist/src/usage/budgetService.d.ts.map +1 -0
- package/dist/src/usage/budgetService.js +50 -0
- package/dist/src/usage/budgetService.js.map +1 -0
- package/dist/src/usage/contracts.d.ts +149 -0
- package/dist/src/usage/contracts.d.ts.map +1 -0
- package/dist/src/usage/contracts.js +2 -0
- package/dist/src/usage/contracts.js.map +1 -0
- package/dist/src/usage/index.d.ts +7 -0
- package/dist/src/usage/index.d.ts.map +1 -0
- package/dist/src/usage/index.js +4 -0
- package/dist/src/usage/index.js.map +1 -0
- package/dist/src/usage/usageLedger.d.ts +19 -0
- package/dist/src/usage/usageLedger.d.ts.map +1 -0
- package/dist/src/usage/usageLedger.js +389 -0
- package/dist/src/usage/usageLedger.js.map +1 -0
- package/dist/src/usage/usageQueryService.d.ts +12 -0
- package/dist/src/usage/usageQueryService.d.ts.map +1 -0
- package/dist/src/usage/usageQueryService.js +29 -0
- package/dist/src/usage/usageQueryService.js.map +1 -0
- package/package.json +14 -2
- package/scripts/prepare-gui-launcher.mjs +62 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in extension framework (Hadamard-owned): a fixed catalog of
|
|
3
|
+
* settings-toggleable extensions, state resolution from
|
|
4
|
+
* `~/.hadamard/settings.json` (`extensions.<id>`) with SDK overrides, a
|
|
5
|
+
* validated settings patcher, and a mutable toggle holder captured by runtime
|
|
6
|
+
* contributions so `/extensions` toggling takes effect without rebuilding the
|
|
7
|
+
* tool-policy pipeline.
|
|
8
|
+
*
|
|
9
|
+
* @module src/extensions/builtInExtensions
|
|
10
|
+
*/
|
|
11
|
+
import { resolveHadamardSettingsStore, persistHadamardSettingsStore } from '../config/hadamardSettingsStore.js';
|
|
12
|
+
import { isRecord } from '../runtime/helpers.js';
|
|
13
|
+
/**
|
|
14
|
+
* Fixed catalog. `security`/`filterOutput` are runtime tool-policy extensions
|
|
15
|
+
* (opt-in, hard-deny/redact semantics); `costTracker`/`usageBar`/`notifications`
|
|
16
|
+
* are default-on session/UI extensions wired into the TUI and GUI.
|
|
17
|
+
*/
|
|
18
|
+
export const BUILT_IN_EXTENSIONS = [
|
|
19
|
+
{
|
|
20
|
+
id: 'security',
|
|
21
|
+
title: 'Security Guard',
|
|
22
|
+
description: 'Denies catastrophic shell commands and writes to protected paths before the permission stage.',
|
|
23
|
+
defaultEnabled: false,
|
|
24
|
+
kind: 'policy',
|
|
25
|
+
configurableKeys: ['protectedPaths', 'extraDangerousPatterns'],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'filterOutput',
|
|
29
|
+
title: 'Output Filter',
|
|
30
|
+
description: 'Redacts secrets and credentials from tool results before they reach the model.',
|
|
31
|
+
defaultEnabled: false,
|
|
32
|
+
kind: 'policy',
|
|
33
|
+
configurableKeys: ['extraPatterns', 'maxChars'],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'costTracker',
|
|
37
|
+
title: 'Cost Tracker',
|
|
38
|
+
description: 'Tracks per-session token usage and cost.',
|
|
39
|
+
defaultEnabled: true,
|
|
40
|
+
kind: 'session',
|
|
41
|
+
configurableKeys: [],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'usageBar',
|
|
45
|
+
title: 'Usage Bar',
|
|
46
|
+
description: 'Shows live context/token usage in interactive surfaces.',
|
|
47
|
+
defaultEnabled: true,
|
|
48
|
+
kind: 'ui',
|
|
49
|
+
configurableKeys: [],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'notifications',
|
|
53
|
+
title: 'Notifications',
|
|
54
|
+
description: 'Surfaces run and background-task notifications.',
|
|
55
|
+
defaultEnabled: true,
|
|
56
|
+
kind: 'ui',
|
|
57
|
+
configurableKeys: ['bell', 'osc'],
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
export function getBuiltInExtensionDefinition(id) {
|
|
61
|
+
return BUILT_IN_EXTENSIONS.find((definition) => definition.id === id);
|
|
62
|
+
}
|
|
63
|
+
const STRING_ARRAY_KEYS = new Set(['protectedPaths', 'extraDangerousPatterns', 'extraPatterns']);
|
|
64
|
+
const BOOLEAN_KEYS = new Set(['bell', 'osc']);
|
|
65
|
+
function isValidConfigValue(key, value) {
|
|
66
|
+
if (STRING_ARRAY_KEYS.has(key)) {
|
|
67
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
|
|
68
|
+
}
|
|
69
|
+
if (BOOLEAN_KEYS.has(key)) {
|
|
70
|
+
return typeof value === 'boolean';
|
|
71
|
+
}
|
|
72
|
+
if (key === 'maxChars') {
|
|
73
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve the effective state of every built-in extension from raw settings
|
|
79
|
+
* (`extensions.<id>` entries) plus SDK overrides. Unknown ids are ignored;
|
|
80
|
+
* invalid shapes fall back to catalog defaults; SDK overrides win and accept a
|
|
81
|
+
* boolean shorthand or `{ enabled, ...config }`.
|
|
82
|
+
*/
|
|
83
|
+
export function resolveBuiltInExtensionStates(settingsRaw, overrides) {
|
|
84
|
+
const stored = isRecord(settingsRaw) && isRecord(settingsRaw.extensions) ? settingsRaw.extensions : {};
|
|
85
|
+
return BUILT_IN_EXTENSIONS.map((definition) => {
|
|
86
|
+
let enabled = definition.defaultEnabled;
|
|
87
|
+
let config = {};
|
|
88
|
+
const storedEntry = stored[definition.id];
|
|
89
|
+
if (isRecord(storedEntry)) {
|
|
90
|
+
if (typeof storedEntry.enabled === 'boolean')
|
|
91
|
+
enabled = storedEntry.enabled;
|
|
92
|
+
config = pickValidConfig(definition, storedEntry);
|
|
93
|
+
}
|
|
94
|
+
const override = overrides?.[definition.id];
|
|
95
|
+
if (typeof override === 'boolean') {
|
|
96
|
+
enabled = override;
|
|
97
|
+
}
|
|
98
|
+
else if (isRecord(override)) {
|
|
99
|
+
if (typeof override.enabled === 'boolean')
|
|
100
|
+
enabled = override.enabled;
|
|
101
|
+
config = { ...config, ...pickValidConfig(definition, override) };
|
|
102
|
+
}
|
|
103
|
+
return { id: definition.id, enabled, config };
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function pickValidConfig(definition, source) {
|
|
107
|
+
const config = {};
|
|
108
|
+
for (const key of definition.configurableKeys) {
|
|
109
|
+
const value = source[key];
|
|
110
|
+
if (value !== undefined && isValidConfigValue(key, value)) {
|
|
111
|
+
config[key] = Array.isArray(value) ? [...value] : value;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return config;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Validated patch of the persisted `extensions.<id>` subtree: unknown stored
|
|
118
|
+
* keys are preserved, invalid patch values throw (mirroring
|
|
119
|
+
* patchManagedPluginSettings strictness). Persists the full settings store.
|
|
120
|
+
*/
|
|
121
|
+
export async function patchBuiltInExtensionSettings(homeDir, id, patch) {
|
|
122
|
+
const definition = getBuiltInExtensionDefinition(id);
|
|
123
|
+
if (!definition) {
|
|
124
|
+
throw new Error(`Unknown built-in extension: ${id}`);
|
|
125
|
+
}
|
|
126
|
+
const validated = {};
|
|
127
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
128
|
+
if (value === undefined)
|
|
129
|
+
continue;
|
|
130
|
+
if (key === 'enabled') {
|
|
131
|
+
if (typeof value !== 'boolean') {
|
|
132
|
+
throw new Error(`extensions.${id}.enabled must be a boolean.`);
|
|
133
|
+
}
|
|
134
|
+
validated.enabled = value;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (!definition.configurableKeys.includes(key)) {
|
|
138
|
+
throw new Error(`Unknown config key for built-in extension '${id}': ${key}`);
|
|
139
|
+
}
|
|
140
|
+
if (!isValidConfigValue(key, value)) {
|
|
141
|
+
const expected = STRING_ARRAY_KEYS.has(key)
|
|
142
|
+
? 'a string array'
|
|
143
|
+
: BOOLEAN_KEYS.has(key)
|
|
144
|
+
? 'a boolean'
|
|
145
|
+
: 'a number >= 0';
|
|
146
|
+
throw new Error(`extensions.${id}.${key} must be ${expected}.`);
|
|
147
|
+
}
|
|
148
|
+
validated[key] = Array.isArray(value) ? [...new Set(value)] : value;
|
|
149
|
+
}
|
|
150
|
+
const store = await resolveHadamardSettingsStore({ homeDir });
|
|
151
|
+
const raw = store.raw;
|
|
152
|
+
const extensions = isRecord(raw.extensions) ? { ...raw.extensions } : {};
|
|
153
|
+
const existing = isRecord(extensions[id]) ? extensions[id] : {};
|
|
154
|
+
extensions[id] = { ...existing, ...validated };
|
|
155
|
+
raw.extensions = extensions;
|
|
156
|
+
await persistHadamardSettingsStore(store.configPath, raw);
|
|
157
|
+
}
|
|
158
|
+
export function createBuiltInExtensionsApi(toggles, homeDir) {
|
|
159
|
+
return {
|
|
160
|
+
list: () => toggles.snapshot(),
|
|
161
|
+
isEnabled: (id) => toggles.isEnabled(id),
|
|
162
|
+
getConfig: (id) => toggles.getConfig(id),
|
|
163
|
+
setEnabled: async (id, enabled) => {
|
|
164
|
+
const previous = toggles.isEnabled(id);
|
|
165
|
+
toggles.setEnabled(id, enabled);
|
|
166
|
+
try {
|
|
167
|
+
await patchBuiltInExtensionSettings(homeDir, id, { enabled });
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
toggles.setEnabled(id, previous);
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Mutable per-client holder resolved once at create(); contributions capture
|
|
178
|
+
* it so toggling an extension later takes effect on the next run without
|
|
179
|
+
* rebuilding the pipeline.
|
|
180
|
+
*/
|
|
181
|
+
export class BuiltInExtensionToggles {
|
|
182
|
+
states = new Map();
|
|
183
|
+
constructor(states) {
|
|
184
|
+
for (const state of states) {
|
|
185
|
+
this.states.set(state.id, { enabled: state.enabled, config: { ...state.config } });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
isEnabled(id) {
|
|
189
|
+
const state = this.states.get(id);
|
|
190
|
+
if (state)
|
|
191
|
+
return state.enabled;
|
|
192
|
+
return getBuiltInExtensionDefinition(id)?.defaultEnabled ?? false;
|
|
193
|
+
}
|
|
194
|
+
getConfig(id) {
|
|
195
|
+
return (this.states.get(id)?.config ?? {});
|
|
196
|
+
}
|
|
197
|
+
setEnabled(id, enabled) {
|
|
198
|
+
const state = this.states.get(id);
|
|
199
|
+
if (!state) {
|
|
200
|
+
if (!getBuiltInExtensionDefinition(id))
|
|
201
|
+
throw new Error(`Unknown built-in extension: ${id}`);
|
|
202
|
+
this.states.set(id, { enabled, config: {} });
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
state.enabled = enabled;
|
|
206
|
+
}
|
|
207
|
+
snapshot() {
|
|
208
|
+
return BUILT_IN_EXTENSIONS.map((definition) => {
|
|
209
|
+
const state = this.states.get(definition.id);
|
|
210
|
+
return {
|
|
211
|
+
id: definition.id,
|
|
212
|
+
enabled: state?.enabled ?? definition.defaultEnabled,
|
|
213
|
+
config: { ...(state?.config ?? {}) },
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=builtInExtensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtInExtensions.js","sourceRoot":"","sources":["../../../src/extensions/builtInExtensions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HadamardRuntimeContribution } from '../contrib/contributionHost.js';
|
|
2
|
+
import { type ToolPostPolicyListener } from '../runtime/toolPolicyPipeline.js';
|
|
3
|
+
import type { BuiltInExtensionToggles } from './builtInExtensions.js';
|
|
4
|
+
/**
|
|
5
|
+
* Redact known secret shapes from `text`. `extraPatterns` are user regex
|
|
6
|
+
* strings (compiled with `g`; invalid ones skipped) whose whole match is
|
|
7
|
+
* replaced with `[REDACTED:custom]`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function redactSensitiveText(text: string, extraPatterns?: readonly string[]): string;
|
|
10
|
+
/** Hard-truncate to `maxChars` (when > 0), marking the cut. */
|
|
11
|
+
export declare function truncateText(text: string, maxChars: number): string;
|
|
12
|
+
export interface FilterOutputExtensionConfig {
|
|
13
|
+
extraPatterns?: string[];
|
|
14
|
+
/** 0 (default) disables truncation; the upstream spill listener still artifacts huge outputs. */
|
|
15
|
+
maxChars?: number;
|
|
16
|
+
}
|
|
17
|
+
/** Post-listener: redacts and truncates accepted results (success and error). No-op when disabled. */
|
|
18
|
+
export declare function createFilterOutputPostListener(toggles: BuiltInExtensionToggles): ToolPostPolicyListener;
|
|
19
|
+
/** Contribution: attaches the filter-output post-listener to the tool-policy listener registry. */
|
|
20
|
+
export declare function createFilterOutputPolicyContribution(toggles: BuiltInExtensionToggles): HadamardRuntimeContribution;
|
|
21
|
+
//# sourceMappingURL=filterOutputPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filterOutputPolicy.d.ts","sourceRoot":"","sources":["../../../src/extensions/filterOutputPolicy.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAA4B,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC5G,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAgDtE;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CA0B3F;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED,MAAM,WAAW,2BAA2B;IAC1C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiBD,sGAAsG;AACtG,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,uBAAuB,GAAG,sBAAsB,CAgBvG;AAED,mGAAmG;AACnG,wBAAgB,oCAAoC,CAAC,OAAO,EAAE,uBAAuB,GAAG,2BAA2B,CAWlH"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { toolPolicyListenerRegistryKey, } from '../runtime/toolPolicyPipeline.js';
|
|
2
|
+
const REDACTION_RULES = [
|
|
3
|
+
// PEM private keys (multi-line; runs first so inner assignments are consumed).
|
|
4
|
+
{
|
|
5
|
+
label: 'private-key',
|
|
6
|
+
pattern: /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY(?: BLOCK)?-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY(?: BLOCK)?-----/g,
|
|
7
|
+
},
|
|
8
|
+
{ label: 'aws-access-key', pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
|
|
9
|
+
{ label: 'github-token', pattern: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/g },
|
|
10
|
+
{ label: 'github-token', pattern: /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g },
|
|
11
|
+
// OpenAI/Anthropic-style API keys (sk-ant-... included).
|
|
12
|
+
{ label: 'api-key', pattern: /\bsk-[A-Za-z0-9_-]{20,}\b/g },
|
|
13
|
+
// Bearer tokens: keep the scheme, redact the token.
|
|
14
|
+
{ label: 'bearer-token', pattern: /\b(Bearer\s+)[A-Za-z0-9._~+/=-]{20,}/g, keepPrefix: true },
|
|
15
|
+
// Generic secret assignments: keep `key=` prefix, redact the value.
|
|
16
|
+
{
|
|
17
|
+
label: 'secret',
|
|
18
|
+
pattern: /\b(password|passwd|pwd|api[_-]?key|apikey|secret|access[_-]?token|auth[_-]?token)\b(\s*[:=]\s*['"]?)([^\s'"]{8,})/gi,
|
|
19
|
+
keepPrefix: true,
|
|
20
|
+
labelFromMatch: true,
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
function compileExtraPatterns(extraPatterns) {
|
|
24
|
+
const compiled = [];
|
|
25
|
+
for (const source of extraPatterns ?? []) {
|
|
26
|
+
if (typeof source !== 'string' || !source)
|
|
27
|
+
continue;
|
|
28
|
+
try {
|
|
29
|
+
compiled.push(new RegExp(source, 'g'));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Invalid user regex: skip rather than break tool results.
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return compiled;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Redact known secret shapes from `text`. `extraPatterns` are user regex
|
|
39
|
+
* strings (compiled with `g`; invalid ones skipped) whose whole match is
|
|
40
|
+
* replaced with `[REDACTED:custom]`.
|
|
41
|
+
*/
|
|
42
|
+
export function redactSensitiveText(text, extraPatterns) {
|
|
43
|
+
let redacted = text;
|
|
44
|
+
for (const rule of REDACTION_RULES) {
|
|
45
|
+
redacted = redacted.replace(rule.pattern, (...args) => {
|
|
46
|
+
const match = args[0];
|
|
47
|
+
const groups = args.slice(1, -2);
|
|
48
|
+
if (rule.labelFromMatch) {
|
|
49
|
+
const key = groups[0] ?? 'secret';
|
|
50
|
+
const separator = groups[1] ?? '';
|
|
51
|
+
const value = groups[2] ?? '';
|
|
52
|
+
if (value.startsWith('[REDACTED:'))
|
|
53
|
+
return match;
|
|
54
|
+
return `${key}${separator}[REDACTED:${key.toLowerCase()}]`;
|
|
55
|
+
}
|
|
56
|
+
if (rule.keepPrefix) {
|
|
57
|
+
const prefix = groups[0] ?? '';
|
|
58
|
+
const value = match.slice(prefix.length);
|
|
59
|
+
if (value.startsWith('[REDACTED:'))
|
|
60
|
+
return match;
|
|
61
|
+
return `${prefix}[REDACTED:${rule.label}]`;
|
|
62
|
+
}
|
|
63
|
+
return `[REDACTED:${rule.label}]`;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
for (const pattern of compileExtraPatterns(extraPatterns)) {
|
|
67
|
+
redacted = redacted.replace(pattern, '[REDACTED:custom]');
|
|
68
|
+
}
|
|
69
|
+
return redacted;
|
|
70
|
+
}
|
|
71
|
+
/** Hard-truncate to `maxChars` (when > 0), marking the cut. */
|
|
72
|
+
export function truncateText(text, maxChars) {
|
|
73
|
+
if (!Number.isFinite(maxChars) || maxChars <= 0 || text.length <= maxChars)
|
|
74
|
+
return text;
|
|
75
|
+
return `${text.slice(0, maxChars)}\n… [truncated by filter-output extension]`;
|
|
76
|
+
}
|
|
77
|
+
function transformContent(content, transform) {
|
|
78
|
+
if (typeof content === 'string')
|
|
79
|
+
return transform(content);
|
|
80
|
+
if (Array.isArray(content)) {
|
|
81
|
+
return content.map((block) => block && typeof block === 'object' && block.type === 'text' && typeof block.text === 'string'
|
|
82
|
+
? { ...block, text: transform(block.text) }
|
|
83
|
+
: block);
|
|
84
|
+
}
|
|
85
|
+
return content;
|
|
86
|
+
}
|
|
87
|
+
/** Post-listener: redacts and truncates accepted results (success and error). No-op when disabled. */
|
|
88
|
+
export function createFilterOutputPostListener(toggles) {
|
|
89
|
+
return async (_call, _execution, next) => {
|
|
90
|
+
if (!toggles.isEnabled('filterOutput'))
|
|
91
|
+
return next();
|
|
92
|
+
const config = toggles.getConfig('filterOutput');
|
|
93
|
+
const maxChars = typeof config.maxChars === 'number' ? config.maxChars : 0;
|
|
94
|
+
const transform = (text) => truncateText(redactSensitiveText(text, config.extraPatterns), maxChars);
|
|
95
|
+
const inner = await next();
|
|
96
|
+
if (inner.kind !== 'accept')
|
|
97
|
+
return inner;
|
|
98
|
+
return {
|
|
99
|
+
kind: 'accept',
|
|
100
|
+
...(inner.content !== undefined ? { content: transformContent(inner.content, transform) } : {}),
|
|
101
|
+
...(inner.additionalContexts !== undefined
|
|
102
|
+
? { additionalContexts: inner.additionalContexts.map((entry) => ({ ...entry, text: transform(entry.text) })) }
|
|
103
|
+
: {}),
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Contribution: attaches the filter-output post-listener to the tool-policy listener registry. */
|
|
108
|
+
export function createFilterOutputPolicyContribution(toggles) {
|
|
109
|
+
return {
|
|
110
|
+
id: 'hadamard.ext.filter-output',
|
|
111
|
+
apply(ctx) {
|
|
112
|
+
const registry = ctx.services.get(toolPolicyListenerRegistryKey);
|
|
113
|
+
if (!registry)
|
|
114
|
+
return;
|
|
115
|
+
const listener = createFilterOutputPostListener(toggles);
|
|
116
|
+
registry.addPost(listener);
|
|
117
|
+
return () => { registry.removePost(listener); };
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=filterOutputPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filterOutputPolicy.js","sourceRoot":"","sources":["../../../src/extensions/filterOutputPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { HadamardRuntimeContribution } from '../contrib/contributionHost.js';
|
|
2
|
+
import { type ToolPrePolicyListener } from '../runtime/toolPolicyPipeline.js';
|
|
3
|
+
import type { BuiltInExtensionToggles } from './builtInExtensions.js';
|
|
4
|
+
/** Default protected paths; extend via settings `extensions.security.protectedPaths`. */
|
|
5
|
+
export declare const DEFAULT_PROTECTED_PATHS: readonly string[];
|
|
6
|
+
/**
|
|
7
|
+
* Return a human-readable violation when the command matches the hard-deny
|
|
8
|
+
* list, else null. `extraPatterns` are user regex strings (compiled
|
|
9
|
+
* case-insensitive; invalid ones are skipped).
|
|
10
|
+
*/
|
|
11
|
+
export declare function findDangerousCommandViolation(command: string, extraPatterns?: readonly string[]): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Return a human-readable violation when `candidatePath` (relative or
|
|
14
|
+
* absolute, resolved against `workDir`) hits one of `protectedPaths`, else
|
|
15
|
+
* null. Entries ending in `/` are directory prefixes; `*`/`?` act as globs
|
|
16
|
+
* matched against the relative path and the basename.
|
|
17
|
+
*/
|
|
18
|
+
export declare function findProtectedPathViolation(candidatePath: string, workDir: string, protectedPaths: readonly string[]): string | null;
|
|
19
|
+
export interface SecurityExtensionConfig {
|
|
20
|
+
protectedPaths?: string[];
|
|
21
|
+
extraDangerousPatterns?: string[];
|
|
22
|
+
}
|
|
23
|
+
/** Pre-listener: dangerous shell commands and protected-path writes. No-op when disabled. */
|
|
24
|
+
export declare function createSecurityPreListener(toggles: BuiltInExtensionToggles): ToolPrePolicyListener;
|
|
25
|
+
/** Contribution: attaches the security pre-listener to the tool-policy listener registry. */
|
|
26
|
+
export declare function createSecurityPolicyContribution(toggles: BuiltInExtensionToggles): HadamardRuntimeContribution;
|
|
27
|
+
//# sourceMappingURL=securityPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityPolicy.d.ts","sourceRoot":"","sources":["../../../src/extensions/securityPolicy.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAA4B,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAE5G,OAAO,EAGL,KAAK,qBAAqB,EAE3B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,yFAAyF;AACzF,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAAiD,CAAC;AAgFvG;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAiB/G;AAmCD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,MAAM,GAAG,IAAI,CAYf;AAiBD,MAAM,WAAW,uBAAuB;IACtC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AASD,6FAA6F;AAC7F,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,uBAAuB,GAAG,qBAAqB,CAgCjG;AAED,6FAA6F;AAC7F,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,uBAAuB,GAAG,2BAA2B,CAW9G"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Guard built-in extension (Hadamard-owned, pi-agent style): an
|
|
3
|
+
* opt-in PRE tool-policy listener that hard-denies catastrophic shell
|
|
4
|
+
* commands and writes to protected paths before the permission stage. Because
|
|
5
|
+
* the pipeline pre-stage is monotonic, this listener can only tighten, never
|
|
6
|
+
* widen, existing behavior.
|
|
7
|
+
*
|
|
8
|
+
* @module src/extensions/securityPolicy
|
|
9
|
+
*/
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { isRecord } from '../runtime/helpers.js';
|
|
12
|
+
import { toolPolicyListenerRegistryKey, } from '../runtime/toolPolicyPipeline.js';
|
|
13
|
+
/** Default protected paths; extend via settings `extensions.security.protectedPaths`. */
|
|
14
|
+
export const DEFAULT_PROTECTED_PATHS = ['.env', '.env.*', '.git/', 'node_modules/'];
|
|
15
|
+
/** Input fields carrying a file path on mutating tools (Write/Edit/NotebookEdit/MultiEdit). */
|
|
16
|
+
const FILE_PATH_FIELDS = ['file_path', 'filePath', 'notebook_path', 'path'];
|
|
17
|
+
/**
|
|
18
|
+
* Catastrophic-command patterns. `git clean -fdx` / `git reset --hard` are
|
|
19
|
+
* deliberately NOT here: they are common recovery operations owned by the
|
|
20
|
+
* permission-rule machinery, not by this hard-deny list.
|
|
21
|
+
*/
|
|
22
|
+
const DANGEROUS_COMMAND_PATTERNS = [
|
|
23
|
+
// mkfs.* formats a filesystem.
|
|
24
|
+
{ pattern: /\bmkfs(?:\.[a-z0-9]+)?\b/i, label: 'filesystem format (mkfs)' },
|
|
25
|
+
// dd writing to a block device.
|
|
26
|
+
{ pattern: /\bdd\b[^;&|]*\bof=\/dev\//i, label: 'dd writing to a device' },
|
|
27
|
+
// Classic fork bomb: :(){ :|:& };:
|
|
28
|
+
{ pattern: /:\s*\(\s*\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;\s*:/, label: 'fork bomb' },
|
|
29
|
+
// OS shutdown/reboot (not followed by a script-ish suffix like shutdown.sh).
|
|
30
|
+
{ pattern: /\b(?:shutdown|reboot|halt|poweroff)\b(?![\w.-])/i, label: 'system power command' },
|
|
31
|
+
// Windows system-drive destruction.
|
|
32
|
+
{ pattern: /\bformat\s+(?:\/[a-z]+\s+)*[a-z]:/i, label: 'drive format' },
|
|
33
|
+
{ pattern: /\bdiskpart\b/i, label: 'disk partitioning (diskpart)' },
|
|
34
|
+
{ pattern: /\bbcdedit\b/i, label: 'boot configuration edit (bcdedit)' },
|
|
35
|
+
{ pattern: /\b(?:del|erase|rd|rmdir)\s+(?:\/[a-z]+\s+)*[a-z]:\\(?:\s|$)/i, label: 'system-drive recursive delete' },
|
|
36
|
+
// Shell redirection overwriting a block device.
|
|
37
|
+
{ pattern: />{1,2}\s*\/dev\/(?:sd[a-z]|hd[a-z]|nvme\d+n\d+|xvd[a-z])\b/, label: 'write to block device' },
|
|
38
|
+
];
|
|
39
|
+
/** `rm` targets that are unambiguously catastrophic when combined with -rf. */
|
|
40
|
+
function isCatastrophicRmTarget(target) {
|
|
41
|
+
const stripped = target.replace(/["']/g, '');
|
|
42
|
+
if (stripped === '*' || stripped === '/*')
|
|
43
|
+
return true;
|
|
44
|
+
const normalized = stripped.replace(/[/\\]+$/, '') || '/';
|
|
45
|
+
return (normalized === '/' ||
|
|
46
|
+
normalized === '~' ||
|
|
47
|
+
normalized.startsWith('~/') ||
|
|
48
|
+
normalized === '$HOME' ||
|
|
49
|
+
normalized === '${HOME}' ||
|
|
50
|
+
normalized.startsWith('$HOME/') ||
|
|
51
|
+
normalized.startsWith('${HOME}/'));
|
|
52
|
+
}
|
|
53
|
+
/** Tokenize each `rm ...` segment; deny only recursive+force against root/home/wildcard targets. */
|
|
54
|
+
function findRmRfViolation(command) {
|
|
55
|
+
const segments = command.match(/\brm\b[^;&|()]*/g) ?? [];
|
|
56
|
+
for (const segment of segments) {
|
|
57
|
+
const tokens = segment.split(/\s+/).filter(Boolean).slice(1);
|
|
58
|
+
let recursive = false;
|
|
59
|
+
let force = false;
|
|
60
|
+
const targets = [];
|
|
61
|
+
for (const token of tokens) {
|
|
62
|
+
if (token === '--')
|
|
63
|
+
continue;
|
|
64
|
+
if (token.startsWith('-')) {
|
|
65
|
+
if (token === '--recursive')
|
|
66
|
+
recursive = true;
|
|
67
|
+
else if (token === '--force')
|
|
68
|
+
force = true;
|
|
69
|
+
else if (/^-[a-zA-Z]+$/.test(token)) {
|
|
70
|
+
if (/r/i.test(token))
|
|
71
|
+
recursive = true;
|
|
72
|
+
if (/f/i.test(token))
|
|
73
|
+
force = true;
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
targets.push(token);
|
|
78
|
+
}
|
|
79
|
+
if (!recursive || !force)
|
|
80
|
+
continue;
|
|
81
|
+
for (const target of targets) {
|
|
82
|
+
if (isCatastrophicRmTarget(target)) {
|
|
83
|
+
return `recursive forced delete of '${target}'`;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Return a human-readable violation when the command matches the hard-deny
|
|
91
|
+
* list, else null. `extraPatterns` are user regex strings (compiled
|
|
92
|
+
* case-insensitive; invalid ones are skipped).
|
|
93
|
+
*/
|
|
94
|
+
export function findDangerousCommandViolation(command, extraPatterns) {
|
|
95
|
+
const rmViolation = findRmRfViolation(command);
|
|
96
|
+
if (rmViolation)
|
|
97
|
+
return rmViolation;
|
|
98
|
+
for (const { pattern, label } of DANGEROUS_COMMAND_PATTERNS) {
|
|
99
|
+
if (pattern.test(command))
|
|
100
|
+
return label;
|
|
101
|
+
}
|
|
102
|
+
for (const source of extraPatterns ?? []) {
|
|
103
|
+
if (typeof source !== 'string' || !source)
|
|
104
|
+
continue;
|
|
105
|
+
let pattern;
|
|
106
|
+
try {
|
|
107
|
+
pattern = new RegExp(source, 'i');
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (pattern.test(command))
|
|
113
|
+
return `custom dangerous pattern /${source}/i`;
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
function toPosix(value) {
|
|
118
|
+
return value.split(path.sep).join('/');
|
|
119
|
+
}
|
|
120
|
+
function globToRegExp(glob) {
|
|
121
|
+
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.');
|
|
122
|
+
return new RegExp(`^${escaped}$`, 'i');
|
|
123
|
+
}
|
|
124
|
+
function matchesProtectedEntry(candidateAbs, workDir, entry) {
|
|
125
|
+
const isDirectory = entry.endsWith('/');
|
|
126
|
+
const cleanEntry = isDirectory ? entry.slice(0, -1) : entry;
|
|
127
|
+
if (!cleanEntry)
|
|
128
|
+
return false;
|
|
129
|
+
const candidatePosix = toPosix(path.resolve(candidateAbs));
|
|
130
|
+
if (path.isAbsolute(cleanEntry) || /^[a-z]:/i.test(cleanEntry)) {
|
|
131
|
+
const entryAbs = toPosix(path.resolve(cleanEntry));
|
|
132
|
+
return isDirectory
|
|
133
|
+
? candidatePosix === entryAbs || candidatePosix.startsWith(`${entryAbs}/`)
|
|
134
|
+
: candidatePosix === entryAbs;
|
|
135
|
+
}
|
|
136
|
+
const relative = toPosix(path.relative(workDir, candidateAbs));
|
|
137
|
+
if (/[*?]/.test(cleanEntry)) {
|
|
138
|
+
const pattern = globToRegExp(cleanEntry);
|
|
139
|
+
return pattern.test(relative) || pattern.test(path.basename(candidateAbs));
|
|
140
|
+
}
|
|
141
|
+
if (isDirectory) {
|
|
142
|
+
// Directory prefix: any matching path segment (covers nested .git/, node_modules/).
|
|
143
|
+
if (relative === cleanEntry || relative.startsWith(`${cleanEntry}/`))
|
|
144
|
+
return true;
|
|
145
|
+
return relative.split('/').includes(cleanEntry);
|
|
146
|
+
}
|
|
147
|
+
return relative === cleanEntry || path.basename(candidateAbs) === cleanEntry;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Return a human-readable violation when `candidatePath` (relative or
|
|
151
|
+
* absolute, resolved against `workDir`) hits one of `protectedPaths`, else
|
|
152
|
+
* null. Entries ending in `/` are directory prefixes; `*`/`?` act as globs
|
|
153
|
+
* matched against the relative path and the basename.
|
|
154
|
+
*/
|
|
155
|
+
export function findProtectedPathViolation(candidatePath, workDir, protectedPaths) {
|
|
156
|
+
const trimmed = candidatePath.trim().replace(/["']+$/, '').replace(/^["']+/, '');
|
|
157
|
+
if (!trimmed)
|
|
158
|
+
return null;
|
|
159
|
+
const resolved = path.isAbsolute(trimmed) || /^[a-z]:/i.test(trimmed)
|
|
160
|
+
? path.resolve(trimmed)
|
|
161
|
+
: path.resolve(workDir, trimmed);
|
|
162
|
+
for (const entry of protectedPaths) {
|
|
163
|
+
if (typeof entry === 'string' && entry.trim() && matchesProtectedEntry(resolved, path.resolve(workDir), entry.trim())) {
|
|
164
|
+
return `protected path '${entry.trim()}'`;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
/** Best-effort scan for `>`/`>>` redirections into protected paths. */
|
|
170
|
+
function findProtectedRedirectionViolation(command, workDir, protectedPaths) {
|
|
171
|
+
const matches = command.match(/>{1,2}\s*[^\s;&|]+/g) ?? [];
|
|
172
|
+
for (const match of matches) {
|
|
173
|
+
const target = match.replace(/>{1,2}\s*/, '');
|
|
174
|
+
const violation = findProtectedPathViolation(target, workDir, protectedPaths);
|
|
175
|
+
if (violation)
|
|
176
|
+
return `shell redirection into ${violation}`;
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
function deny(state, detail) {
|
|
181
|
+
state.behavior = 'deny';
|
|
182
|
+
state.reason =
|
|
183
|
+
`[security extension] Blocked ${detail}. ` +
|
|
184
|
+
'Disable via /extensions security off or settings extensions.security.enabled=false.';
|
|
185
|
+
}
|
|
186
|
+
/** Pre-listener: dangerous shell commands and protected-path writes. No-op when disabled. */
|
|
187
|
+
export function createSecurityPreListener(toggles) {
|
|
188
|
+
return async (call, state) => {
|
|
189
|
+
if (state.behavior === 'deny')
|
|
190
|
+
return;
|
|
191
|
+
if (!toggles.isEnabled('security'))
|
|
192
|
+
return;
|
|
193
|
+
const config = toggles.getConfig('security');
|
|
194
|
+
const protectedPaths = [...DEFAULT_PROTECTED_PATHS, ...(config.protectedPaths ?? [])];
|
|
195
|
+
const input = isRecord(call.input) ? call.input : {};
|
|
196
|
+
// Any tool whose input carries a shell command string (Bash, PowerShell, ...).
|
|
197
|
+
if (typeof input.command === 'string') {
|
|
198
|
+
const commandViolation = findDangerousCommandViolation(input.command, config.extraDangerousPatterns);
|
|
199
|
+
if (commandViolation) {
|
|
200
|
+
deny(state, `dangerous shell command: ${commandViolation}`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const redirectionViolation = findProtectedRedirectionViolation(input.command, call.workDir, protectedPaths);
|
|
204
|
+
if (redirectionViolation) {
|
|
205
|
+
deny(state, redirectionViolation);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// File-path inputs on mutating tools; read-only tools (Read, Grep) pass.
|
|
210
|
+
if (call.adapter.isReadOnly?.(call.input) === true)
|
|
211
|
+
return;
|
|
212
|
+
for (const field of FILE_PATH_FIELDS) {
|
|
213
|
+
const value = input[field];
|
|
214
|
+
if (typeof value !== 'string' || !value.trim())
|
|
215
|
+
continue;
|
|
216
|
+
const pathViolation = findProtectedPathViolation(value, call.workDir, protectedPaths);
|
|
217
|
+
if (pathViolation) {
|
|
218
|
+
deny(state, `write to ${pathViolation}`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** Contribution: attaches the security pre-listener to the tool-policy listener registry. */
|
|
225
|
+
export function createSecurityPolicyContribution(toggles) {
|
|
226
|
+
return {
|
|
227
|
+
id: 'hadamard.ext.security',
|
|
228
|
+
apply(ctx) {
|
|
229
|
+
const registry = ctx.services.get(toolPolicyListenerRegistryKey);
|
|
230
|
+
if (!registry)
|
|
231
|
+
return;
|
|
232
|
+
const listener = createSecurityPreListener(toggles);
|
|
233
|
+
registry.addPre(listener);
|
|
234
|
+
return () => { registry.removePre(listener); };
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=securityPolicy.js.map
|