@geohar/pi-mcp-combiner 0.13.3 → 0.14.0

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 (95) hide show
  1. package/README.md +227 -126
  2. package/dist/client/config-ladder.d.ts +62 -0
  3. package/dist/client/config-ladder.d.ts.map +1 -0
  4. package/dist/client/config-ladder.js +162 -0
  5. package/dist/client/config-ladder.js.map +1 -0
  6. package/dist/client/connection.d.ts +113 -0
  7. package/dist/client/connection.d.ts.map +1 -0
  8. package/dist/client/connection.js +332 -0
  9. package/dist/client/connection.js.map +1 -0
  10. package/dist/client/control.d.ts +17 -0
  11. package/dist/client/control.d.ts.map +1 -0
  12. package/dist/client/control.js +80 -0
  13. package/dist/client/control.js.map +1 -0
  14. package/dist/client/direct-tools.d.ts +41 -0
  15. package/dist/client/direct-tools.d.ts.map +1 -0
  16. package/dist/client/direct-tools.js +122 -0
  17. package/dist/client/direct-tools.js.map +1 -0
  18. package/dist/client/elicitation.d.ts +22 -0
  19. package/dist/client/elicitation.d.ts.map +1 -0
  20. package/dist/client/elicitation.js +93 -0
  21. package/dist/client/elicitation.js.map +1 -0
  22. package/dist/client/footer.d.ts +17 -0
  23. package/dist/client/footer.d.ts.map +1 -0
  24. package/dist/client/footer.js +99 -0
  25. package/dist/client/footer.js.map +1 -0
  26. package/dist/client/panel.d.ts +16 -0
  27. package/dist/client/panel.d.ts.map +1 -0
  28. package/dist/client/panel.js +426 -0
  29. package/dist/client/panel.js.map +1 -0
  30. package/dist/client/prompts.d.ts +30 -0
  31. package/dist/client/prompts.d.ts.map +1 -0
  32. package/dist/client/prompts.js +230 -0
  33. package/dist/client/prompts.js.map +1 -0
  34. package/dist/client/proxy-tool.d.ts +22 -0
  35. package/dist/client/proxy-tool.d.ts.map +1 -0
  36. package/dist/client/proxy-tool.js +225 -0
  37. package/dist/client/proxy-tool.js.map +1 -0
  38. package/dist/client/ranking.d.ts +21 -0
  39. package/dist/client/ranking.d.ts.map +1 -0
  40. package/dist/client/ranking.js +113 -0
  41. package/dist/client/ranking.js.map +1 -0
  42. package/dist/client/render.d.ts +28 -0
  43. package/dist/client/render.d.ts.map +1 -0
  44. package/dist/client/render.js +166 -0
  45. package/dist/client/render.js.map +1 -0
  46. package/dist/client/renderers.d.ts +31 -0
  47. package/dist/client/renderers.d.ts.map +1 -0
  48. package/dist/client/renderers.js +191 -0
  49. package/dist/client/renderers.js.map +1 -0
  50. package/dist/client/resources.d.ts +20 -0
  51. package/dist/client/resources.d.ts.map +1 -0
  52. package/dist/client/resources.js +119 -0
  53. package/dist/client/resources.js.map +1 -0
  54. package/dist/client/schema-signature.d.ts +3 -0
  55. package/dist/client/schema-signature.d.ts.map +1 -0
  56. package/dist/client/schema-signature.js +183 -0
  57. package/dist/client/schema-signature.js.map +1 -0
  58. package/dist/client/script.d.ts +10 -0
  59. package/dist/client/script.d.ts.map +1 -0
  60. package/dist/client/script.js +130 -0
  61. package/dist/client/script.js.map +1 -0
  62. package/dist/client/settings.d.ts +46 -0
  63. package/dist/client/settings.d.ts.map +1 -0
  64. package/dist/client/settings.js +81 -0
  65. package/dist/client/settings.js.map +1 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +333 -29
  68. package/dist/index.js.map +1 -1
  69. package/dist/pi.d.ts +82 -2
  70. package/dist/pi.d.ts.map +1 -1
  71. package/dist/pi.js +2 -1
  72. package/dist/pi.js.map +1 -1
  73. package/dist/sharedserver-resolve.d.ts.map +1 -1
  74. package/dist/sharedserver-resolve.js +2 -1
  75. package/dist/sharedserver-resolve.js.map +1 -1
  76. package/package.json +68 -57
  77. package/src/client/config-ladder.ts +221 -0
  78. package/src/client/connection.ts +373 -0
  79. package/src/client/control.ts +94 -0
  80. package/src/client/direct-tools.ts +146 -0
  81. package/src/client/elicitation.ts +115 -0
  82. package/src/client/footer.ts +108 -0
  83. package/src/client/panel.ts +478 -0
  84. package/src/client/prompts.ts +251 -0
  85. package/src/client/proxy-tool.ts +261 -0
  86. package/src/client/ranking.ts +130 -0
  87. package/src/client/render.ts +166 -0
  88. package/src/client/renderers.ts +211 -0
  89. package/src/client/resources.ts +137 -0
  90. package/src/client/schema-signature.ts +184 -0
  91. package/src/client/script.ts +150 -0
  92. package/src/client/settings.ts +109 -0
  93. package/src/index.ts +384 -32
  94. package/src/pi.ts +86 -6
  95. package/src/sharedserver-resolve.ts +10 -3
