@dollhousemcp/mcp-server 2.0.16 → 2.0.18

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md.backup +18 -0
  3. package/dist/elements/BaseElement.d.ts +1 -0
  4. package/dist/elements/BaseElement.d.ts.map +1 -1
  5. package/dist/elements/BaseElement.js +7 -1
  6. package/dist/elements/agents/AgentManager.js +2 -2
  7. package/dist/elements/base/BaseElementManager.d.ts.map +1 -1
  8. package/dist/elements/base/BaseElementManager.js +17 -1
  9. package/dist/elements/base/ElementFileOperations.js +2 -2
  10. package/dist/elements/ensembles/EnsembleManager.js +3 -3
  11. package/dist/elements/memories/MemoryManager.d.ts.map +1 -1
  12. package/dist/elements/memories/MemoryManager.js +14 -3
  13. package/dist/elements/skills/SkillManager.js +2 -2
  14. package/dist/elements/templates/TemplateManager.js +2 -2
  15. package/dist/generated/version.d.ts +2 -2
  16. package/dist/generated/version.js +3 -3
  17. package/dist/handlers/ElementCRUDHandler.d.ts.map +1 -1
  18. package/dist/handlers/ElementCRUDHandler.js +3 -2
  19. package/dist/handlers/element-crud/createElement.d.ts.map +1 -1
  20. package/dist/handlers/element-crud/createElement.js +6 -2
  21. package/dist/handlers/element-crud/editElement.d.ts.map +1 -1
  22. package/dist/handlers/element-crud/editElement.js +6 -2
  23. package/dist/handlers/element-crud/helpers.d.ts +2 -0
  24. package/dist/handlers/element-crud/helpers.d.ts.map +1 -1
  25. package/dist/handlers/element-crud/helpers.js +21 -2
  26. package/dist/handlers/mcp-aql/IntrospectionResolver.d.ts.map +1 -1
  27. package/dist/handlers/mcp-aql/IntrospectionResolver.js +34 -7
  28. package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts +1 -0
  29. package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
  30. package/dist/handlers/mcp-aql/MCPAQLHandler.js +50 -14
  31. package/dist/handlers/mcp-aql/OperationSchema.d.ts.map +1 -1
  32. package/dist/handlers/mcp-aql/OperationSchema.js +3 -2
  33. package/dist/handlers/mcp-aql/evaluatePermission.d.ts.map +1 -1
  34. package/dist/handlers/mcp-aql/evaluatePermission.js +2 -1
  35. package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts +17 -1
  36. package/dist/handlers/mcp-aql/policies/ElementPolicies.d.ts.map +1 -1
  37. package/dist/handlers/mcp-aql/policies/ElementPolicies.js +88 -4
  38. package/dist/handlers/strategies/AgentActivationStrategy.d.ts.map +1 -1
  39. package/dist/handlers/strategies/AgentActivationStrategy.js +5 -1
  40. package/dist/handlers/strategies/BaseActivationStrategy.d.ts +1 -0
  41. package/dist/handlers/strategies/BaseActivationStrategy.d.ts.map +1 -1
  42. package/dist/handlers/strategies/BaseActivationStrategy.js +15 -1
  43. package/dist/handlers/strategies/EnsembleActivationStrategy.d.ts.map +1 -1
  44. package/dist/handlers/strategies/EnsembleActivationStrategy.js +5 -1
  45. package/dist/handlers/strategies/MemoryActivationStrategy.d.ts.map +1 -1
  46. package/dist/handlers/strategies/MemoryActivationStrategy.js +5 -1
  47. package/dist/handlers/strategies/PersonaActivationStrategy.d.ts.map +1 -1
  48. package/dist/handlers/strategies/PersonaActivationStrategy.js +5 -1
  49. package/dist/handlers/strategies/SkillActivationStrategy.d.ts.map +1 -1
  50. package/dist/handlers/strategies/SkillActivationStrategy.js +5 -1
  51. package/dist/handlers/strategies/TemplateActivationStrategy.d.ts.map +1 -1
  52. package/dist/handlers/strategies/TemplateActivationStrategy.js +7 -2
  53. package/dist/persona/PersonaElement.js +2 -2
  54. package/dist/services/SerializationService.d.ts.map +1 -1
  55. package/dist/services/SerializationService.js +7 -1
  56. package/dist/types/elements/IElement.d.ts +9 -0
  57. package/dist/types/elements/IElement.d.ts.map +1 -1
  58. package/dist/types/elements/IElement.js +1 -1
  59. package/dist/utils/permissionHooks.d.ts +39 -3
  60. package/dist/utils/permissionHooks.d.ts.map +1 -1
  61. package/dist/utils/permissionHooks.js +651 -74
  62. package/dist/web/public/permissions.css +190 -2
  63. package/dist/web/public/permissions.js +209 -56
  64. package/dist/web/public/setup.js +452 -108
  65. package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
  66. package/dist/web/routes/permissionRoutes.js +108 -17
  67. package/dist/web/routes/setupRoutes.d.ts +1 -0
  68. package/dist/web/routes/setupRoutes.d.ts.map +1 -1
  69. package/dist/web/routes/setupRoutes.js +128 -42
  70. package/package.json +3 -1
  71. package/scripts/pretooluse-dollhouse.sh +39 -1
  72. package/scripts/pretooluse-vscode.sh +163 -0
  73. package/scripts/pretooluse-windsurf.sh +166 -4
  74. package/server.json +2 -2
