@dollhousemcp/mcp-server 2.0.27 → 2.0.29

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 (42) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/generated/version.d.ts +2 -2
  3. package/dist/generated/version.js +3 -3
  4. package/dist/handlers/mcp-aql/OperationSchema.js +2 -2
  5. package/dist/handlers/mcp-aql/evaluatePermission.d.ts.map +1 -1
  6. package/dist/handlers/mcp-aql/evaluatePermission.js +9 -3
  7. package/dist/services/BuildInfoService.d.ts +6 -1
  8. package/dist/services/BuildInfoService.d.ts.map +1 -1
  9. package/dist/services/BuildInfoService.js +23 -3
  10. package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -1
  11. package/dist/tools/portfolio/submitToPortfolioTool.js +4 -3
  12. package/dist/utils/permissionHooks.d.ts +18 -0
  13. package/dist/utils/permissionHooks.d.ts.map +1 -1
  14. package/dist/utils/permissionHooks.js +182 -15
  15. package/dist/web/console/IngestRoutes.d.ts +7 -1
  16. package/dist/web/console/IngestRoutes.d.ts.map +1 -1
  17. package/dist/web/console/IngestRoutes.js +28 -6
  18. package/dist/web/console/LeaderForwardingSink.d.ts +6 -1
  19. package/dist/web/console/LeaderForwardingSink.d.ts.map +1 -1
  20. package/dist/web/console/LeaderForwardingSink.js +8 -2
  21. package/dist/web/console/UnifiedConsole.d.ts.map +1 -1
  22. package/dist/web/console/UnifiedConsole.js +6 -3
  23. package/dist/web/console/sessionClientPlatform.d.ts +11 -0
  24. package/dist/web/console/sessionClientPlatform.d.ts.map +1 -0
  25. package/dist/web/console/sessionClientPlatform.js +83 -0
  26. package/dist/web/public/permissions.js +10 -0
  27. package/dist/web/public/sessions.css +89 -9
  28. package/dist/web/public/sessions.js +160 -4
  29. package/dist/web/public/setup.js +40 -0
  30. package/dist/web/routes/permissionRoutes.d.ts +1 -0
  31. package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
  32. package/dist/web/routes/permissionRoutes.js +17 -7
  33. package/dist/web/routes/setupRoutes.d.ts +5 -1
  34. package/dist/web/routes/setupRoutes.d.ts.map +1 -1
  35. package/dist/web/routes/setupRoutes.js +28 -14
  36. package/dist/web/server.d.ts.map +1 -1
  37. package/dist/web/server.js +5 -1
  38. package/package.json +1 -1
  39. package/scripts/pretooluse-dollhouse.sh +36 -2
  40. package/scripts/pretooluse-vscode.sh +5 -2
  41. package/scripts/pretooluse-windsurf.sh +5 -2
  42. package/server.json +2 -2
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Best-effort MCP client platform detection for session metadata.
3
+ *
4
+ * This is intentionally conservative: when we cannot identify the host
5
+ * confidently, we return null rather than guessing from a session ID.
6
+ */
7
+ const CLIENT_PLATFORM_LABELS = {
8
+ 'claude-code': 'Claude Code',
9
+ 'claude-desktop': 'Claude Desktop',
10
+ codex: 'Codex',
11
+ cursor: 'Cursor',
12
+ vscode: 'VS Code',
13
+ windsurf: 'Windsurf',
14
+ 'gemini-cli': 'Gemini CLI',
15
+ cline: 'Cline',
16
+ lmstudio: 'LM Studio',
17
+ 'web-console': 'Web Console',
18
+ };
19
+ function normalizeText(value) {
20
+ return typeof value === 'string' ? value.trim().toLowerCase() : '';
21
+ }
22
+ function includesAny(value, needles) {
23
+ return needles.some((needle) => value.includes(needle));
24
+ }
25
+ function matchesAnySource(values, needles) {
26
+ return values.some((value) => includesAny(value, needles));
27
+ }
28
+ const TEXT_PLATFORM_MATCHERS = [
29
+ { platform: 'cursor', needles: ['cursor'] },
30
+ { platform: 'windsurf', needles: ['windsurf'] },
31
+ { platform: 'gemini-cli', needles: ['gemini'] },
32
+ { platform: 'cline', needles: ['cline'] },
33
+ { platform: 'lmstudio', needles: ['lmstudio', 'lm studio'] },
34
+ { platform: 'claude-desktop', needles: ['claude desktop'] },
35
+ { platform: 'claude-code', needles: ['claude code'] },
36
+ { platform: 'codex', needles: ['codex'] },
37
+ ];
38
+ export function normalizeSessionClientPlatformId(value) {
39
+ const normalized = normalizeText(value ?? undefined);
40
+ if (!normalized) {
41
+ return null;
42
+ }
43
+ if (normalized === 'gemini') {
44
+ return 'gemini-cli';
45
+ }
46
+ if (normalized in CLIENT_PLATFORM_LABELS) {
47
+ return normalized;
48
+ }
49
+ return null;
50
+ }
51
+ export function getSessionClientPlatformLabel(platform) {
52
+ return platform ? CLIENT_PLATFORM_LABELS[platform] ?? '' : '';
53
+ }
54
+ export function detectSessionClientPlatformId(env = process.env, argv = process.argv, execPath = process.execPath, title = process.title) {
55
+ const termProgram = normalizeText(env.TERM_PROGRAM);
56
+ const argvText = normalizeText(argv.join(' '));
57
+ const execPathText = normalizeText(execPath);
58
+ const titleText = normalizeText(title);
59
+ const textSources = [argvText, execPathText, titleText];
60
+ if (env.CLAUDE_DESKTOP === 'true' || env.CLAUDE_DESKTOP_VERSION) {
61
+ return 'claude-desktop';
62
+ }
63
+ if (env.CLAUDE_CODE === 'true' || termProgram === 'claude-code') {
64
+ return 'claude-code';
65
+ }
66
+ if (env.VSCODE_CWD ||
67
+ env.VSCODE_PID ||
68
+ env.VSCODE_IPC_HOOK ||
69
+ env.VSCODE_NLS_CONFIG ||
70
+ termProgram === 'vscode') {
71
+ return 'vscode';
72
+ }
73
+ if (env.CODEX_HOME || termProgram === 'codex') {
74
+ return 'codex';
75
+ }
76
+ for (const matcher of TEXT_PLATFORM_MATCHERS) {
77
+ if (matchesAnySource(textSources, matcher.needles)) {
78
+ return matcher.platform;
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbkNsaWVudFBsYXRmb3JtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3dlYi9jb25zb2xlL3Nlc3Npb25DbGllbnRQbGF0Zm9ybS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7R0FLRztBQWNILE1BQU0sc0JBQXNCLEdBQTRDO0lBQ3RFLGFBQWEsRUFBRSxhQUFhO0lBQzVCLGdCQUFnQixFQUFFLGdCQUFnQjtJQUNsQyxLQUFLLEVBQUUsT0FBTztJQUNkLE1BQU0sRUFBRSxRQUFRO0lBQ2hCLE1BQU0sRUFBRSxTQUFTO0lBQ2pCLFFBQVEsRUFBRSxVQUFVO0lBQ3BCLFlBQVksRUFBRSxZQUFZO0lBQzFCLEtBQUssRUFBRSxPQUFPO0lBQ2QsUUFBUSxFQUFFLFdBQVc7SUFDckIsYUFBYSxFQUFFLGFBQWE7Q0FDN0IsQ0FBQztBQUVGLFNBQVMsYUFBYSxDQUFDLEtBQXlCO0lBQzlDLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUNyRSxDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsS0FBYSxFQUFFLE9BQTBCO0lBQzVELE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0FBQzFELENBQUM7QUFFRCxTQUFTLGdCQUFnQixDQUFDLE1BQXlCLEVBQUUsT0FBMEI7SUFDN0UsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDN0QsQ0FBQztBQUVELE1BQU0sc0JBQXNCLEdBR3ZCO0lBQ0gsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE9BQU8s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LHNCQUFzQixFQUFFLENBQUM7UUFDN0MsSUFBSSxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDbkQsT0FBTyxPQUFPLENBQUMsUUFBUSxDQUFDO1FBQzFCLENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCZXN0LWVmZm9ydCBNQ1AgY2xpZW50IHBsYXRmb3JtIGRldGVjdGlvbiBmb3Igc2Vzc2lvbiBtZXRhZGF0YS5cbiAqXG4gKiBUaGlzIGlzIGludGVudGlvbmFsbHkgY29uc2VydmF0aXZlOiB3aGVuIHdlIGNhbm5vdCBpZGVudGlmeSB0aGUgaG9zdFxuICogY29uZmlkZW50bHksIHdlIHJldHVybiBudWxsIHJhdGhlciB0aGFuIGd1ZXNzaW5nIGZyb20gYSBzZXNzaW9uIElELlxuICovXG5cbmV4cG9ydCB0eXBlIFNlc3Npb25DbGllbnRQbGF0Zm9ybUlkID1cbiAgfCAnY2xhdWRlLWNvZGUnXG4gIHwgJ2NsYXVkZS1kZXNrdG9wJ1xuICB8ICdjb2RleCdcbiAgfCAnY3Vyc29yJ1xuICB8ICd2c2NvZGUnXG4gIHwgJ3dpbmRzdXJmJ1xuICB8ICdnZW1pbmktY2xpJ1xuICB8ICdjbGluZSdcbiAgfCAnbG1zdHVkaW8nXG4gIHwgJ3dlYi1jb25zb2xlJztcblxuY29uc3QgQ0xJRU5UX1BMQVRGT1JNX0xBQkVMUzogUmVjb3JkPFNlc3Npb25DbGllbnRQbGF0Zm9ybUlkLCBzdHJpbmc+ID0ge1xuICAnY2xhdWRlLWNvZGUnOiAnQ2xhdWRlIENvZGUnLFxuICAnY2xhdWRlLWRlc2t0b3AnOiAnQ2xhdWRlIERlc2t0b3AnLFxuICBjb2RleDogJ0NvZGV4JyxcbiAgY3Vyc29yOiAnQ3Vyc29yJyxcbiAgdnNjb2RlOiAnVlMgQ29kZScsXG4gIHdpbmRzdXJmOiAnV2luZHN1cmYnLFxuICAnZ2VtaW5pLWNsaSc6ICdHZW1pbmkgQ0xJJyxcbiAgY2xpbmU6ICdDbGluZScsXG4gIGxtc3R1ZGlvOiAnTE0gU3R1ZGlvJyxcbiAgJ3dlYi1jb25zb2xlJzogJ1dlYiBDb25zb2xlJyxcbn07XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZVRleHQodmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gdmFsdWUudHJpbSgpLnRvTG93ZXJDYXNlKCkgOiAnJztcbn1cblxuZnVuY3Rpb24gaW5jbHVkZXNBbnkodmFsdWU6IHN0cmluZywgbmVlZGxlczogcmVhZG9ubHkgc3RyaW5nW10pOiBib29sZWFuIHtcbiAgcmV0dXJuIG5lZWRsZXMuc29tZSgobmVlZGxlKSA9PiB2YWx1ZS5pbmNsdWRlcyhuZWVkbGUpKTtcbn1cblxuZnVuY3Rpb24gbWF0Y2hlc0FueVNvdXJjZSh2YWx1ZXM6IHJlYWRvbmx5IHN0cmluZ1tdLCBuZWVkbGVzOiByZWFkb25seSBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICByZXR1cm4gdmFsdWVzLnNvbWUoKHZhbHVlKSA9PiBpbmNsdWRlc0FueSh2YWx1ZSwgbmVlZGxlcykpO1xufVxuXG5jb25zdCBURVhUX1BMQVRGT1JNX01BVENIRVJTOiBSZWFkb25seUFycmF5PHtcbiAgcGxhdGZvcm06IFNlc3Npb25DbGllbnRQbGF0Zm9ybUlkO1xuICBuZWVkbGVzOiByZWFkb25seSBzdHJpbmdbXTtcbn0+ID0gW1xuICB7IHBsYXRmb3JtOiAnY3Vyc29yJywgbmVlZGxlczogWydjdXJzb3InXSB9LFxuICB7IHBsYXRmb3JtOiAnd2luZHN1cmYnLCBuZWVkbGVzOiBbJ3dpbmRzdXJmJ10gfSxcbiAgeyBwbGF0Zm9ybTogJ2dlbWluaS1jbGknLCBuZWVkbGVzOiBbJ2dlbWluaSddIH0sXG4gIHsgcGxhdGZvcm06ICdjbGluZScsIG5lZWRsZXM6IFsnY2xpbmUnXSB9LFxuICB7IHBsYXRmb3JtOiAnbG1zdHVkaW8nLCBuZWVkbGVzOiBbJ2xtc3R1ZGlvJywgJ2xtIHN0dWRpbyddIH0sXG4gIHsgcGxhdGZvcm06ICdjbGF1ZGUtZGVza3RvcCcsIG5lZWRsZXM6IFsnY2xhdWRlIGRlc2t0b3AnXSB9LFxuICB7IHBsYXRmb3JtOiAnY2xhdWRlLWNvZGUnLCBuZWVkbGVzOiBbJ2NsYXVkZSBjb2RlJ10gfSxcbiAgeyBwbGF0Zm9ybTogJ2NvZGV4JywgbmVlZGxlczogWydjb2RleCddIH0sXG5dO1xuXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplU2Vzc2lvbkNsaWVudFBsYXRmb3JtSWQoXG4gIHZhbHVlOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkLFxuKTogU2Vzc2lvbkNsaWVudFBsYXRmb3JtSWQgfCBudWxsIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZVRleHQodmFsdWUgPz8gdW5kZWZpbmVkKTtcbiAgaWYgKCFub3JtYWxpemVkKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAobm9ybWFsaXplZCA9PT0gJ2dlbWluaScpIHtcbiAgICByZXR1cm4gJ2dlbWluaS1jbGknO1xuICB9XG5cbiAgaWYgKG5vcm1hbGl6ZWQgaW4gQ0xJRU5UX1BMQVRGT1JNX0xBQkVMUykge1xuICAgIHJldHVybiBub3JtYWxpemVkIGFzIFNlc3Npb25DbGllbnRQbGF0Zm9ybUlkO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXNzaW9uQ2xpZW50UGxhdGZvcm1MYWJlbChcbiAgcGxhdGZvcm06IFNlc3Npb25DbGllbnRQbGF0Zm9ybUlkIHwgbnVsbCB8IHVuZGVmaW5lZCxcbik6IHN0cmluZyB7XG4gIHJldHVybiBwbGF0Zm9ybSA/IENMSUVOVF9QTEFURk9STV9MQUJFTFNbcGxhdGZvcm1dID8/ICcnIDogJyc7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXRlY3RTZXNzaW9uQ2xpZW50UGxhdGZvcm1JZChcbiAgZW52OiBOb2RlSlMuUHJvY2Vzc0VudiA9IHByb2Nlc3MuZW52LFxuICBhcmd2OiByZWFkb25seSBzdHJpbmdbXSA9IHByb2Nlc3MuYXJndixcbiAgZXhlY1BhdGg6IHN0cmluZyA9IHByb2Nlc3MuZXhlY1BhdGgsXG4gIHRpdGxlOiBzdHJpbmcgPSBwcm9jZXNzLnRpdGxlLFxuKTogU2Vzc2lvbkNsaWVudFBsYXRmb3JtSWQgfCBudWxsIHtcbiAgY29uc3QgdGVybVByb2dyYW0gPSBub3JtYWxpemVUZXh0KGVudi5URVJNX1BST0dSQU0pO1xuICBjb25zdCBhcmd2VGV4dCA9IG5vcm1hbGl6ZVRleHQoYXJndi5qb2luKCcgJykpO1xuICBjb25zdCBleGVjUGF0aFRleHQgPSBub3JtYWxpemVUZXh0KGV4ZWNQYXRoKTtcbiAgY29uc3QgdGl0bGVUZXh0ID0gbm9ybWFsaXplVGV4dCh0aXRsZSk7XG4gIGNvbnN0IHRleHRTb3VyY2VzID0gW2FyZ3ZUZXh0LCBleGVjUGF0aFRleHQsIHRpdGxlVGV4dF07XG5cbiAgaWYgKGVudi5DTEFVREVfREVTS1RPUCA9PT0gJ3RydWUnIHx8IGVudi5DTEFVREVfREVTS1RPUF9WRVJTSU9OKSB7XG4gICAgcmV0dXJuICdjbGF1ZGUtZGVza3RvcCc7XG4gIH1cblxuICBpZiAoZW52LkNMQVVERV9DT0RFID09PSAndHJ1ZScgfHwgdGVybVByb2dyYW0gPT09ICdjbGF1ZGUtY29kZScpIHtcbiAgICByZXR1cm4gJ2NsYXVkZS1jb2RlJztcbiAgfVxuXG4gIGlmIChcbiAgICBlbnYuVlNDT0RFX0NXRCB8fFxuICAgIGVudi5WU0NPREVfUElEIHx8XG4gICAgZW52LlZTQ09ERV9JUENfSE9PSyB8fFxuICAgIGVudi5WU0NPREVfTkxTX0NPTkZJRyB8fFxuICAgIHRlcm1Qcm9ncmFtID09PSAndnNjb2RlJ1xuICApIHtcbiAgICByZXR1cm4gJ3ZzY29kZSc7XG4gIH1cblxuICBpZiAoZW52LkNPREVYX0hPTUUgfHwgdGVybVByb2dyYW0gPT09ICdjb2RleCcpIHtcbiAgICByZXR1cm4gJ2NvZGV4JztcbiAgfVxuXG4gIGZvciAoY29uc3QgbWF0Y2hlciBvZiBURVhUX1BMQVRGT1JNX01BVENIRVJTKSB7XG4gICAgaWYgKG1hdGNoZXNBbnlTb3VyY2UodGV4dFNvdXJjZXMsIG1hdGNoZXIubmVlZGxlcykpIHtcbiAgICAgIHJldHVybiBtYXRjaGVyLnBsYXRmb3JtO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuIl19
@@ -225,6 +225,16 @@
225
225
  } else if (data.permissionPromptActive) {
226
226
  hookDot.dataset.status = 'active';
227
227
  hookLabel.textContent = 'Prompt tool active';
228
+ } else if (data.hookNeedsRepair) {
229
+ hookDot.dataset.status = 'warning';
230
+ hookLabel.textContent = data.hookHost
231
+ ? `Hook needs repair (${data.hookHost})`
232
+ : 'Hook needs repair';
233
+ } else if (data.hookAutoRepaired) {
234
+ hookDot.dataset.status = 'active';
235
+ hookLabel.textContent = data.hookHost
236
+ ? `Hook refreshed (${data.hookHost})`
237
+ : 'Hook refreshed';
228
238
  } else if (data.hookInstalled) {
229
239
  hookDot.dataset.status = 'active';
230
240
  hookLabel.textContent = data.hookHost ? `Hook installed (${data.hookHost})` : 'Hook installed';
@@ -66,7 +66,8 @@
66
66
  position: absolute;
67
67
  top: calc(100% + 0.4rem);
68
68
  right: 0;
69
- min-width: 480px;
69
+ width: min(34rem, calc(100vw - 1rem));
70
+ box-sizing: border-box;
70
71
  background: var(--paper-strong, #fff);
71
72
  border: 1px solid var(--line, #c8d5e9);
72
73
  border-radius: var(--radius-md, 0.85rem);
@@ -184,10 +185,11 @@
184
185
 
185
186
  .session-dropdown-item {
186
187
  display: grid;
187
- grid-template-columns: 1rem 8px 1fr 62px 72px 3.5rem 1.2rem;
188
+ grid-template-columns: 1rem 8px minmax(0, 1fr) 5.5rem 6.75rem 4.5rem 1.2rem;
188
189
  align-items: center;
189
- gap: 0.4rem;
190
- padding: 0.45rem 0.75rem;
190
+ column-gap: 0.7rem;
191
+ row-gap: 0.3rem;
192
+ padding: 0.55rem 0.9rem;
191
193
  font-size: var(--step--1, 0.82rem);
192
194
  cursor: pointer;
193
195
  transition: background 0.1s;
@@ -235,12 +237,51 @@
235
237
  white-space: nowrap;
236
238
  }
237
239
 
240
+ .session-dropdown-primary {
241
+ min-width: 0;
242
+ display: flex;
243
+ flex-direction: column;
244
+ gap: 0.18rem;
245
+ align-self: center;
246
+ }
247
+
248
+ .session-dropdown-meta {
249
+ display: flex;
250
+ align-items: center;
251
+ gap: 0.35rem;
252
+ min-width: 0;
253
+ flex-wrap: wrap;
254
+ }
255
+
256
+ .session-dropdown-version {
257
+ font-size: 0.7rem;
258
+ font-family: var(--font-mono, monospace);
259
+ color: var(--ink-500, #677893);
260
+ white-space: nowrap;
261
+ }
262
+
263
+ .session-dropdown-update {
264
+ display: inline-flex;
265
+ align-items: center;
266
+ padding: 1px 5px;
267
+ border-radius: 999px;
268
+ font-size: 0.62rem;
269
+ font-weight: 700;
270
+ letter-spacing: 0.04em;
271
+ background: #ecfdf5;
272
+ color: #166534;
273
+ border: 1px solid #86efac;
274
+ white-space: nowrap;
275
+ }
276
+
238
277
  .session-dropdown-uptime {
239
278
  font-size: 0.7rem;
240
279
  font-family: var(--font-mono, monospace);
241
280
  color: var(--ink-500, #677893);
242
281
  white-space: nowrap;
243
282
  text-align: right;
283
+ min-width: 4.5rem;
284
+ justify-self: end;
244
285
  }
245
286
 
246
287
  .session-dropdown-role {
@@ -287,6 +328,16 @@
287
328
  color: var(--ink-900, #e0e8f0);
288
329
  }
289
330
 
331
+ [data-theme="dark"] .session-dropdown-version {
332
+ color: var(--ink-500, #8899bb);
333
+ }
334
+
335
+ [data-theme="dark"] .session-dropdown-update {
336
+ background: #052e16;
337
+ color: #bbf7d0;
338
+ border-color: #166534;
339
+ }
340
+
290
341
  [data-theme="dark"] .session-dropdown-toggle-label {
291
342
  color: var(--ink-500, #8899bb);
292
343
  }
@@ -363,15 +414,40 @@
363
414
  * - Color (blue=positive, orange=negative — colorblind-safe pair)
364
415
  */
365
416
  .session-status-badge {
366
- display: inline-block;
367
- padding: 1px 5px;
368
- border-radius: 3px;
369
- font-size: 9px;
417
+ display: inline-flex;
418
+ align-items: center;
419
+ justify-content: center;
420
+ padding: 2px 7px;
421
+ border-radius: 5px;
422
+ font-size: 10px;
370
423
  font-weight: 600;
371
424
  letter-spacing: 0.04em;
372
425
  white-space: nowrap;
373
426
  text-align: center;
374
- min-width: 52px;
427
+ min-width: 4.75rem;
428
+ box-sizing: border-box;
429
+ }
430
+
431
+ .session-dropdown-item > .session-status-badge {
432
+ justify-self: center;
433
+ }
434
+
435
+ .session-dropdown-badge-stack {
436
+ display: flex;
437
+ flex-direction: column;
438
+ align-items: center;
439
+ justify-self: center;
440
+ gap: 0.24rem;
441
+ width: 100%;
442
+ max-width: 6.75rem;
443
+ }
444
+
445
+ .session-dropdown-client-label {
446
+ font-size: 0.62rem;
447
+ line-height: 1.15;
448
+ color: var(--ink-500, #677893);
449
+ text-align: center;
450
+ width: 100%;
375
451
  }
376
452
 
377
453
  .session-status-badge[data-status="positive"] {
@@ -398,6 +474,10 @@
398
474
  border-color: #9a3412;
399
475
  }
400
476
 
477
+ [data-theme="dark"] .session-dropdown-client-label {
478
+ color: var(--ink-500, #8899bb);
479
+ }
480
+
401
481
  /* Session filter in the log viewer */
402
482
  #log-session-filter {
403
483
  min-width: 120px;
@@ -33,6 +33,18 @@
33
33
  var lastReloadTargetVersion = '';
34
34
  var pendingLeaderReloadTimer = null;
35
35
  var showPolicySessions = loadPolicyDebugVisibility();
36
+ var CLIENT_PLATFORM_LABELS = {
37
+ 'claude-code': 'Claude Code',
38
+ 'claude-desktop': 'Claude Desktop',
39
+ 'codex': 'Codex',
40
+ 'cursor': 'Cursor',
41
+ 'vscode': 'VS Code',
42
+ 'windsurf': 'Windsurf',
43
+ 'gemini-cli': 'Gemini CLI',
44
+ 'cline': 'Cline',
45
+ 'lmstudio': 'LM Studio',
46
+ 'web-console': 'Web Console'
47
+ };
36
48
 
37
49
  function loadPolicyDebugVisibility() {
38
50
  try {
@@ -176,6 +188,55 @@
176
188
  /** NFC-normalize a string safely */
177
189
  function nfc(s) { try { return s.normalize('NFC'); } catch(e) { return s; } }
178
190
 
191
+ function normalizeClientPlatform(platform) {
192
+ if (typeof platform !== 'string') return '';
193
+ var normalized = nfc(platform).trim().toLowerCase();
194
+ if (!normalized) return '';
195
+ if (normalized === 'gemini') return 'gemini-cli';
196
+ return Object.prototype.hasOwnProperty.call(CLIENT_PLATFORM_LABELS, normalized) ? normalized : '';
197
+ }
198
+
199
+ function displayPlatform(session) {
200
+ if (!session || typeof session !== 'object') return '';
201
+ if (typeof session.clientPlatformLabel === 'string' && session.clientPlatformLabel.trim()) {
202
+ return nfc(session.clientPlatformLabel.trim());
203
+ }
204
+ var platform = normalizeClientPlatform(session.clientPlatform);
205
+ return platform ? CLIENT_PLATFORM_LABELS[platform] || '' : '';
206
+ }
207
+
208
+ function displayVersion(session) {
209
+ if (!session || typeof session !== 'object') return '';
210
+ var normalized = normalizeSemver(session.serverVersion);
211
+ if (!normalized && typeof session.serverVersion === 'string') {
212
+ normalized = nfc(session.serverVersion).trim();
213
+ }
214
+ if (!normalized) return '';
215
+ return normalized.charAt(0) === 'v' ? normalized : ('v' + normalized);
216
+ }
217
+
218
+ function getNewestKnownSessionVersion(list) {
219
+ if (!Array.isArray(list)) return '';
220
+ var newest = '';
221
+ for (var i = 0; i < list.length; i++) {
222
+ var session = list[i];
223
+ if (!session || isPolicyOnlySession(session) || session.status !== 'active') continue;
224
+ var version = normalizeSemver(session.serverVersion);
225
+ if (!version) continue;
226
+ if (!newest || compareSemver(version, newest) > 0) {
227
+ newest = version;
228
+ }
229
+ }
230
+ return newest;
231
+ }
232
+
233
+ function sessionHasUpdateAvailable(session, newestVersion) {
234
+ if (!session || !newestVersion || isPolicyOnlySession(session)) return false;
235
+ var version = normalizeSemver(session.serverVersion);
236
+ if (!version) return false;
237
+ return compareSemver(version, newestVersion) < 0;
238
+ }
239
+
179
240
  function isPolicyOnlySession(session) {
180
241
  return !!(session && session.isPolicyOnly);
181
242
  }
@@ -231,6 +292,9 @@
231
292
  isLeader: false,
232
293
  authenticated: false,
233
294
  kind: 'policy',
295
+ serverVersion: '',
296
+ clientPlatform: '',
297
+ clientPlatformLabel: '',
234
298
  isPolicyOnly: true,
235
299
  });
236
300
  }
@@ -254,12 +318,63 @@
254
318
  // Build a key from current sessions to detect changes
255
319
  function sessionListKey(list) {
256
320
  return list.map(function(s) {
257
- return s.sessionId + ':' + s.status + ':' + (isPolicyOnlySession(s) ? 'policy' : 'live');
321
+ return [
322
+ s.sessionId,
323
+ s.status,
324
+ s.displayName || '',
325
+ s.serverVersion || '',
326
+ s.clientPlatform || '',
327
+ s.clientPlatformLabel || '',
328
+ s.isLeader ? 'leader' : 'member',
329
+ s.authenticated ? 'auth' : 'noauth',
330
+ isPolicyOnlySession(s) ? 'policy' : 'live'
331
+ ].join(':');
258
332
  }).join(',')
259
333
  + '|policyDebug:' + (showPolicySessions ? 'on' : 'off')
260
334
  + '|knownPolicy:' + policySessions.map(function(session) { return session.sessionId; }).join(',');
261
335
  }
262
336
 
337
+ function normalizeLiveSessions(list) {
338
+ if (!Array.isArray(list)) return [];
339
+ var normalized = [];
340
+ var seen = new Set();
341
+
342
+ for (var i = 0; i < list.length; i++) {
343
+ var item = list[i];
344
+ if (!item || typeof item.sessionId !== 'string') continue;
345
+ var sessionId = nfc(item.sessionId).trim();
346
+ if (!sessionId || seen.has(sessionId)) continue;
347
+ seen.add(sessionId);
348
+
349
+ var clientPlatform = normalizeClientPlatform(item.clientPlatform);
350
+ var clientPlatformLabel = '';
351
+ if (typeof item.clientPlatformLabel === 'string' && item.clientPlatformLabel.trim()) {
352
+ clientPlatformLabel = nfc(item.clientPlatformLabel).trim();
353
+ } else if (clientPlatform) {
354
+ clientPlatformLabel = CLIENT_PLATFORM_LABELS[clientPlatform] || '';
355
+ }
356
+
357
+ normalized.push({
358
+ sessionId: sessionId,
359
+ displayName: nfc(typeof item.displayName === 'string' && item.displayName ? item.displayName : sessionId),
360
+ color: typeof item.color === 'string' ? item.color : '',
361
+ pid: typeof item.pid === 'number' ? item.pid : 0,
362
+ startedAt: typeof item.startedAt === 'string' ? item.startedAt : '',
363
+ lastHeartbeat: typeof item.lastHeartbeat === 'string' ? item.lastHeartbeat : '',
364
+ status: item.status === 'ended' ? 'ended' : 'active',
365
+ isLeader: !!item.isLeader,
366
+ authenticated: !!item.authenticated,
367
+ kind: typeof item.kind === 'string' ? item.kind : 'mcp',
368
+ serverVersion: normalizeSemver(item.serverVersion) || (typeof item.serverVersion === 'string' ? nfc(item.serverVersion).trim() : ''),
369
+ consoleProtocolVersion: typeof item.consoleProtocolVersion === 'number' ? item.consoleProtocolVersion : 0,
370
+ clientPlatform: clientPlatform,
371
+ clientPlatformLabel: clientPlatformLabel,
372
+ });
373
+ }
374
+
375
+ return normalized;
376
+ }
377
+
263
378
  function setPolicyDebugVisibility(nextVisible, keepDropdownOpen) {
264
379
  var normalized = !!nextVisible;
265
380
  if (showPolicySessions === normalized) return;
@@ -513,6 +628,7 @@
513
628
  if (!a.isLeader && b.isLeader) return 1;
514
629
  return 0;
515
630
  });
631
+ var newestKnownVersion = getNewestKnownSessionVersion(sorted);
516
632
 
517
633
  function appendSessionItem(s) {
518
634
  var item = document.createElement('div');
@@ -529,11 +645,37 @@
529
645
  if (s.color) dot.style.background = s.color;
530
646
  item.appendChild(dot);
531
647
 
648
+ var nameWrap = document.createElement('div');
649
+ nameWrap.className = 'session-dropdown-primary';
650
+
532
651
  var nameEl = document.createElement('span');
533
652
  nameEl.className = 'session-dropdown-name';
534
653
  nameEl.textContent = displayName(s);
535
654
  if (s.color) nameEl.style.color = s.color;
536
- item.appendChild(nameEl);
655
+ nameWrap.appendChild(nameEl);
656
+
657
+ var versionText = displayVersion(s);
658
+ if (versionText) {
659
+ var metaRow = document.createElement('div');
660
+ metaRow.className = 'session-dropdown-meta';
661
+
662
+ var versionEl = document.createElement('span');
663
+ versionEl.className = 'session-dropdown-version';
664
+ versionEl.textContent = versionText;
665
+ metaRow.appendChild(versionEl);
666
+
667
+ if (sessionHasUpdateAvailable(s, newestKnownVersion)) {
668
+ var updateBadge = document.createElement('span');
669
+ updateBadge.className = 'session-dropdown-update';
670
+ updateBadge.textContent = 'Update available';
671
+ updateBadge.title = 'A newer local DollhouseMCP session version is active.';
672
+ metaRow.appendChild(updateBadge);
673
+ }
674
+
675
+ nameWrap.appendChild(metaRow);
676
+ }
677
+
678
+ item.appendChild(nameWrap);
537
679
 
538
680
  // Session status badges (#1805) — for persisted policy sessions we
539
681
  // switch from "live/authenticated" semantics to "saved/no client".
@@ -554,6 +696,9 @@
554
696
  }
555
697
  item.appendChild(authBadge);
556
698
 
699
+ var clientWrap = document.createElement('div');
700
+ clientWrap.className = 'session-dropdown-badge-stack';
701
+
557
702
  var clientBadge = document.createElement('span');
558
703
  clientBadge.className = 'session-status-badge';
559
704
  if (isPolicyOnlySession(s)) {
@@ -569,7 +714,17 @@
569
714
  clientBadge.dataset.status = 'negative';
570
715
  clientBadge.title = 'No MCP client attached';
571
716
  }
572
- item.appendChild(clientBadge);
717
+ clientWrap.appendChild(clientBadge);
718
+
719
+ var platformLabel = displayPlatform(s);
720
+ if (platformLabel) {
721
+ var clientLabel = document.createElement('span');
722
+ clientLabel.className = 'session-dropdown-client-label';
723
+ clientLabel.textContent = platformLabel;
724
+ clientWrap.appendChild(clientLabel);
725
+ }
726
+
727
+ item.appendChild(clientWrap);
573
728
 
574
729
  var uptimeEl = document.createElement('span');
575
730
  uptimeEl.className = 'session-dropdown-uptime';
@@ -727,7 +882,7 @@
727
882
  return res.json();
728
883
  }).then(function(data) {
729
884
  if (data && data.sessions) {
730
- sessions = data.sessions;
885
+ sessions = normalizeLiveSessions(data.sessions);
731
886
  maybeForceReloadForNewLeader(sessions);
732
887
  updateSessionIndicator();
733
888
  updateSessionFilterOptions();
@@ -743,6 +898,7 @@
743
898
  window.DollhouseSessions = {
744
899
  getFilterSessionId: function() { return filterSessionId; },
745
900
  displayName: displayName,
901
+ displayPlatform: displayPlatform,
746
902
  getSessions: function() { return sessions; },
747
903
  getLiveSessions: getLiveSessions,
748
904
  getSelectableSessions: getSelectableSessions,
@@ -13,6 +13,9 @@
13
13
  const PKG = '@dollhousemcp/mcp-server';
14
14
  const HOOKS_DIR = '~/.dollhouse/hooks';
15
15
  const HOOK_BASE_SCRIPT_PATH = `${HOOKS_DIR}/pretooluse-dollhouse.sh`;
16
+ const HOOK_CONTRACT_DOC_URL = 'https://github.com/DollhouseMCP/mcp-server/blob/main/docs/architecture/permission-hook-platform-contracts.md';
17
+ // Keep hook entrypoints and output expectations in sync with
18
+ // docs/architecture/permission-hook-platform-contracts.md.
16
19
 
17
20
  /** Platform registry — drives config generation AND panel rendering */
18
21
  const PLATFORMS = [
@@ -677,6 +680,13 @@ codex_hooks = true`;
677
680
  const updatePermissionInstallButton = (btn, detected) => {
678
681
  if (!btn || btn.classList.contains('is-success')) return;
679
682
 
683
+ if (detected?.hookNeedsRepair) {
684
+ btn.textContent = 'Repair hooks';
685
+ btn.disabled = false;
686
+ btn.classList.remove('is-match');
687
+ return;
688
+ }
689
+
680
690
  if (detected?.hookInstalled) {
681
691
  btn.textContent = 'Permissions enabled';
682
692
  btn.disabled = true;
@@ -1116,7 +1126,30 @@ codex_hooks = true`;
1116
1126
  return PERMISSION_SUPPORT_MATRIX[platformId];
1117
1127
  };
1118
1128
 
1129
+ const getHookRepairStatusCopy = (support, detected) => {
1130
+ if (detected?.hookNeedsRepair) {
1131
+ return {
1132
+ tone: 'warning',
1133
+ titleText: `${support.label} hook files need repair.`,
1134
+ messageText: 'DollhouseMCP detected stale local hook assets. Use Configure Now below to rewrite them, or reload the local server so the automatic repair pass can run again.',
1135
+ };
1136
+ }
1137
+
1138
+ if (detected?.hookAutoRepaired) {
1139
+ return {
1140
+ tone: 'info',
1141
+ titleText: `${support.label} hook files were refreshed automatically.`,
1142
+ messageText: 'The installed local hook assets were updated to match this release. Restart the client if it is already running.',
1143
+ };
1144
+ }
1145
+
1146
+ return null;
1147
+ };
1148
+
1119
1149
  const getFullNativePermissionStatusCopy = (support, detected) => {
1150
+ const repairCopy = getHookRepairStatusCopy(support, detected);
1151
+ if (repairCopy) return repairCopy;
1152
+
1120
1153
  if (detected?.hookInstalled) {
1121
1154
  return {
1122
1155
  tone: 'info',
@@ -1142,6 +1175,9 @@ codex_hooks = true`;
1142
1175
 
1143
1176
  const getPartialPermissionStatusCopy = (support, detected) => {
1144
1177
  const activationLabel = support.label === 'Codex' ? 'Bash guardrails' : 'permission hooks';
1178
+ const repairCopy = getHookRepairStatusCopy(support, detected);
1179
+ if (repairCopy) return repairCopy;
1180
+
1145
1181
  if (detected?.hookInstalled) {
1146
1182
  return {
1147
1183
  tone: 'info',
@@ -1182,6 +1218,9 @@ codex_hooks = true`;
1182
1218
  };
1183
1219
 
1184
1220
  const getManualPermissionStatusCopy = (support, detected) => {
1221
+ const repairCopy = getHookRepairStatusCopy(support, detected);
1222
+ if (repairCopy) return repairCopy;
1223
+
1185
1224
  if (detected?.hookAssetsPrepared) {
1186
1225
  return {
1187
1226
  tone: 'info',
@@ -1591,6 +1630,7 @@ codex_hooks = true`;
1591
1630
  intro.innerHTML = `<div class="setup-permissions-note">
1592
1631
  <strong>Permissions &amp; Security</strong>
1593
1632
  <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>
1633
+ <p class="setup-hint">Need the advanced client-by-client hook contract details? <a href="${HOOK_CONTRACT_DOC_URL}" target="_blank" rel="noopener noreferrer">Read the platform contract reference</a>.</p>
1594
1634
  </div>`;
1595
1635
  };
1596
1636
 
@@ -14,6 +14,7 @@ import type { MCPAQLHandler } from '../../handlers/mcp-aql/MCPAQLHandler.js';
14
14
  */
15
15
  export interface RegisterPermissionRoutesOptions {
16
16
  homeDir?: string;
17
+ autoRepairHookAssets?: boolean;
17
18
  }
18
19
  export declare function registerPermissionRoutes(router: Router, handler: MCPAQLHandler, options?: RegisterPermissionRoutesOptions): void;
19
20
  //# sourceMappingURL=permissionRoutes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"permissionRoutes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/permissionRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AA8T7E;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,+BAAoC,GAC5C,IAAI,CA+NN"}
1
+ {"version":3,"file":"permissionRoutes.d.ts","sourceRoot":"","sources":["../../../src/web/routes/permissionRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAyV7E;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,+BAAoC,GAC5C,IAAI,CAiPN"}