@@ -0,0 +1,17 @@
1
+ import type { CombinerConnection } from "./connection.js";
2
+ export type HealthServer = {
3
+ name?: string;
4
+ status?: string;
5
+ state?: string;
6
+ transport?: string;
7
+ };
8
+ export type HealthSnapshot = {
9
+ servers?: Array<Record<string, unknown>>;
10
+ tool_count?: number;
11
+ [k: string]: unknown;
12
+ };
13
+ /** `status` verb: health glyph table + our session's tool view. */
14
+ export declare function statusText(connection: CombinerConnection, cwd: string): Promise<string>;
15
+ /** `enable` / `disable` / `restart-server` verbs via the combiner meta-tools. */
16
+ export declare function metaToolCall(connection: CombinerConnection, verb: "enable" | "disable" | "restart-server", server: string): Promise<string>;
17
+ //# sourceMappingURL=control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../../src/client/control.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEzD,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjG,MAAM,MAAM,cAAc,GAAG;IACzB,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACxC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB,CAAA;AAkBD,mEAAmE;AACnE,wBAAsB,UAAU,CAAC,UAAU,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwC7F;AAED,iFAAiF;AACjF,wBAAsB,YAAY,CAC9B,UAAU,EAAE,kBAAkB,EAC9B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,gBAAgB,EAC7C,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAajB"}
@@ -0,0 +1,80 @@
1
+ // /mcp-combiner control verbs: inspect and drive the combiner from a Pi session.
2
+ //
3
+ // The read side hits the combiner's control plane directly (GET /health, token
4
+ // filter routes); the write side drives the combiner__* meta-tools through our own
5
+ // MCP client — one auth path, no second protocol.
6
+ const GLYPHS = {
7
+ ready: "✓",
8
+ connected: "✓",
9
+ starting: "…",
10
+ connecting: "…",
11
+ failed: "✗",
12
+ error: "✗",
13
+ disabled: "–",
14
+ idle: "○",
15
+ };
16
+ function glyph(state) {
17
+ if (!state)
18
+ return "?";
19
+ return GLYPHS[state.toLowerCase()] ?? "?";
20
+ }
21
+ /** `status` verb: health glyph table + our session's tool view. */
22
+ export async function statusText(connection, cwd) {
23
+ const lines = [];
24
+ lines.push(`connection: ${connection.state}${connection.lastError ? ` (${connection.lastError})` : ""}`);
25
+ try {
26
+ const health = (await connection.health());
27
+ // The combiner ships `servers` as an object keyed by name; tolerate arrays too.
28
+ const raw = health.servers;
29
+ const entries = [];
30
+ if (Array.isArray(raw)) {
31
+ for (const s of raw) {
32
+ if (typeof s === "object" && s !== null) {
33
+ const rec = s;
34
+ entries.push([typeof rec.name === "string" ? rec.name : "?", rec]);
35
+ }
36
+ }
37
+ }
38
+ else if (typeof raw === "object" && raw !== null) {
39
+ for (const [name, s] of Object.entries(raw)) {
40
+ if (typeof s === "object" && s !== null)
41
+ entries.push([name, s]);
42
+ }
43
+ }
44
+ for (const [name, s] of entries) {
45
+ const state = typeof (s.status ?? s.state) === "string" ? String(s.status ?? s.state) : undefined;
46
+ const transport = typeof s.transport === "string" ? ` [${s.transport}]` : "";
47
+ const dis = s.disabled === true ? " (disabled)" : "";
48
+ lines.push(`${glyph(state)} ${name}${transport} (${state ?? "unknown"})${dis}`);
49
+ }
50
+ }
51
+ catch (e) {
52
+ lines.push(`/health unreachable: ${e instanceof Error ? e.message : String(e)}`);
53
+ }
54
+ try {
55
+ const tools = await connection.listTools();
56
+ const servers = [...new Set(tools.map((t) => t.name.split("_", 1)[0] ?? ""))].filter(Boolean).sort();
57
+ lines.push(`visible to this session: ${tools.length} tools across ${servers.length} servers (${servers.join(", ")})`);
58
+ }
59
+ catch {
60
+ // connection state already reported above
61
+ }
62
+ lines.push(`cwd: ${cwd}`);
63
+ return lines.join("\n");
64
+ }
65
+ /** `enable` / `disable` / `restart-server` verbs via the combiner meta-tools. */
66
+ export async function metaToolCall(connection, verb, server) {
67
+ const map = {
68
+ enable: "combiner__enable_server",
69
+ disable: "combiner__disable_server",
70
+ "restart-server": "combiner__restart_server",
71
+ };
72
+ const tool = map[verb];
73
+ const result = (await connection.callTool(tool, { server_name: server }));
74
+ const text = (result?.content ?? [])
75
+ .map((b) => b.text ?? "")
76
+ .join("\n")
77
+ .trim();
78
+ return text || `${verb} ${server}: done`;
79
+ }
80
+ //# sourceMappingURL=control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.js","sourceRoot":"","sources":["../../src/client/control.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,EAAE;AACF,+EAA+E;AAC/E,mFAAmF;AACnF,kDAAkD;AAYlD,MAAM,MAAM,GAA2B;IACnC,KAAK,EAAE,GAAG;IACV,SAAS,EAAE,GAAG;IACd,QAAQ,EAAE,GAAG;IACb,UAAU,EAAE,GAAG;IACf,MAAM,EAAE,GAAG;IACX,KAAK,EAAE,GAAG;IACV,QAAQ,EAAE,GAAG;IACb,IAAI,EAAE,GAAG;CACZ,CAAA;AAED,SAAS,KAAK,CAAC,KAAyB;IACpC,IAAI,CAAC,KAAK;QAAE,OAAO,GAAG,CAAA;IACtB,OAAO,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,GAAG,CAAA;AAC7C,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAA8B,EAAE,GAAW;IACxE,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,CAAC,IAAI,CAAC,eAAe,UAAU,CAAC,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACxG,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,MAAM,UAAU,CAAC,MAAM,EAAE,CAAmB,CAAA;QAC5D,gFAAgF;QAChF,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAA;QAC1B,MAAM,OAAO,GAA6C,EAAE,CAAA;QAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;gBAClB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBACtC,MAAM,GAAG,GAAG,CAA4B,CAAA;oBACxC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;gBACtE,CAAC;YACL,CAAC;QACL,CAAC;aAAM,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,EAAE,CAAC;gBACrE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;oBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC,CAAC,CAAA;YAC/F,CAAC;QACL,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YACjG,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;YAC5E,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAA;YACpD,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,SAAS,KAAK,KAAK,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC,CAAA;QACnF,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACpF,CAAC;IACD,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,CAAA;QAC1C,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;QACpG,KAAK,CAAC,IAAI,CACN,4BAA4B,KAAK,CAAC,MAAM,iBAAiB,OAAO,CAAC,MAAM,aAAa,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5G,CAAA;IACL,CAAC;IAAC,MAAM,CAAC;QACL,0CAA0C;IAC9C,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAA;IACzB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,UAA8B,EAC9B,IAA6C,EAC7C,MAAc;IAEd,MAAM,GAAG,GAAgC;QACrC,MAAM,EAAE,yBAAyB;QACjC,OAAO,EAAE,0BAA0B;QACnC,gBAAgB,EAAE,0BAA0B;KAC/C,CAAA;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IACtB,MAAM,MAAM,GAAG,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAA2C,CAAA;IACnH,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;SACxB,IAAI,CAAC,IAAI,CAAC;SACV,IAAI,EAAE,CAAA;IACX,OAAO,IAAI,IAAI,GAAG,IAAI,IAAI,MAAM,QAAQ,CAAA;AAC5C,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { ToolDefinition } from "../pi.js";
2
+ import type { CombinerConnection, ToolSummary } from "./connection.js";
3
+ export type DirectToolsSpec = string[] | "search";
4
+ /** Names that must never be shadowed by a promoted tool (pi builtins). Callers add
5
+ * their own tool names on top. */
6
+ export declare const RESERVED_TOOL_NAMES: readonly ["read", "bash", "edit", "write", "grep", "find", "ls", "mcp", "glob"];
7
+ /** Apply a server allow/deny filter to a combined tool list. Server names may
8
+ * contain underscores (gws_georgeharker), so matching is by PREFIX — a tool
9
+ * belongs to entry E iff its name starts `E_` (subsumes first-segment equality). */
10
+ export declare function toolServerMatches(toolName: string, serverEntry: string): boolean;
11
+ /** Apply a server allow/deny filter to a combined tool list (`<server>_` prefix,
12
+ * underscore-safe via toolServerMatches). */
13
+ export declare function applyServerFilter(tools: ToolSummary[], filter: {
14
+ allow?: string[];
15
+ deny?: string[];
16
+ } | undefined): ToolSummary[];
17
+ /** fnmatch-lite: `*` → any run, `?` → one char, everything else literal. */
18
+ export declare function globToRegExp(pattern: string): RegExp;
19
+ export declare function matchesGlob(name: string, pattern: string): boolean;
20
+ /** Resolve the allowlist spec against the combined tool list (server filter applied
21
+ * by the caller). Returns matching tools in list order. */
22
+ export declare function resolveAllowlist(tools: ToolSummary[], patterns: string[]): ToolSummary[];
23
+ export type DirectToolDeps = {
24
+ connection: CombinerConnection;
25
+ /** Names already registered (shared across syncs + search activation). */
26
+ registered: Set<string>;
27
+ /** Reserved names to refuse (builtins + this extension's own tool names). */
28
+ reserved: Set<string>;
29
+ register: (tool: ToolDefinition) => void;
30
+ log: (level: "info" | "warn" | "error", message: string) => void;
31
+ };
32
+ /** Build the Pi tool definition for one promoted combiner tool. */
33
+ export declare function buildDirectTool(tool: ToolSummary, deps: DirectToolDeps): ToolDefinition;
34
+ /** Register one tool if new and not reserved. Returns the name, or undefined when skipped. */
35
+ export declare function registerDirectTool(tool: ToolSummary, deps: DirectToolDeps): string | undefined;
36
+ /** Allowlist sync: register every matching, not-yet-registered tool. */
37
+ export declare function syncAllowlistTools(tools: ToolSummary[], patterns: string[], deps: DirectToolDeps): number;
38
+ /** Search-mode activation: register matched tools (bounded per activation). Returns
39
+ * the newly activated names — empty when everything matched was already live. */
40
+ export declare function activateFromSearch(matches: ToolSummary[], deps: DirectToolDeps, max?: number): string[];
41
+ //# sourceMappingURL=direct-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-tools.d.ts","sourceRoot":"","sources":["../../src/client/direct-tools.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAItE,MAAM,MAAM,eAAe,GAAG,MAAM,EAAE,GAAG,QAAQ,CAAA;AAEjD;mCACmC;AACnC,eAAO,MAAM,mBAAmB,iFAAkF,CAAA;AAElH;;qFAEqF;AACrF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAEhF;AAED;8CAC8C;AAC9C,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,WAAW,EAAE,EACpB,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,GAC1D,WAAW,EAAE,CASf;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;4DAC4D;AAC5D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAGxF;AAWD,MAAM,MAAM,cAAc,GAAG;IACzB,UAAU,EAAE,kBAAkB,CAAA;IAC9B,0EAA0E;IAC1E,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACvB,6EAA6E;IAC7E,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAA;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACnE,CAAA;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,GAAG,cAAc,CAcvF;AAED,8FAA8F;AAC9F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,CAU9F;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,CAczG;AAED;kFACkF;AAClF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,SAAK,GAAG,MAAM,EAAE,CAQnG"}
@@ -0,0 +1,122 @@
1
+ // Direct tool promotion: allowlist + search-mode, per the agreed design
2
+ // (docs/adapter-design.md §Now/Later). Behavior follows pi-mcp-adapter's
3
+ // directTools modes (MIT, © 2026 Nico Bailon).
4
+ //
5
+ // `combiner.directTools` on the shared-file entry is either a glob allowlist over
6
+ // combined tool names — registered once at session start, cache-stable — or
7
+ // "search": nothing registered upfront; the first mcp({search}) match activates
8
+ // those tools as first-class Pi tools for the rest of the session (the adapter's
9
+ // directTools:"search" semantics, on our own mid-session registerTool path).
10
+ //
11
+ // `directTools: true` is deliberately NOT offered: at combiner scale (hundreds of
12
+ // tools) it burns the context window the proxy exists to save. Allowlists larger
13
+ // than ~50 tools draw a loud warning and still register — an explicit list is the
14
+ // user's call.
15
+ import { renderToolResult, textResult } from "./render.js";
16
+ import { directToolRenderers } from "./renderers.js";
17
+ /** Names that must never be shadowed by a promoted tool (pi builtins). Callers add
18
+ * their own tool names on top. */
19
+ export const RESERVED_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls", "mcp", "glob"];
20
+ /** Apply a server allow/deny filter to a combined tool list. Server names may
21
+ * contain underscores (gws_georgeharker), so matching is by PREFIX — a tool
22
+ * belongs to entry E iff its name starts `E_` (subsumes first-segment equality). */
23
+ export function toolServerMatches(toolName, serverEntry) {
24
+ return toolName.startsWith(`${serverEntry}_`);
25
+ }
26
+ /** Apply a server allow/deny filter to a combined tool list (`<server>_` prefix,
27
+ * underscore-safe via toolServerMatches). */
28
+ export function applyServerFilter(tools, filter) {
29
+ if (!filter)
30
+ return tools;
31
+ if (filter.allow?.length) {
32
+ return tools.filter((t) => filter.allow.some((e) => toolServerMatches(t.name, e)));
33
+ }
34
+ if (filter.deny?.length) {
35
+ return tools.filter((t) => !filter.deny.some((e) => toolServerMatches(t.name, e)));
36
+ }
37
+ return tools;
38
+ }
39
+ /** fnmatch-lite: `*` → any run, `?` → one char, everything else literal. */
40
+ export function globToRegExp(pattern) {
41
+ const escaped = pattern
42
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
43
+ .replace(/\*/g, ".*")
44
+ .replace(/\?/g, ".");
45
+ return new RegExp(`^${escaped}$`, "i");
46
+ }
47
+ export function matchesGlob(name, pattern) {
48
+ return globToRegExp(pattern).test(name);
49
+ }
50
+ /** Resolve the allowlist spec against the combined tool list (server filter applied
51
+ * by the caller). Returns matching tools in list order. */
52
+ export function resolveAllowlist(tools, patterns) {
53
+ const regexes = patterns.map(globToRegExp);
54
+ return tools.filter((t) => regexes.some((re) => re.test(t.name)));
55
+ }
56
+ /** Ensure a usable parameters object: pass the advertised JSON schema through when it
57
+ * is an object; repair anything else to an empty object schema. */
58
+ function normalizeInputSchema(schema) {
59
+ if (typeof schema === "object" && schema !== null && !Array.isArray(schema)) {
60
+ return schema;
61
+ }
62
+ return { type: "object", properties: {} };
63
+ }
64
+ /** Build the Pi tool definition for one promoted combiner tool. */
65
+ export function buildDirectTool(tool, deps) {
66
+ return {
67
+ name: tool.name,
68
+ label: `MCP: ${tool.name}`,
69
+ description: tool.description ?? `Combiner tool ${tool.name}`,
70
+ parameters: normalizeInputSchema(tool.inputSchema),
71
+ ...directToolRenderers(tool.name),
72
+ execute: async () => {
73
+ const result = await deps.connection.callTool(tool.name, undefined);
74
+ const text = renderToolResult(result);
75
+ if (result?.isError)
76
+ throw new Error(text);
77
+ return textResult(text);
78
+ },
79
+ };
80
+ }
81
+ /** Register one tool if new and not reserved. Returns the name, or undefined when skipped. */
82
+ export function registerDirectTool(tool, deps) {
83
+ if (deps.registered.has(tool.name))
84
+ return undefined;
85
+ if (deps.reserved.has(tool.name)) {
86
+ deps.log("warn", `directTools: refusing to register "${tool.name}" — reserved name`);
87
+ deps.registered.add(tool.name); // don't re-warn on every sync
88
+ return undefined;
89
+ }
90
+ deps.registered.add(tool.name);
91
+ deps.register(buildDirectTool(tool, deps));
92
+ return tool.name;
93
+ }
94
+ /** Allowlist sync: register every matching, not-yet-registered tool. */
95
+ export function syncAllowlistTools(tools, patterns, deps) {
96
+ const matches = resolveAllowlist(tools, patterns);
97
+ if (matches.length > 50) {
98
+ deps.log("warn", `directTools: allowlist promotes ${matches.length} tools — every schema rides in every ` +
99
+ "request. Consider trimming (the mcp() proxy covers the rest).");
100
+ }
101
+ let added = 0;
102
+ for (const tool of matches) {
103
+ if (registerDirectTool(tool, deps))
104
+ added++;
105
+ }
106
+ return added;
107
+ }
108
+ /** Search-mode activation: register matched tools (bounded per activation). Returns
109
+ * the newly activated names — empty when everything matched was already live. */
110
+ export function activateFromSearch(matches, deps, max = 10) {
111
+ const activated = [];
112
+ for (const tool of matches) {
113
+ if (activated.length >= max)
114
+ break;
115
+ if (deps.registered.has(tool.name))
116
+ continue;
117
+ if (registerDirectTool(tool, deps))
118
+ activated.push(tool.name);
119
+ }
120
+ return activated;
121
+ }
122
+ //# sourceMappingURL=direct-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-tools.js","sourceRoot":"","sources":["../../src/client/direct-tools.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,yEAAyE;AACzE,+CAA+C;AAC/C,EAAE;AACF,kFAAkF;AAClF,4EAA4E;AAC5E,gFAAgF;AAChF,iFAAiF;AACjF,6EAA6E;AAC7E,EAAE;AACF,kFAAkF;AAClF,iFAAiF;AACjF,kFAAkF;AAClF,eAAe;AAIf,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAIpD;mCACmC;AACnC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAU,CAAA;AAElH;;qFAEqF;AACrF,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,WAAmB;IACnE,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,WAAW,GAAG,CAAC,CAAA;AACjD,CAAC;AAED;8CAC8C;AAC9C,MAAM,UAAU,iBAAiB,CAC7B,KAAoB,EACpB,MAAyD;IAEzD,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACzB,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IACvF,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IACvF,CAAC;IACD,OAAO,KAAK,CAAA;AAChB,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,OAAe;IACxC,MAAM,OAAO,GAAG,OAAO;SAClB,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC;SACpC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACxB,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,EAAE,GAAG,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,OAAe;IACrD,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3C,CAAC;AAED;4DAC4D;AAC5D,MAAM,UAAU,gBAAgB,CAAC,KAAoB,EAAE,QAAkB;IACrE,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IAC1C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACrE,CAAC;AAED;oEACoE;AACpE,SAAS,oBAAoB,CAAC,MAAe;IACzC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1E,OAAO,MAAiC,CAAA;IAC5C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,CAAA;AAC7C,CAAC;AAYD,mEAAmE;AACnE,MAAM,UAAU,eAAe,CAAC,IAAiB,EAAE,IAAoB;IACnE,OAAO;QACH,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,QAAQ,IAAI,CAAC,IAAI,EAAE;QAC1B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,iBAAiB,IAAI,CAAC,IAAI,EAAE;QAC7D,UAAU,EAAE,oBAAoB,CAAC,IAAI,CAAC,WAAW,CAAC;QAClD,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;QACjC,OAAO,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;YACnE,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;YACrC,IAAK,MAAgC,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,CAAA;YACrE,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC;KACJ,CAAA;AACL,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,kBAAkB,CAAC,IAAiB,EAAE,IAAoB;IACtE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,sCAAsC,IAAI,CAAC,IAAI,mBAAmB,CAAC,CAAA;QACpF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAC,8BAA8B;QAC7D,OAAO,SAAS,CAAA;IACpB,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAA;AACpB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,kBAAkB,CAAC,KAAoB,EAAE,QAAkB,EAAE,IAAoB;IAC7F,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IACjD,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,CACJ,MAAM,EACN,mCAAmC,OAAO,CAAC,MAAM,uCAAuC;YACpF,+DAA+D,CACtE,CAAA;IACL,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE,KAAK,EAAE,CAAA;IAC/C,CAAC;IACD,OAAO,KAAK,CAAA;AAChB,CAAC;AAED;kFACkF;AAClF,MAAM,UAAU,kBAAkB,CAAC,OAAsB,EAAE,IAAoB,EAAE,GAAG,GAAG,EAAE;IACrF,MAAM,SAAS,GAAa,EAAE,CAAA;IAC9B,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,SAAS,CAAC,MAAM,IAAI,GAAG;YAAE,MAAK;QAClC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC5C,IAAI,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACjE,CAAC;IACD,OAAO,SAAS,CAAA;AACpB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { ExtensionUIContext } from "../pi.js";
2
+ export type ElicitUi = {
3
+ hasUI: boolean;
4
+ ui?: ExtensionUIContext;
5
+ };
6
+ export type ElicitRequest = {
7
+ message?: string;
8
+ requestedSchema?: unknown;
9
+ };
10
+ export type ElicitResponse = {
11
+ action: "accept";
12
+ content: Record<string, ElicitValue>;
13
+ } | {
14
+ action: "decline" | "cancel";
15
+ };
16
+ /** Primitive value an elicitation form can collect (the SDK's accepted value set,
17
+ * incl. string[] for array-typed form fields). */
18
+ export type ElicitValue = string | number | boolean | string[];
19
+ /** Handle an elicitation request against Pi's UI. Never throws — a UI that can't
20
+ * answer declines, and the combiner applies its elicitUnavailable policy. */
21
+ export declare function handleElicitation(req: ElicitRequest, elicitUi: ElicitUi): Promise<ElicitResponse>;
22
+ //# sourceMappingURL=elicitation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../../src/client/elicitation.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAElD,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAElE,MAAM,MAAM,aAAa,GAAG;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAA;AAIjG;mDACmD;AACnD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAA;AAiD9D;8EAC8E;AAC9E,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CA2BvG"}
@@ -0,0 +1,93 @@
1
+ // Elicitation bridge: MCP server→client elicitation → Pi's ctx.ui dialogs.
2
+ //
3
+ // The structured dialogs (select/confirm/input) are the right model: each mode
4
+ // (interactive, RPC, print) provides its own implementation, so a gate question
5
+ // renders as a native TUI dialog locally AND extends over the wire as
6
+ // extension_ui_request frames in RPC mode — remote clients (e.g. un-bien's
7
+ // paired app) render them natively. Custom TUI overlays would be interactive-
8
+ // mode-only and would not reach remote clients; pi-ask's flow is a separate
9
+ // protocol we deliberately don't couple to.
10
+ //
11
+ // Load-bearing for the combiner's permissions gate, which elicits
12
+ // (Allow once / Allow for session / Deny) for tools whose policy resolves to elicit;
13
+ // its secure fallback is elicitUnavailable: deny. So when no dialog-capable UI exists
14
+ // we return "decline" rather than hanging — the combiner then denies the call.
15
+ //
16
+ // Simplified from pi-mcp-adapter's elicitation-handler.ts (MIT, © 2026 Nico Bailon):
17
+ // form schemas map to sequential per-property dialogs (enum→select, boolean→confirm,
18
+ // string/number→input); there is no URL-elicitation mode (no OAuth here).
19
+ // Options are returned VERBATIM — the combiner string-matches the gate choice.
20
+ const REFUSE = { action: "decline" };
21
+ function isRecord(v) {
22
+ return typeof v === "object" && v !== null && !Array.isArray(v);
23
+ }
24
+ /** Coerce raw dialog input to the declared primitive; undefined when it doesn't fit. */
25
+ function coerce(raw, type) {
26
+ if (type === "number" || type === "integer") {
27
+ const n = Number(raw);
28
+ if (!Number.isFinite(n))
29
+ return undefined;
30
+ return type === "integer" ? Math.trunc(n) : n;
31
+ }
32
+ return raw;
33
+ }
34
+ /** Present one property's dialog; returns the value or undefined (cancelled/invalid). */
35
+ async function askProperty(ui, label, prop) {
36
+ const type = typeof prop.type === "string" ? prop.type : "string";
37
+ const desc = typeof prop.description === "string" && prop.description ? ` — ${prop.description}` : "";
38
+ if (Array.isArray(prop.enum) && prop.enum.every((v) => typeof v === "string")) {
39
+ const options = prop.enum;
40
+ const picked = await ui.select?.(`${label}${desc}`, options);
41
+ return picked;
42
+ }
43
+ if (type === "boolean") {
44
+ return await ui.confirm?.(label, `${prop.description ?? "Allow this request?"}`, undefined);
45
+ }
46
+ if (type === "array") {
47
+ // Best-effort arrays: comma-separated input (v1 — no repeat-prompt loop yet).
48
+ const raw = await ui.input?.(`${label}${desc}`, "a,b,c (comma-separated)");
49
+ if (raw === undefined)
50
+ return undefined;
51
+ const items = raw
52
+ .split(",")
53
+ .map((s) => s.trim())
54
+ .filter((s) => s.length > 0);
55
+ return items;
56
+ }
57
+ const raw = await ui.input?.(`${label}${desc}`, type === "string" ? "string" : type);
58
+ if (raw === undefined)
59
+ return undefined;
60
+ const value = coerce(raw, type);
61
+ return value;
62
+ }
63
+ /** Handle an elicitation request against Pi's UI. Never throws — a UI that can't
64
+ * answer declines, and the combiner applies its elicitUnavailable policy. */
65
+ export async function handleElicitation(req, elicitUi) {
66
+ if (!elicitUi.hasUI || !elicitUi.ui?.select || !elicitUi.ui.input)
67
+ return REFUSE;
68
+ const schema = isRecord(req.requestedSchema) ? req.requestedSchema : undefined;
69
+ const props = schema && isRecord(schema.properties) ? schema.properties : undefined;
70
+ const header = typeof req.message === "string" && req.message ? req.message : "MCP server request";
71
+ // No schema → boolean-shaped consent question (covers plain allow/deny elicits).
72
+ if (!props || Object.keys(props).length === 0) {
73
+ const ok = await elicitUi.ui.confirm?.(header, "Allow?", undefined);
74
+ if (ok === undefined)
75
+ return REFUSE;
76
+ return ok ? { action: "accept", content: {} } : REFUSE;
77
+ }
78
+ // Sequential per-property dialogs — each element rides the mode-implemented
79
+ // UI surface, so multi-property forms work over the wire too. A single-
80
+ // property form (the consent-gate shape) asks under the bare message; only
81
+ // multi-property forms prefix the property name.
82
+ const entries = Object.entries(props).filter(([, v]) => isRecord(v));
83
+ const content = {};
84
+ for (const [name, raw] of entries) {
85
+ const label = entries.length === 1 ? header : `${header}: ${name}`;
86
+ const value = await askProperty(elicitUi.ui, label, raw);
87
+ if (value === undefined)
88
+ return REFUSE;
89
+ content[name] = value;
90
+ }
91
+ return { action: "accept", content };
92
+ }
93
+ //# sourceMappingURL=elicitation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elicitation.js","sourceRoot":"","sources":["../../src/client/elicitation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { CombinerConnection } from "./connection.js";
2
+ import type { ExtensionUIContext } from "../pi.js";
3
+ import type { FooterStatus } from "./settings.js";
4
+ export type FooterCounts = {
5
+ enabled: number;
6
+ ready: number;
7
+ disabled: number;
8
+ };
9
+ /** Derive enabled/ready/disabled counts from a /health snapshot. Tolerates both
10
+ * the object-keyed shape (what the combiner serves) and an array (defensive). */
11
+ export declare function countsFromHealth(health: unknown): FooterCounts;
12
+ /** Render the footer text for a mode (undefined = clear the slot). */
13
+ export declare function footerText(mode: FooterStatus, counts: FooterCounts, connectionState: string, toolCount?: number): string | undefined;
14
+ /** Refresh the footer from live health + this session's tool view. Never throws;
15
+ * logs (once) when the UI cannot take a status so a dead label is diagnosable. */
16
+ export declare function updateFooter(connection: CombinerConnection, ui: ExtensionUIContext | undefined, key: string, mode: FooterStatus): Promise<void>;
17
+ //# sourceMappingURL=footer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../src/client/footer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAajD,MAAM,MAAM,YAAY,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E;kFACkF;AAClF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,CAyB9D;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CACtB,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAWpB;AAID;mFACmF;AACnF,wBAAsB,YAAY,CAC9B,UAAU,EAAE,kBAAkB,EAC9B,EAAE,EAAE,kBAAkB,GAAG,SAAS,EAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
@@ -0,0 +1,99 @@
1
+ // Footer status line for enabled MCP servers, compatible with pi-mcp-adapter's
2
+ // mcpFooterStatus setting: "full" (default) = "N servers enabled (M ready) · T tools",
3
+ // "compact" = "MCP M/N", "off" = none. Published via ctx.ui.setStatus under the key
4
+ // `mcp` (default, overridable via the mcpFooterKey setting) — the slot
5
+ // pi-mcp-adapter wrote and oh-my-posh-style footers aggregate into PI_STATUS.
6
+ /** Health entry server states we count as "ready" (combiner /health semantics). */
7
+ const READY_STATES = new Set(["ready", "connected"]);
8
+ /** nf-fa-plug (U+F1E6), emitted directly — a nerd-font codepoint, never an emoji,
9
+ * so the glyph renders in any nerd-font terminal and passes through footer
10
+ * translation layers (oh-my-posh's ICON_MAP) untouched. */
11
+ const PLUG = "\uF1E6";
12
+ /** Derive enabled/ready/disabled counts from a /health snapshot. Tolerates both
13
+ * the object-keyed shape (what the combiner serves) and an array (defensive). */
14
+ export function countsFromHealth(health) {
15
+ const raw = health?.servers;
16
+ const entries = [];
17
+ if (Array.isArray(raw)) {
18
+ for (const s of raw)
19
+ if (typeof s === "object" && s !== null)
20
+ entries.push(["", s]);
21
+ }
22
+ else if (typeof raw === "object" && raw !== null) {
23
+ for (const [name, s] of Object.entries(raw)) {
24
+ if (typeof s === "object" && s !== null)
25
+ entries.push([name, s]);
26
+ }
27
+ }
28
+ else {
29
+ return { enabled: 0, ready: 0, disabled: 0 };
30
+ }
31
+ let enabled = 0;
32
+ let ready = 0;
33
+ let disabled = 0;
34
+ for (const [, s] of entries) {
35
+ if (s.disabled) {
36
+ disabled++;
37
+ continue;
38
+ }
39
+ enabled++;
40
+ const state = (s.state ?? s.status ?? "").toLowerCase();
41
+ if (READY_STATES.has(state))
42
+ ready++;
43
+ }
44
+ return { enabled, ready, disabled };
45
+ }
46
+ /** Render the footer text for a mode (undefined = clear the slot). */
47
+ export function footerText(mode, counts, connectionState, toolCount) {
48
+ if (mode === "off")
49
+ return undefined;
50
+ if (mode === "compact")
51
+ return `${PLUG} MCP ${counts.ready}/${counts.enabled}`;
52
+ let text = `${PLUG} ${counts.enabled} ${counts.enabled === 1 ? "server" : "servers"} enabled`;
53
+ if (counts.ready > 0)
54
+ text += ` (${counts.ready} ready)`;
55
+ if (counts.disabled > 0)
56
+ text += ` (${counts.disabled} disabled)`;
57
+ if (typeof toolCount === "number" && toolCount > 0)
58
+ text += ` · ${toolCount} tools`;
59
+ if (connectionState !== "connected" && connectionState !== "disconnected") {
60
+ text += ` — ${connectionState}`;
61
+ }
62
+ return text;
63
+ }
64
+ let warnedNoSetStatus = false;
65
+ /** Refresh the footer from live health + this session's tool view. Never throws;
66
+ * logs (once) when the UI cannot take a status so a dead label is diagnosable. */
67
+ export async function updateFooter(connection, ui, key, mode) {
68
+ if (mode === "off")
69
+ return;
70
+ const setStatus = ui?.setStatus;
71
+ if (!setStatus) {
72
+ if (!warnedNoSetStatus) {
73
+ warnedNoSetStatus = true;
74
+ // Headless/print modes have no footer — fine — but a TUI session with no
75
+ // setStatus deserves one log line rather than a silently missing label.
76
+ if (ui)
77
+ console.error(`mcp-combiner: footer unavailable (ctx.ui has no setStatus)`);
78
+ }
79
+ return;
80
+ }
81
+ let text;
82
+ try {
83
+ const [health, tools] = await Promise.all([connection.health(), connection.listTools().catch(() => undefined)]);
84
+ const toolCount = tools?.length;
85
+ text = footerText(mode, countsFromHealth(health), connection.state, toolCount);
86
+ }
87
+ catch {
88
+ // Combiner unreachable: report our connection state honestly, still occupying
89
+ // the slot so the label never silently vanishes.
90
+ text = footerText(mode, { enabled: 0, ready: 0, disabled: 0 }, connection.state);
91
+ }
92
+ try {
93
+ setStatus(key, text);
94
+ }
95
+ catch (e) {
96
+ console.error(`mcp-combiner: footer setStatus failed (${e instanceof Error ? e.message : String(e)})`);
97
+ }
98
+ }
99
+ //# sourceMappingURL=footer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../src/client/footer.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,uFAAuF;AACvF,oFAAoF;AACpF,uEAAuE;AACvE,8EAA8E;AAM9E,mFAAmF;AACnF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAA;AAEpD;;4DAE4D;AAC5D,MAAM,IAAI,GAAG,QAAQ,CAAA;AAOrB;kFACkF;AAClF,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC5C,MAAM,GAAG,GAAI,MAAgC,EAAE,OAAO,CAAA;IACtD,MAAM,OAAO,GAAkC,EAAE,CAAA;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,GAAG;YAAE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAiB,CAAC,CAAC,CAAA;IACvG,CAAC;SAAM,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,EAAE,CAAC;YACrE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAiB,CAAC,CAAC,CAAA;QACpF,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAA;IAChD,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YACb,QAAQ,EAAE,CAAA;YACV,SAAQ;QACZ,CAAC;QACD,OAAO,EAAE,CAAA;QACT,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;QACvD,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,KAAK,EAAE,CAAA;IACxC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;AACvC,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,UAAU,CACtB,IAAkB,EAClB,MAAoB,EACpB,eAAuB,EACvB,SAAkB;IAElB,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,SAAS,CAAA;IACpC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,GAAG,IAAI,QAAQ,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,EAAE,CAAA;IAC9E,IAAI,IAAI,GAAG,GAAG,IAAI,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,UAAU,CAAA;IAC7F,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC;QAAE,IAAI,IAAI,KAAK,MAAM,CAAC,KAAK,SAAS,CAAA;IACxD,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC;QAAE,IAAI,IAAI,KAAK,MAAM,CAAC,QAAQ,YAAY,CAAA;IACjE,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,GAAG,CAAC;QAAE,IAAI,IAAI,MAAM,SAAS,QAAQ,CAAA;IACnF,IAAI,eAAe,KAAK,WAAW,IAAI,eAAe,KAAK,cAAc,EAAE,CAAC;QACxE,IAAI,IAAI,MAAM,eAAe,EAAE,CAAA;IACnC,CAAC;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAED,IAAI,iBAAiB,GAAG,KAAK,CAAA;AAE7B;mFACmF;AACnF,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,UAA8B,EAC9B,EAAkC,EAClC,GAAW,EACX,IAAkB;IAElB,IAAI,IAAI,KAAK,KAAK;QAAE,OAAM;IAC1B,MAAM,SAAS,GAAG,EAAE,EAAE,SAAS,CAAA;IAC/B,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACrB,iBAAiB,GAAG,IAAI,CAAA;YACxB,yEAAyE;YACzE,wEAAwE;YACxE,IAAI,EAAE;gBAAE,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAA;QACvF,CAAC;QACD,OAAM;IACV,CAAC;IACD,IAAI,IAAwB,CAAA;IAC5B,IAAI,CAAC;QACD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,UAAU,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;QAC/G,MAAM,SAAS,GAAG,KAAK,EAAE,MAAM,CAAA;QAC/B,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IAClF,CAAC;IAAC,MAAM,CAAC;QACL,8EAA8E;QAC9E,iDAAiD;QACjD,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IACpF,CAAC;IACD,IAAI,CAAC;QACD,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAC1G,CAAC;AACL,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { CombinerConnection } from "./connection.js";
2
+ export type PanelDeps = {
3
+ connection: CombinerConnection;
4
+ toolName: string;
5
+ /** This session's grouping token (identity row). */
6
+ getToken: () => string | undefined;
7
+ /** This session's project server filter, if any ([session off] labels). */
8
+ getFilter: () => {
9
+ allow?: string[];
10
+ deny?: string[];
11
+ } | undefined;
12
+ notify: (message: string, level?: "info" | "warn" | "error") => void;
13
+ };
14
+ /** Open the panel as a centered overlay; resolves when closed. */
15
+ export declare function openCombinerPanel(deps: PanelDeps, ui: unknown): Promise<void>;
16
+ //# sourceMappingURL=panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/client/panel.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAA+C,MAAM,iBAAiB,CAAA;AAQtG,MAAM,MAAM,SAAS,GAAG;IACpB,UAAU,EAAE,kBAAkB,CAAA;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,oDAAoD;IACpD,QAAQ,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAClC,2EAA2E;IAC3E,SAAS,EAAE,MAAM;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS,CAAA;IAClE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,KAAK,IAAI,CAAA;CACvE,CAAA;AA6aD,kEAAkE;AAClE,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBnF"}