@@ -18,15 +18,15 @@
18
18
  const PLATFORMS = [
19
19
  // Claude Desktop & Claude Code panels are handwritten in HTML (unique structure)
20
20
  { id: 'claude-desktop', rootKey: 'mcpServers' },
21
- { id: 'claude-code', rootKey: 'mcpServers', cli: 'claude', hookSupport: 'verified', hookCommand: `bash ${HOOK_BASE_SCRIPT_PATH}`, hookConfigPath: '<code>~/.claude/settings.json</code>' },
21
+ { id: 'claude-code', rootKey: 'mcpServers', cli: 'claude', hookCommand: `bash ${HOOK_BASE_SCRIPT_PATH}`, hookConfigPath: '<code>~/.claude/settings.json</code>' },
22
22
  // These panels are generated from this data by renderGeneratedPanels()
23
- { id: 'cursor', rootKey: 'mcpServers', installClient: 'cursor', openClient: 'cursor', configPath: '<code>.cursor/mcp.json</code> in your project, or <code>~/.cursor/mcp.json</code> for all projects', hint: 'Or configure via Settings &gt; MCP Servers in the Cursor UI.', hookSupport: 'manual', hookCommand: `bash ${HOOKS_DIR}/pretooluse-cursor.sh`, hookConfigPath: '<code>.cursor/mcp.json</code> in your project, or <code>~/.cursor/mcp.json</code> for all projects' },
24
- { id: 'vscode', rootKey: 'servers', installClient: 'vscode', configPath: '<code>.vscode/mcp.json</code> in your workspace', hint: 'VS Code uses <code>"servers"</code>, not <code>"mcpServers"</code>.' },
25
- { id: 'codex', rootKey: 'mcpServers', installClient: 'codex', openClient: 'codex', cli: 'codex', toml: true, tomlPath: '<code>~/.codex/config.toml</code> (Codex uses TOML, not JSON)', hookSupport: 'manual', hookCommand: `bash ${HOOKS_DIR}/pretooluse-codex.sh`, hookConfigPath: '<code>~/.codex/config.toml</code>' },
26
- { id: 'gemini', rootKey: 'mcpServers', installClient: 'gemini-cli', openClient: 'gemini-cli', cli: 'gemini', configPath: '<code>~/.gemini/settings.json</code> or <code>.gemini/settings.json</code> in your project', hookSupport: 'manual', hookCommand: `bash ${HOOKS_DIR}/pretooluse-gemini.sh`, hookConfigPath: '<code>~/.gemini/settings.json</code> or <code>.gemini/settings.json</code> in your project' },
27
- { id: 'windsurf', rootKey: 'mcpServers', installClient: 'windsurf', openClient: 'windsurf', configPath: '<code>~/.codeium/windsurf/mcp_config.json</code>', hint: 'Or click the MCPs icon in the Cascade panel &gt; Configure.', hookSupport: 'manual', hookCommand: `bash ${HOOKS_DIR}/pretooluse-windsurf.sh`, hookConfigPath: '<code>~/.codeium/windsurf/mcp_config.json</code>' },
28
- { id: 'cline', rootKey: 'mcpServers', installClient: 'cline', configPath: '<code>cline_mcp_settings.json</code> via Cline\'s top nav &gt; Configure &gt; Advanced MCP Settings' },
29
- { id: 'lmstudio', rootKey: 'mcpServers', openClient: 'lmstudio', configPath: '<code>~/.lmstudio/mcp.json</code> (or open via Program tab &gt; Install &gt; Edit mcp.json)', hint: 'Restart LM Studio after saving.' },
23
+ { id: 'cursor', rootKey: 'mcpServers', installClient: 'cursor', openClient: 'cursor', configPath: '<code>.cursor/mcp.json</code> in your project, or <code>~/.cursor/mcp.json</code> for all projects', hint: 'Or configure via Settings &gt; MCP Servers in the Cursor UI.', hookCommand: `bash ${HOOKS_DIR}/pretooluse-cursor.sh`, hookConfigPath: '<code>.cursor/hooks.json</code> in your project, or <code>~/.cursor/hooks.json</code> for all projects' },
24
+ { id: 'vscode', rootKey: 'servers', installClient: 'vscode', configPath: '<code>.vscode/mcp.json</code> in your workspace', hint: 'VS Code uses <code>"servers"</code>, not <code>"mcpServers"</code>.', hookCommand: `bash ${HOOKS_DIR}/pretooluse-vscode.sh`, hookConfigPath: '<code>~/.copilot/hooks/dollhouse-permissions.json</code> plus <code>chat.hookFilesLocations</code> in VS Code user settings' },
25
+ { id: 'codex', rootKey: 'mcpServers', installClient: 'codex', openClient: 'codex', cli: 'codex', toml: true, tomlPath: '<code>~/.codex/config.toml</code> (Codex uses TOML, not JSON)', hookCommand: `bash ${HOOKS_DIR}/pretooluse-codex.sh`, hookConfigPath: '<code>~/.codex/hooks.json</code> and <code>~/.codex/config.toml</code>' },
26
+ { id: 'gemini', rootKey: 'mcpServers', installClient: 'gemini-cli', openClient: 'gemini-cli', cli: 'gemini', configPath: '<code>~/.gemini/settings.json</code> or <code>.gemini/settings.json</code> in your project', hookCommand: `bash ${HOOKS_DIR}/pretooluse-gemini.sh`, hookConfigPath: '<code>~/.gemini/settings.json</code> or <code>.gemini/settings.json</code> in your project' },
27
+ { id: 'windsurf', rootKey: 'mcpServers', installClient: 'windsurf', openClient: 'windsurf', configPath: '<code>~/.codeium/windsurf/mcp_config.json</code>', hint: 'Or click the MCPs icon in the Cascade panel &gt; Configure.', hookCommand: `bash ${HOOKS_DIR}/pretooluse-windsurf.sh`, hookConfigPath: '<code>~/.codeium/windsurf/hooks.json</code> or <code>.windsurf/hooks.json</code> in your project' },
28
+ { id: 'cline', rootKey: 'mcpServers', installClient: 'cline', openClient: 'cline', configPath: 'Cline stores MCP servers in <code>cline_mcp_settings.json</code> inside its extension settings. Use Configure Now or open the file directly.' },
29
+ { id: 'lmstudio', rootKey: 'mcpServers', installClient: 'lmstudio', openClient: 'lmstudio', configPath: '<code>~/.lmstudio/mcp.json</code> (or open via Program tab &gt; Install &gt; Edit mcp.json)', hint: 'Restart LM Studio after saving.' },
30
30
  ];
31
31
 
32
32
  const HOOK_BASE_SCRIPT = `#!/bin/bash
@@ -82,6 +82,94 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
82
82
  }
83
83
  }`;
84
84
 
85
+ const GEMINI_HOOK_SETTINGS = `{
86
+ "hooks": {
87
+ "BeforeTool": [
88
+ {
89
+ "matcher": ".*",
90
+ "hooks": [
91
+ {
92
+ "type": "command",
93
+ "command": "bash ${HOOKS_DIR}/pretooluse-gemini.sh"
94
+ }
95
+ ]
96
+ }
97
+ ]
98
+ }
99
+ }`;
100
+
101
+ const CODEX_HOOK_SETTINGS = `{
102
+ "hooks": {
103
+ "PreToolUse": [
104
+ {
105
+ "matcher": "Bash",
106
+ "hooks": [
107
+ {
108
+ "type": "command",
109
+ "command": "bash ${HOOKS_DIR}/pretooluse-codex.sh",
110
+ "statusMessage": "Checking Bash permissions"
111
+ }
112
+ ]
113
+ }
114
+ ]
115
+ }
116
+ }`;
117
+
118
+ const CURSOR_HOOK_SETTINGS = `{
119
+ "version": 1,
120
+ "hooks": {
121
+ "preToolUse": [
122
+ {
123
+ "type": "command",
124
+ "command": "bash ${HOOKS_DIR}/pretooluse-cursor.sh",
125
+ "matcher": ".*"
126
+ }
127
+ ]
128
+ }
129
+ }`;
130
+
131
+ const VSCODE_HOOK_SETTINGS = `{
132
+ "hooks": {
133
+ "PreToolUse": [
134
+ {
135
+ "matcher": "*",
136
+ "hooks": [
137
+ {
138
+ "type": "command",
139
+ "command": "bash ${HOOKS_DIR}/pretooluse-vscode.sh"
140
+ }
141
+ ]
142
+ }
143
+ ]
144
+ }
145
+ }`;
146
+
147
+ const VSCODE_HOOK_LOCATIONS_SETTINGS = `{
148
+ "chat.hookFilesLocations": {
149
+ "~/.copilot/hooks": true
150
+ }
151
+ }`;
152
+
153
+ const WINDSURF_HOOK_SETTINGS = `{
154
+ "hooks": {
155
+ "pre_run_command": [
156
+ {
157
+ "type": "command",
158
+ "command": "bash ${HOOKS_DIR}/pretooluse-windsurf.sh"
159
+ }
160
+ ],
161
+ "pre_mcp_tool_use": [
162
+ {
163
+ "type": "command",
164
+ "command": "bash ${HOOKS_DIR}/pretooluse-windsurf.sh"
165
+ }
166
+ ]
167
+ }
168
+ }`;
169
+
170
+ const CODEX_HOOK_FEATURES_TOML = `[features]
171
+ codex_hooks = true`;
172
+
85
173
  /** Build a JSON config block for a given npx command string */
86
174
  function jsonConfig(rootKey, npxCmd) {
87
175
  const parts = npxCmd.split(' ');
@@ -459,6 +547,32 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
459
547
  : `${msg}. Try the manual config below.`;
460
548
  };
461
549
 
550
+ const buildInstallPayload = (client) => {
551
+ const payload = { client };
552
+ if (currentMethod === 'global' && pinnedVersion && pinnedVersion !== 'latest') {
553
+ payload.version = pinnedVersion;
554
+ } else if (currentChannel !== 'latest') {
555
+ payload.channel = currentChannel;
556
+ }
557
+ return payload;
558
+ };
559
+
560
+ const applyInstallSuccessState = (btn, status, data, verified) => {
561
+ btn.textContent = 'Installed';
562
+ btn.classList.remove('is-loading');
563
+ btn.classList.add('is-success');
564
+ if (!status) return;
565
+
566
+ if (data.hookInstall?.supported && !data.hookInstall?.configured && data.hookInstall?.assetsPrepared) {
567
+ status.textContent = 'Configured MCP server. Dollhouse hook assets were also prepared; finish manual permission setup in Permissions & Security.';
568
+ } else {
569
+ status.textContent = verified
570
+ ? 'Verified — config written. Restart the application to activate.'
571
+ : 'Restart the application to activate.';
572
+ }
573
+ status.classList.add('is-success');
574
+ };
575
+
462
576
  /** Handle Configure Now button click */
463
577
  const handleInstallClick = async (btn) => {
464
578
  const client = btn.dataset.installClient;
@@ -476,17 +590,10 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
476
590
  }
477
591
 
478
592
  try {
479
- const payload = { client };
480
- if (currentMethod === 'global' && pinnedVersion && pinnedVersion !== 'latest') {
481
- payload.version = pinnedVersion;
482
- } else if (currentChannel !== 'latest') {
483
- payload.channel = currentChannel;
484
- }
485
-
486
593
  const res = await DollhouseAuth.apiFetch('/api/setup/install', {
487
594
  method: 'POST',
488
595
  headers: { 'Content-Type': 'application/json' },
489
- body: JSON.stringify(payload),
596
+ body: JSON.stringify(buildInstallPayload(client)),
490
597
  });
491
598
 
492
599
  const data = await res.json();
@@ -500,16 +607,7 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
500
607
  await fetchDetection();
501
608
  updateDetectionState();
502
609
  const verified = detectedConfigs[clientToPlatformReverse[client]]?.installed;
503
-
504
- btn.textContent = 'Installed';
505
- btn.classList.remove('is-loading');
506
- btn.classList.add('is-success');
507
- if (status) {
508
- status.textContent = verified
509
- ? 'Verified — config written. Restart the application to activate.'
510
- : 'Restart the application to activate.';
511
- status.classList.add('is-success');
512
- }
610
+ applyInstallSuccessState(btn, status, data, verified);
513
611
 
514
612
  // Show the completion banner after any successful install
515
613
  showCompletionBanner(client);
@@ -572,7 +670,7 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
572
670
  btn.classList.add('is-success');
573
671
 
574
672
  if (status) {
575
- status.textContent = 'Claude Code permissions are enabled. Restart Claude Code if it is already running.';
673
+ status.textContent = data.hookInstall?.message || 'Permissions are enabled. Restart the client if it is already running.';
576
674
  status.classList.add('is-success');
577
675
  }
578
676
  } catch (err) {
@@ -790,6 +888,7 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
790
888
  'claude': 'claude-desktop',
791
889
  'claude-code': 'claude-code',
792
890
  'cursor': 'cursor',
891
+ 'cline': 'cline',
793
892
  'windsurf': 'windsurf',
794
893
  'lmstudio': 'lmstudio',
795
894
  'gemini-cli': 'gemini',
@@ -867,70 +966,228 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
867
966
  }
868
967
  };
869
968
 
870
- const PERMISSION_PLATFORM_LABELS = {
871
- 'claude-desktop': 'Claude Desktop',
872
- 'claude-code': 'Claude Code',
873
- cursor: 'Cursor',
874
- vscode: 'VS Code',
875
- codex: 'Codex',
876
- gemini: 'Gemini CLI',
877
- windsurf: 'Windsurf',
878
- cline: 'Cline',
879
- lmstudio: 'LM Studio',
969
+ const PERMISSION_SUPPORT_MATRIX = {
970
+ 'claude-desktop': {
971
+ label: 'Claude Desktop',
972
+ supportLevel: 'unsupported',
973
+ statusTag: 'coming soon',
974
+ badgeClass: 'unsupported',
975
+ limitation: 'Claude Desktop can host DollhouseMCP, but this release does not ship a native permissions setup flow for it yet.',
976
+ },
977
+ 'claude-code': {
978
+ label: 'Claude Code',
979
+ supportLevel: 'full_native',
980
+ statusTag: 'claude code',
981
+ badgeClass: 'verified',
982
+ configPath: '<code>~/.claude/settings.json</code>',
983
+ scriptPath: HOOK_BASE_SCRIPT_PATH,
984
+ settingsBlock: CLAUDE_CODE_HOOK_SETTINGS,
985
+ limitation: 'Claude Code has the full native permission-hook path in this release.',
986
+ },
987
+ gemini: {
988
+ label: 'Gemini CLI',
989
+ supportLevel: 'partial_native',
990
+ statusTag: 'allow / deny',
991
+ badgeClass: 'manual',
992
+ configPath: '<code>~/.gemini/settings.json</code> or <code>.gemini/settings.json</code> in your project',
993
+ scriptPath: `${HOOKS_DIR}/pretooluse-gemini.sh`,
994
+ settingsBlock: GEMINI_HOOK_SETTINGS,
995
+ limitation: 'Gemini CLI exposes native BeforeTool hooks, but it does not support an ask/confirm response path. Confirmation-style policies currently degrade to deny.',
996
+ },
997
+ cursor: {
998
+ label: 'Cursor',
999
+ supportLevel: 'partial_native',
1000
+ statusTag: 'native hooks',
1001
+ badgeClass: 'manual',
1002
+ configPath: '<code>.cursor/hooks.json</code> in your project, or <code>~/.cursor/hooks.json</code> for all projects',
1003
+ scriptPath: `${HOOKS_DIR}/pretooluse-cursor.sh`,
1004
+ settingsBlock: CURSOR_HOOK_SETTINGS,
1005
+ limitation: 'Cursor exposes native hooks, but its permission handling still needs broader runtime verification across allow and ask decisions.',
1006
+ },
1007
+ vscode: {
1008
+ label: 'VS Code',
1009
+ supportLevel: 'partial_native',
1010
+ statusTag: 'native hooks',
1011
+ badgeClass: 'manual',
1012
+ configPath: '<code>~/.copilot/hooks/dollhouse-permissions.json</code> and VS Code user settings',
1013
+ scriptPath: `${HOOKS_DIR}/pretooluse-vscode.sh`,
1014
+ settingsBlock: VSCODE_HOOK_SETTINGS,
1015
+ featureBlock: VSCODE_HOOK_LOCATIONS_SETTINGS,
1016
+ featureHeading: '2. Enable <code>~/.copilot/hooks</code> in VS Code user settings',
1017
+ featureCopyLabel: 'Copy VS Code hookFilesLocations settings',
1018
+ limitation: 'VS Code exposes native PreToolUse hooks, but it ignores matcher values and uses tool names that differ from Claude Code. This adapter normalizes the common built-in tools we know about.',
1019
+ },
1020
+ windsurf: {
1021
+ label: 'Windsurf',
1022
+ supportLevel: 'partial_native',
1023
+ statusTag: 'allow / deny',
1024
+ badgeClass: 'manual',
1025
+ configPath: '<code>~/.codeium/windsurf/hooks.json</code> or <code>.windsurf/hooks.json</code> in your project',
1026
+ scriptPath: `${HOOKS_DIR}/pretooluse-windsurf.sh`,
1027
+ settingsBlock: WINDSURF_HOOK_SETTINGS,
1028
+ limitation: 'Windsurf exposes native pre-run and pre-MCP hooks, but they are binary allow-or-block hooks. Confirmation-style policies currently degrade to block.',
1029
+ },
1030
+ codex: {
1031
+ label: 'Codex',
1032
+ supportLevel: 'partial_native',
1033
+ statusTag: 'bash only',
1034
+ badgeClass: 'manual',
1035
+ configPath: '<code>~/.codex/hooks.json</code> and <code>~/.codex/config.toml</code>',
1036
+ scriptPath: `${HOOKS_DIR}/pretooluse-codex.sh`,
1037
+ settingsBlock: CODEX_HOOK_SETTINGS,
1038
+ featureBlock: CODEX_HOOK_FEATURES_TOML,
1039
+ limitation: 'Codex currently only supports native PreToolUse hooks for Bash, so this turns on Bash permission guardrails only.',
1040
+ },
1041
+ cline: {
1042
+ label: 'Cline',
1043
+ supportLevel: 'mcp_only',
1044
+ statusTag: 'mcp only',
1045
+ badgeClass: 'manual',
1046
+ limitation: 'Cline MCP setup is supported here, but native permission-hook automation is still incomplete in this release.',
1047
+ },
1048
+ lmstudio: {
1049
+ label: 'LM Studio',
1050
+ supportLevel: 'mcp_only',
1051
+ statusTag: 'mcp only',
1052
+ badgeClass: 'manual',
1053
+ limitation: 'LM Studio MCP setup is supported here, but permission enforcement currently relies on LM Studio built-in confirmations or a future fallback adapter.',
1054
+ },
880
1055
  };
881
1056
 
882
- const getPermissionStatusCopy = (platformId, detected) => {
883
- if (platformId === 'claude-code') {
884
- if (detected?.hookInstalled) {
885
- return {
886
- tone: 'info',
887
- titleText: 'Claude Code permission enforcement is enabled.',
888
- messageText: 'No further changes are needed here unless you want to reinstall the hook settings.',
889
- };
890
- }
1057
+ const getPermissionSupport = (platformId, detected) => {
1058
+ if (detected?.support) {
1059
+ return {
1060
+ ...PERMISSION_SUPPORT_MATRIX[platformId],
1061
+ supportLevel: detected.support.level || PERMISSION_SUPPORT_MATRIX[platformId]?.supportLevel,
1062
+ };
1063
+ }
1064
+ return PERMISSION_SUPPORT_MATRIX[platformId];
1065
+ };
891
1066
 
892
- if (detected?.installed) {
893
- return {
894
- tone: 'warning',
895
- titleText: 'Claude Code is connected for this client.',
896
- messageText: 'DollhouseMCP is configured as an MCP server. Use Configure Now below to also install the Claude Code permission hook.',
897
- };
898
- }
1067
+ const getFullNativePermissionStatusCopy = (support, detected) => {
1068
+ if (detected?.hookInstalled) {
1069
+ return {
1070
+ tone: 'info',
1071
+ titleText: `${support.label} permission enforcement is enabled.`,
1072
+ messageText: 'No further changes are needed here unless you want to reinstall the hook settings.',
1073
+ };
1074
+ }
899
1075
 
1076
+ if (detected?.installed) {
1077
+ return {
1078
+ tone: 'warning',
1079
+ titleText: `${support.label} is connected for this client.`,
1080
+ messageText: `DollhouseMCP is configured as an MCP server. Use Configure Now below to also install the ${support.label} permission hook.`,
1081
+ };
1082
+ }
1083
+
1084
+ return {
1085
+ tone: 'info',
1086
+ titleText: `${support.label} permissions are not configured yet.`,
1087
+ messageText: `First connect DollhouseMCP using Auto-updating or Pinned version, then use Configure Now below to install the ${support.label} permission hook.`,
1088
+ };
1089
+ };
1090
+
1091
+ const getPartialPermissionStatusCopy = (support, detected) => {
1092
+ const activationLabel = support.label === 'Codex' ? 'Bash guardrails' : 'permission hooks';
1093
+ if (detected?.hookInstalled) {
900
1094
  return {
901
1095
  tone: 'info',
902
- titleText: 'Claude Code permissions are not configured yet.',
903
- messageText: 'First connect DollhouseMCP using Auto-updating or Pinned version, then use Configure Now below to install the Claude Code permission hook.',
1096
+ titleText: `${support.label} ${activationLabel} are enabled.`,
1097
+ messageText: support.limitation,
904
1098
  };
905
1099
  }
906
1100
 
907
- const support = PLATFORMS.find((platform) => platform.id === platformId)?.hookSupport || 'unsupported';
908
- if (support === 'manual') {
909
- if (detected?.installed) {
910
- return {
911
- tone: 'warning',
912
- titleText: 'DollhouseMCP is connected for this client.',
913
- messageText: 'DollhouseMCP is configured here, but permission enforcement is separate. Use the manual hook steps below to turn it on for this client.',
914
- };
915
- }
1101
+ if (detected?.installed) {
1102
+ return {
1103
+ tone: 'warning',
1104
+ titleText: `${support.label} is connected for this client.`,
1105
+ messageText: `DollhouseMCP is configured as an MCP server. Use Configure Now below to turn on ${support.label}'s native ${activationLabel}.`,
1106
+ };
1107
+ }
916
1108
 
1109
+ return {
1110
+ tone: 'info',
1111
+ titleText: `${support.label} ${activationLabel} are not configured yet.`,
1112
+ messageText: `First connect DollhouseMCP using Auto-updating or Pinned version, then use Configure Now below to install ${support.label}'s native ${activationLabel}.`,
1113
+ };
1114
+ };
1115
+
1116
+ const getMcpOnlyPermissionStatusCopy = (support, detected) => {
1117
+ if (detected?.installed) {
1118
+ return {
1119
+ tone: 'warning',
1120
+ titleText: `${support.label} is connected for this client.`,
1121
+ messageText: `${support.limitation} This release keeps that client in the MCP and fallback lane for now.`,
1122
+ };
1123
+ }
1124
+
1125
+ return {
1126
+ tone: 'info',
1127
+ titleText: `${support.label} supports MCP setup in this release.`,
1128
+ messageText: `${support.limitation} Use Auto-updating or Pinned version above to connect DollhouseMCP first.`,
1129
+ };
1130
+ };
1131
+
1132
+ const getManualPermissionStatusCopy = (support, detected) => {
1133
+ if (detected?.hookAssetsPrepared) {
917
1134
  return {
918
1135
  tone: 'info',
919
- titleText: 'Manual permissions setup is available for this client.',
920
- messageText: 'Use the steps below if you want to turn on permission enforcement for this client manually.',
1136
+ titleText: 'Hook bridge files are already prepared for this client.',
1137
+ messageText: 'Finish the client-specific hook registration below to turn on permission enforcement.',
1138
+ };
1139
+ }
1140
+ if (detected?.installed) {
1141
+ return {
1142
+ tone: 'warning',
1143
+ titleText: 'DollhouseMCP is connected for this client.',
1144
+ messageText: 'DollhouseMCP is configured here, but permission enforcement is separate. Use the manual hook steps below to turn it on for this client.',
921
1145
  };
922
1146
  }
923
1147
 
924
- const platformLabel = PERMISSION_PLATFORM_LABELS[platformId] || 'this client';
925
1148
  return {
926
- tone: detected?.installed ? 'warning' : 'neutral',
927
- titleText: `Permissions & security tools are unavailable for ${platformLabel} right now.`,
928
- messageText: detected?.installed
929
- ? 'DollhouseMCP is connected for this client, but this release does not include a supported permissions setup flow here yet.'
930
- : 'This release does not include a supported permissions setup flow for this client yet.',
1149
+ tone: 'info',
1150
+ titleText: 'Manual permissions setup is available for this client.',
1151
+ messageText: 'Use the steps below if you want to turn on permission enforcement for this client manually.',
931
1152
  };
932
1153
  };
933
1154
 
1155
+ const getUnsupportedPermissionStatusCopy = (support, detected) => ({
1156
+ tone: detected?.installed ? 'warning' : 'neutral',
1157
+ titleText: `Permissions & security tools are unavailable for ${support.label} right now.`,
1158
+ messageText: detected?.installed
1159
+ ? 'DollhouseMCP is connected for this client, but this release does not include a supported permissions setup flow here yet.'
1160
+ : support.limitation,
1161
+ });
1162
+
1163
+ const getPermissionStatusCopy = (platformId, detected) => {
1164
+ const support = getPermissionSupport(platformId, detected);
1165
+ if (!support) {
1166
+ return getUnsupportedPermissionStatusCopy({
1167
+ label: 'this client',
1168
+ limitation: 'This release does not include a supported permissions setup flow for this client yet.',
1169
+ }, detected);
1170
+ }
1171
+
1172
+ if (support.supportLevel === 'full_native') {
1173
+ return getFullNativePermissionStatusCopy(support, detected);
1174
+ }
1175
+
1176
+ if (support.supportLevel === 'partial_native') {
1177
+ return getPartialPermissionStatusCopy(support, detected);
1178
+ }
1179
+
1180
+ if (support.supportLevel === 'mcp_only') {
1181
+ return getMcpOnlyPermissionStatusCopy(support, detected);
1182
+ }
1183
+
1184
+ if (support.supportLevel === 'manual') {
1185
+ return getManualPermissionStatusCopy(support, detected);
1186
+ }
1187
+
1188
+ return getUnsupportedPermissionStatusCopy(support, detected);
1189
+ };
1190
+
934
1191
  const updatePermissionStatus = (panel, platformId, detected) => {
935
1192
  const status = panel?.querySelector('.setup-permission-status');
936
1193
  if (!status) return;
@@ -950,6 +1207,7 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
950
1207
  const panel = document.getElementById('setup-panel-' + platformId);
951
1208
  const tabBtn = document.getElementById('setup-tab-' + platformId);
952
1209
  updatePermissionStatus(panel, platformId, detected);
1210
+ updatePermissionInstallButton(panel?.querySelector('.setup-permission-install-btn'), detected);
953
1211
 
954
1212
  if (!detected?.installed) return;
955
1213
 
@@ -958,7 +1216,6 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
958
1216
  updateDetectionNotice(panel?.querySelector('.setup-installed-notice'), matches);
959
1217
  updateDetectionBadge(tabBtn?.querySelector('.setup-tab-badge'), matches);
960
1218
  updateDetectionButton(panel?.querySelector('.setup-install-btn'), matches);
961
- updatePermissionInstallButton(panel?.querySelector('.setup-permission-install-btn'), detected);
962
1219
 
963
1220
  // Refresh the "Current config" code block with the latest detected config
964
1221
  if (detected.currentConfig && panel) {
@@ -1120,49 +1377,136 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
1120
1377
  return html;
1121
1378
  };
1122
1379
 
1123
- const renderPermissionSection = (p) => {
1124
- const hookSupport = p.hookSupport || 'unsupported';
1125
- const configPath = p.hookConfigPath || p.configPath || p.tomlPath || 'this client’s user configuration';
1380
+ const buildPartialAutoHint = (p, partial) => {
1381
+ const base = partial.limitation;
1382
+ if (p.id === 'codex') {
1383
+ return `${base} This automatic path writes the shared hook bridge, updates <code>~/.codex/hooks.json</code>, and enables <code>features.codex_hooks</code> in <code>~/.codex/config.toml</code>.`;
1384
+ }
1385
+ if (p.id === 'vscode') {
1386
+ return `${base} This automatic path writes the shared hook bridge, creates <code>~/.copilot/hooks/dollhouse-permissions.json</code>, and enables <code>~/.copilot/hooks</code> in VS Code's <code>chat.hookFilesLocations</code> setting.`;
1387
+ }
1388
+ return `${base} This automatic path writes the shared hook bridge and updates ${partial.configPath}.`;
1389
+ };
1126
1390
 
1127
- if (hookSupport === 'verified' && p.id === 'claude-code') {
1128
- return `<div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1129
- <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--verified">claude code</span></h3>
1130
- <div class="setup-permission-status" data-state="info">
1131
- <strong class="setup-permission-status-title"></strong>
1132
- <p class="setup-permission-status-msg"></p>
1133
- </div>
1134
- <div class="setup-install-row">
1135
- <button class="setup-btn setup-btn-primary setup-permission-install-btn" type="button" data-permission-install-client="claude-code">Configure Now</button>
1136
- <span class="setup-install-status" data-permission-install-status="claude-code"></span>
1391
+ const buildPartialFeatureHeading = (p, partial) => {
1392
+ if (partial.featureHeading) return partial.featureHeading;
1393
+ if (p.id === 'codex') return '2. Enable Codex hooks in <code>~/.codex/config.toml</code>';
1394
+ return '2. Add the additional client settings';
1395
+ };
1396
+
1397
+ const renderVerifiedPermissionSection = (p, verified) => {
1398
+ const permissionInstallClient = p.installClient || p.id;
1399
+ return `<div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1400
+ <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--verified">${verified.statusTag}</span></h3>
1401
+ <div class="setup-permission-status" data-state="info">
1402
+ <strong class="setup-permission-status-title"></strong>
1403
+ <p class="setup-permission-status-msg"></p>
1404
+ </div>
1405
+ <div class="setup-install-row">
1406
+ <button class="setup-btn setup-btn-primary setup-permission-install-btn" type="button" data-permission-install-client="${permissionInstallClient}">Configure Now</button>
1407
+ <span class="setup-install-status" data-permission-install-status="${permissionInstallClient}"></span>
1408
+ </div>
1409
+ <p class="setup-hint">This writes the shared hook bridge assets and updates ${verified.configPath} automatically.</p>
1410
+ </div>
1411
+ <div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1412
+ <details class="setup-manual-fallback">
1413
+ <summary>Manual fallback</summary>
1414
+ <div class="setup-manual-fallback-body">
1415
+ <h4>1. Save the shared hook bridge once</h4>
1416
+ <p>Save this file as <code>${HOOK_BASE_SCRIPT_PATH}</code>, then make it executable with <code>chmod +x ${HOOK_BASE_SCRIPT_PATH}</code>.</p>
1417
+ <div class="setup-code-block"><button class="setup-copy-btn" type="button" data-copy-text='${escapeAttr(HOOK_BASE_SCRIPT)}' aria-label="Copy shared hook bridge">Copy</button>
1418
+ <pre><code>${escapeHtml(HOOK_BASE_SCRIPT)}</code></pre>
1419
+ </div>
1420
+ <h4>2. Add the ${verified.label} hook settings</h4>
1421
+ <p>Add this block to ${verified.configPath} so ${verified.label} can call the hook bridge before tool use.</p>
1422
+ <div class="setup-code-block"><button class="setup-copy-btn" type="button" data-copy-text='${escapeAttr(verified.settingsBlock)}' aria-label="Copy ${verified.label} hook settings">Copy</button>
1423
+ <pre><code>${escapeHtml(verified.settingsBlock)}</code></pre>
1424
+ </div>
1425
+ <p class="setup-hint">Command hook target: <code>${verified.scriptPath}</code></p>
1137
1426
  </div>
1138
- <p class="setup-hint">This writes the shared hook bridge to <code>${HOOK_BASE_SCRIPT_PATH}</code> and updates ${configPath} automatically.</p>
1427
+ </details>
1428
+ </div>`;
1429
+ };
1430
+
1431
+ const renderPartialPermissionSection = (p, partial) => {
1432
+ const permissionInstallClient = p.installClient || p.id;
1433
+ const autoHint = buildPartialAutoHint(p, partial);
1434
+ const featureHeading = buildPartialFeatureHeading(p, partial);
1435
+ const featureSection = partial.featureBlock
1436
+ ? `<h4>${featureHeading}</h4>
1437
+ <div class="setup-code-block"><button class="setup-copy-btn" type="button" data-copy-text='${escapeAttr(partial.featureBlock)}' aria-label="${escapeAttr(partial.featureCopyLabel || `Copy ${partial.label} settings`)}">Copy</button>
1438
+ <pre><code>${escapeHtml(partial.featureBlock)}</code></pre>
1439
+ </div>`
1440
+ : '';
1441
+ const stepNumber = partial.featureBlock ? '3' : '2';
1442
+
1443
+ return `<div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1444
+ <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--manual">${partial.statusTag}</span></h3>
1445
+ <div class="setup-permission-status" data-state="info">
1446
+ <strong class="setup-permission-status-title"></strong>
1447
+ <p class="setup-permission-status-msg"></p>
1448
+ </div>
1449
+ <div class="setup-install-row">
1450
+ <button class="setup-btn setup-btn-primary setup-permission-install-btn" type="button" data-permission-install-client="${permissionInstallClient}">Configure Now</button>
1451
+ <span class="setup-install-status" data-permission-install-status="${permissionInstallClient}"></span>
1139
1452
  </div>
1140
- <div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1141
- <details class="setup-manual-fallback">
1142
- <summary>Manual fallback</summary>
1143
- <div class="setup-manual-fallback-body">
1144
- <h4>1. Save the shared hook bridge once</h4>
1145
- <p>Save this file as <code>${HOOK_BASE_SCRIPT_PATH}</code>, then make it executable with <code>chmod +x ${HOOK_BASE_SCRIPT_PATH}</code>.</p>
1146
- <div class="setup-code-block"><button class="setup-copy-btn" type="button" data-copy-text='${escapeAttr(HOOK_BASE_SCRIPT)}' aria-label="Copy shared hook bridge">Copy</button>
1147
- <pre><code>${escapeHtml(HOOK_BASE_SCRIPT)}</code></pre>
1148
- </div>
1149
- <h4>2. Add the Claude Code hook settings</h4>
1150
- <p>Add this block to ${configPath} so Claude Code can call the hook bridge before tool use.</p>
1151
- <div class="setup-code-block"><button class="setup-copy-btn" type="button" data-copy-text='${escapeAttr(CLAUDE_CODE_HOOK_SETTINGS)}' aria-label="Copy Claude Code hook settings">Copy</button>
1152
- <pre><code>${escapeHtml(CLAUDE_CODE_HOOK_SETTINGS)}</code></pre>
1153
- </div>
1154
- <p class="setup-hint">Command hook target: <code>${HOOK_BASE_SCRIPT_PATH}</code></p>
1453
+ <p class="setup-hint">${autoHint}</p>
1454
+ </div>
1455
+ <div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1456
+ <details class="setup-manual-fallback">
1457
+ <summary>Manual fallback</summary>
1458
+ <div class="setup-manual-fallback-body">
1459
+ <h4>1. Save the shared hook bridge once</h4>
1460
+ <p>Save this file as <code>${HOOK_BASE_SCRIPT_PATH}</code>, then make it executable with <code>chmod +x ${HOOK_BASE_SCRIPT_PATH}</code>.</p>
1461
+ <div class="setup-code-block"><button class="setup-copy-btn" type="button" data-copy-text='${escapeAttr(HOOK_BASE_SCRIPT)}' aria-label="Copy shared hook bridge">Copy</button>
1462
+ <pre><code>${escapeHtml(HOOK_BASE_SCRIPT)}</code></pre>
1155
1463
  </div>
1156
- </details>
1157
- </div>`;
1464
+ ${featureSection}
1465
+ <h4>${stepNumber}. Add the ${partial.label} hook settings in ${partial.configPath}</h4>
1466
+ <div class="setup-code-block"><button class="setup-copy-btn" type="button" data-copy-text='${escapeAttr(partial.settingsBlock)}' aria-label="Copy ${partial.label} hook settings">Copy</button>
1467
+ <pre><code>${escapeHtml(partial.settingsBlock)}</code></pre>
1468
+ </div>
1469
+ <p class="setup-hint">Command hook target: <code>${partial.scriptPath}</code></p>
1470
+ </div>
1471
+ </details>
1472
+ </div>`;
1473
+ };
1474
+
1475
+ const renderMcpOnlyPermissionSection = (support) => `<div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1476
+ <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--${support.badgeClass}">${support.statusTag}</span></h3>
1477
+ <div class="setup-permission-status" data-state="info">
1478
+ <strong class="setup-permission-status-title"></strong>
1479
+ <p class="setup-permission-status-msg"></p>
1480
+ </div>
1481
+ <p class="setup-hint">${support.limitation}</p>
1482
+ </div>`;
1483
+
1484
+ const renderPermissionSection = (p) => {
1485
+ const support = getPermissionSupport(p.id);
1486
+ const configPath = p.hookConfigPath || p.configPath || p.tomlPath || 'this client’s user configuration';
1487
+
1488
+ if (!support) {
1489
+ return '';
1490
+ }
1491
+
1492
+ if (support.supportLevel === 'full_native') {
1493
+ return renderVerifiedPermissionSection(p, support);
1494
+ }
1495
+
1496
+ if (support.supportLevel === 'partial_native') {
1497
+ return renderPartialPermissionSection(p, support);
1498
+ }
1499
+
1500
+ if (support.supportLevel === 'mcp_only') {
1501
+ return renderMcpOnlyPermissionSection(support);
1158
1502
  }
1159
1503
 
1160
- if (hookSupport === 'manual') {
1504
+ if (support.supportLevel === 'manual') {
1161
1505
  const platformName = p.id === 'gemini' ? 'gemini' : p.id;
1162
1506
  const wrapperFilename = `pretooluse-${platformName}.sh`;
1163
1507
  const wrapperScript = buildHookWrapperScript(platformName);
1164
1508
  return `<div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1165
- <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--manual">manual setup</span></h3>
1509
+ <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--${support.badgeClass}">${support.statusTag}</span></h3>
1166
1510
  <div class="setup-permission-status" data-state="info">
1167
1511
  <strong class="setup-permission-status-title"></strong>
1168
1512
  <p class="setup-permission-status-msg"></p>
@@ -1180,7 +1524,7 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
1180
1524
  }
1181
1525
 
1182
1526
  return `<div class="setup-method setup-security-mode" data-setup-modes="permissions" hidden>
1183
- <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--unsupported">coming soon</span></h3>
1527
+ <h3>Permissions &amp; Security <span class="setup-support-badge setup-support-badge--${support.badgeClass}">${support.statusTag}</span></h3>
1184
1528
  <div class="setup-permission-status" data-state="neutral">
1185
1529
  <strong class="setup-permission-status-title"></strong>
1186
1530
  <p class="setup-permission-status-msg"></p>
@@ -1194,7 +1538,7 @@ exec bash "$SCRIPT_DIR/pretooluse-dollhouse.sh"`;
1194
1538
 
1195
1539
  intro.innerHTML = `<div class="setup-permissions-note">
1196
1540
  <strong>Permissions &amp; Security</strong>
1197
- <p>Use this mode to turn on permission enforcement for supported clients. Claude Code is fully guided in this release. Where we have workable manual steps for other clients, they are shown here. Otherwise, the client will be marked as coming soon.</p>
1541
+ <p>Use this mode to turn on permission enforcement for supported clients. Claude Code is fully guided in this release. Gemini CLI, Cursor, VS Code, Windsurf, and Codex have native partial support, while Cline and LM Studio stay in the MCP and fallback lane for now. Other clients will be marked as coming soon.</p>
1198
1542
  </div>`;
1199
1543
  };
1200
1544