host-execution-mcp 1.0.0 → 2.0.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 (94) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +14 -12
  3. package/SECURITY.md +3 -3
  4. package/dist/access/index.d.ts +21 -10
  5. package/dist/access/index.js +55 -27
  6. package/dist/access/index.js.map +1 -1
  7. package/dist/access/paradi-auth.d.ts +3 -3
  8. package/dist/access/paradi-auth.js +4 -4
  9. package/dist/access/paradi-auth.js.map +1 -1
  10. package/dist/access/paradi-transport.d.ts +1 -1
  11. package/dist/access/paradi-transport.js +3 -3
  12. package/dist/access/paradi-transport.js.map +1 -1
  13. package/dist/access/paradi-username.d.ts +1 -1
  14. package/dist/access/paradi-username.js +2 -2
  15. package/dist/access/paradi-username.js.map +1 -1
  16. package/dist/access/session-pool.d.ts +5 -0
  17. package/dist/access/session-pool.js +7 -0
  18. package/dist/access/session-pool.js.map +1 -1
  19. package/dist/access/ssh-transport.d.ts +1 -1
  20. package/dist/access/ssh-transport.js +3 -2
  21. package/dist/access/ssh-transport.js.map +1 -1
  22. package/dist/config-yaml.d.ts +54 -0
  23. package/dist/config-yaml.js +172 -0
  24. package/dist/config-yaml.js.map +1 -0
  25. package/dist/config.d.ts +45 -1
  26. package/dist/config.js +126 -22
  27. package/dist/config.js.map +1 -1
  28. package/dist/index.js +3 -3
  29. package/dist/index.js.map +1 -1
  30. package/dist/instructions.d.ts +4 -1
  31. package/dist/instructions.js +92 -70
  32. package/dist/instructions.js.map +1 -1
  33. package/dist/kubectl/runner.d.ts +7 -8
  34. package/dist/kubectl/runner.js +18 -21
  35. package/dist/kubectl/runner.js.map +1 -1
  36. package/dist/link-runtime.d.ts +39 -0
  37. package/dist/link-runtime.js +134 -0
  38. package/dist/link-runtime.js.map +1 -0
  39. package/dist/server.d.ts +2 -1
  40. package/dist/server.js +10 -12
  41. package/dist/server.js.map +1 -1
  42. package/dist/sources/guides.d.ts +34 -0
  43. package/dist/sources/guides.js +50 -0
  44. package/dist/sources/guides.js.map +1 -0
  45. package/dist/sources/index.d.ts +5 -0
  46. package/dist/sources/index.js +22 -0
  47. package/dist/sources/index.js.map +1 -0
  48. package/dist/sources/yaml-template.d.ts +31 -0
  49. package/dist/sources/yaml-template.js +35 -0
  50. package/dist/sources/yaml-template.js.map +1 -0
  51. package/dist/ssh/access-client.d.ts +6 -2
  52. package/dist/ssh/access-client.js +58 -27
  53. package/dist/ssh/access-client.js.map +1 -1
  54. package/dist/ssh/access-errors.js +1 -1
  55. package/dist/ssh/access-errors.js.map +1 -1
  56. package/dist/ssh/access-sftp.js +3 -3
  57. package/dist/ssh/access-sftp.js.map +1 -1
  58. package/dist/tools/copy-job-schemas.d.ts +96 -581
  59. package/dist/tools/copy-job-schemas.js +9 -9
  60. package/dist/tools/copy-job-schemas.js.map +1 -1
  61. package/dist/tools/register.d.ts +2 -10
  62. package/dist/tools/register.js +174 -331
  63. package/dist/tools/register.js.map +1 -1
  64. package/dist/tools/remote-schemas.d.ts +156 -708
  65. package/dist/tools/remote-schemas.js +99 -103
  66. package/dist/tools/remote-schemas.js.map +1 -1
  67. package/dist/utils/copy-executor.d.ts +3 -1
  68. package/dist/utils/copy-executor.js +39 -25
  69. package/dist/utils/copy-executor.js.map +1 -1
  70. package/dist/utils/copy-transfer.d.ts +2 -0
  71. package/dist/utils/copy-transfer.js.map +1 -1
  72. package/dist/utils/remote-executor.d.ts +3 -4
  73. package/dist/utils/remote-executor.js +8 -18
  74. package/dist/utils/remote-executor.js.map +1 -1
  75. package/dist/utils/remote-target.js +1 -1
  76. package/dist/utils/remote-target.js.map +1 -1
  77. package/docs/AGENT_GUIDE.md +31 -103
  78. package/docs/CONFIGURATION.md +39 -10
  79. package/docs/GUIDE.md +186 -0
  80. package/docs/PARADI_ACCESS_PLAN.md +6 -6
  81. package/docs/TODO.md +4 -11
  82. package/docs/USER_GUIDE.zh-CN.md +38 -69
  83. package/docs/host-execution.yaml +92 -0
  84. package/docs/paradi-gateway-interactive.png +0 -0
  85. package/package.json +67 -65
  86. package/dist/ssh/bastion-client.d.ts +0 -60
  87. package/dist/ssh/bastion-client.js +0 -423
  88. package/dist/ssh/bastion-client.js.map +0 -1
  89. package/dist/ssh/bastion-errors.d.ts +0 -62
  90. package/dist/ssh/bastion-errors.js +0 -190
  91. package/dist/ssh/bastion-errors.js.map +0 -1
  92. package/dist/ssh/hop1-sftp.d.ts +0 -14
  93. package/dist/ssh/hop1-sftp.js +0 -437
  94. package/dist/ssh/hop1-sftp.js.map +0 -1
@@ -1,88 +1,90 @@
1
+ import { loadSourceLinks } from "./config-yaml.js";
1
2
  function buildSshBaseInstructions() {
2
- return `You are connected to host-execution-mcp, a HostExecutionContext-based remote execution MCP.
3
-
4
- Execution model:
5
- Access: MCP client → AccessTransport → HostExecutionContext (landing)
6
- Runtime: selected Context → shell / docker / k8s / copy (SessionPool; Runtime never creates SSH)
7
- Derive: context_derive → contextKey (ACCESS_KIND=ssh only). NOT SSH from the laptop.
8
-
9
- Context vs shell:
10
- - context_derive — create a derived HostExecutionContext; returns contextKey (does not probe reachability)
11
- - shell_exec — shell on a Context; never creates Context (omit contextKey = AccessTransport landing)
12
- - ssh_exec — shortcut for context_derive + shell_exec; returns reusable contextKey. Prefer for derive+shell in one call; reuse the key for follow-up docker_*/remote_*/shell_exec
13
-
14
- docker_* / context_probe: Runtime on selected Context.
15
- Omit contextKey = AccessTransport landing (ACCESS under ssh; TARGET under paradi-gateway).
16
-
17
- remote_* target=context = HostExecutionContext by contextKey (from context_derive / ssh_exec).
18
-
19
- Tool selection:
20
- - access_check — Local→ACCESS connectivity (≤10s; NOT kubectl). First session / after ACCESS_UNAVAILABLE
21
- - shell_exec — landing or derived shell (contextKey)
22
- - context_derive — need a contextKey without running a command yet
23
- - ssh_exec — one-shot derive+shell (returns contextKey)
24
- - docker_* — Docker on landing or contextKey
25
- - k8s_* — kubectl on landing only (by design). kubectl on a derived host: shell_exec(contextKey, "kubectl …")
26
- - remote_* target=landing|pod|context — files/ps/copy
27
- - remote_copy_file vs remote_copy_start — sync vs async; never auto-promote; prefer start when size>256MB or ETA>2min
28
-
29
- Hard rules:
30
- - access_check.reachable=false or code=ACCESS_UNAVAILABLE → stop (VPN / ACCESS_HOST); do not retry other tools
31
- - SSH success ≠ docker/kubectl; unknown ≠ true — never invent true; never reuse capabilities across Contexts
32
- - Before pkill/kill/rm: remote_ps or user confirmation
33
- - Never assume namespace/paths; never reuse ACCESS_USER as TARGET_USER / derive user
34
- - success=false: read stdout (stderr merged). truncated → more lines / remote_copy_*
35
- - Multi-container pods: pass container name
36
- - Operational cookbook (shell quoting, CRLF, docker login quirks, registry probes): see docs/AGENT_GUIDE.md`;
3
+ return `You are connected to host-execution-mcp.
4
+
5
+ Execution model:
6
+ Access: MCP client → SSH → this YAML link's landing (ACCESS_HOST)
7
+ Runtime: shell / docker / kubectl / copy on that landing
8
+ Second hop: pass host (IP reachable FROM ACCESS). Omit host = stay on the landing.
9
+ This tool path is ACCESS→host, not laptop SSH.
10
+
11
+ Tools:
12
+ - access_check — Local→ACCESS probe (≤10s; NOT kubectl). First session / after ACCESS_UNAVAILABLE
13
+ - shell_exec — command on the selected machine (omit host = landing; pass host = hop-2)
14
+ - context_probe / docker_* / k8s_* / remote_* — same pick: description + optional host
15
+ - remote_read_file / remote_ps — path on that machine; add namespace+pod to go into a container via kubectl there
16
+ - remote_copy_* — endpoints target=local|remote|pod; remote/pod use the same selected machine
17
+
18
+ Hard rules:
19
+ - access_check.reachable=false or code=ACCESS_UNAVAILABLE → stop THIS link (VPN / ACCESS_HOST). Other YAML descriptions may still work.
20
+ - SSH success ≠ docker/kubectl; unknown ≠ true — never invent true; never reuse capabilities across machines
21
+ - Before pkill/kill/rm: remote_ps or user confirmation
22
+ - Never assume namespace/paths; never reuse ACCESS_USER as hop-2 user
23
+ - success=false: read stdout (stderr merged). truncated → more lines / remote_copy_*
24
+ - Multi-container pods: pass container name
25
+ - Once per conversation: listResources and read host-execution://guides/user, host-execution://guides/agent, and host-execution://guides/yaml. GUIDE is the capability the user wants; if a tool cannot meet it, tell the user. Reuse for the session — do not look for repo file paths.`;
37
26
  }
38
27
  function buildParadiBaseInstructions(config) {
39
- const target = config.targetHost?.trim() || "<TARGET_HOST>";
40
- return `You are connected to host-execution-mcp, a HostExecutionContext-based remote execution MCP (ACCESS_KIND=paradi-gateway).
41
-
42
- Landing endpoint is TARGET (${target}) — not the gateway OS. Runtime does not know gateway details; never creates SSH.
43
-
44
- Derive / context_derive / ssh_exec / remote_* target=context / contextKey: unsupported by current Paradi AccessTransport (landing is already TARGET). Handlers throw if called — omit contextKey; use target=landing|pod|local.
45
-
46
- Default workflow:
47
- - Shell: shell_exec or remote_* target=landing
48
- - Docker / context_probe: omit contextKey (landing = TARGET)
49
- - Pods: k8s_* / remote_* target=pod (kubectl on landing)
50
- - Copy: local↔landing or pod/local; SFTP degraded — prefer remote_copy_start for large files
51
-
52
- Hard rules:
53
- - access_check.reachable=false or ACCESS_UNAVAILABLE → stop (VPN / ACCESS_HOST)
54
- - unknown ≠ true; SSH success ≠ docker/kubectl; never reuse capabilities across Contexts
55
- - Before pkill/kill/rm: remote_ps or user confirmation
56
- - Never assume namespace/paths
57
- - Operational cookbook: docs/AGENT_GUIDE.md`;
28
+ const target = config.targetHost?.trim();
29
+ const landingHint = target
30
+ ? `TARGET_HOSTS has one landing (${target}) — omit host on that machine.`
31
+ : `TARGET_HOSTS has no single default — pass host to select a TARGET landing.`;
32
+ return `You are connected to host-execution-mcp (ACCESS_KIND=paradi-gateway).
33
+
34
+ ${landingHint} Landing is a TARGET OS (encoded at the gateway), not the gateway OS.
35
+ Pass host to select a TARGET landing (gateway re-encodes identity) — not hop-2 SSH from the current machine.
36
+
37
+ Workflow:
38
+ - One TARGET_HOSTS: omit host
39
+ - Many or omitted: pass host on shell_exec / docker_* / remote_*
40
+ - Pods / copy: same machine as shell_exec. Copy target=remote = that landing; no hop-2. SFTP degraded — prefer remote_copy_start for large files.
41
+
42
+ Hard rules:
43
+ - access_check.reachable=false or ACCESS_UNAVAILABLE → stop THIS link (VPN / ACCESS_HOST)
44
+ - unknown ≠ true; SSH success ≠ docker/kubectl; never reuse capabilities across machines
45
+ - Before pkill/kill/rm: remote_ps or user confirmation
46
+ - Never assume namespace/paths
47
+ - Once per conversation: listResources and read host-execution://guides/user, host-execution://guides/agent, and host-execution://guides/yaml. GUIDE is the capability the user wants; if a tool cannot meet it, tell the user. Reuse for the session — do not look for repo file paths.`;
58
48
  }
59
- /** TARGET_* default derive auth so agents omit configured defaults instead of asking the human. */
49
+ /** TARGET_* default hop-2 / Paradi auth so agents omit configured defaults instead of asking the human. */
60
50
  export function buildDerivedHostAuthGuidance(config) {
61
51
  if (config.accessKind === "paradi-gateway") {
62
- const host = config.targetHost?.trim();
63
- return `
64
- Paradi landing: Context endpoint is TARGET${host ? ` (${host})` : ""}. Derive unsupported by current Paradi AccessTransport — omit contextKey; context_derive / ssh_exec / target=context throw if called. Use shell_exec, docker_*, k8s_*, target=landing|pod|local.`;
52
+ return `
53
+ Paradi landing select.${formatTargetHostHint(config)} Pass host on tools to pick a TARGET landing (gateway re-encodes identity). Omit user/password when TARGET_USER is set. Do not hop-2 from a Paradi landing.`;
65
54
  }
66
55
  const user = config.targetUser?.trim();
67
56
  const passwordSet = Boolean(config.targetPassword);
68
- const host = config.targetHost?.trim();
69
- const hostHint = host ? ` TARGET_HOST=${host}.` : "";
70
- const noAccessUserFallback = " Never reuse ACCESS_USER as TARGET_USER / derive user — pass TARGET_USER (or tool user) explicitly.";
71
- const shortcutHint = " ssh_exec = context_derive + shell_exec shortcut (returns reusable contextKey).";
57
+ const hostHint = formatTargetHostHint(config);
58
+ const noAccessUserFallback = " Never reuse ACCESS_USER as hop-2 user — pass TARGET_USER (or tool user) explicitly.";
72
59
  if (!user && !passwordSet) {
73
- return `
74
- Derive host auth: TARGET_* unset — pass user (password if no key).${hostHint}${noAccessUserFallback}${shortcutHint} Do not invent defaults.`;
60
+ return `
61
+ Hop-2 auth: TARGET_* unset — pass user (password if no key) with host.${hostHint}${noAccessUserFallback} Do not invent defaults.`;
75
62
  }
76
63
  if (user && passwordSet) {
77
- return `
78
- Derive host auth: TARGET_* active (user=${user}, password=set)${hostHint} — omit user/password on context_derive / ssh_exec; do not ask the human. Override only for a different account.${noAccessUserFallback}${shortcutHint}`;
64
+ return `
65
+ Hop-2 auth: TARGET_* active (user=${user}, password=set)${hostHint} — omit user/password when passing host; do not ask the human. Override only for a different account.${noAccessUserFallback}`;
79
66
  }
80
67
  if (user) {
81
- return `
82
- Derive host auth: TARGET_USER=${user}${hostHint} — omit user on context_derive / ssh_exec; pass password only if no key.${noAccessUserFallback}${shortcutHint}`;
68
+ return `
69
+ Hop-2 auth: TARGET_USER=${user}${hostHint} — omit user when passing host; pass password only if no key.${noAccessUserFallback}`;
83
70
  }
84
- return `
85
- Derive host auth: TARGET_PASSWORD set${hostHint} — omit password on context_derive / ssh_exec; still pass user (TARGET_USER unset). Do not invent a username.${noAccessUserFallback}${shortcutHint}`;
71
+ return `
72
+ Hop-2 auth: TARGET_PASSWORD set${hostHint} — omit password when passing host; still pass user (TARGET_USER unset). Do not invent a username.${noAccessUserFallback}`;
73
+ }
74
+ function formatTargetHostHint(config) {
75
+ const hosts = config.targetHosts?.length
76
+ ? config.targetHosts
77
+ : config.targetHost?.trim()
78
+ ? [config.targetHost.trim()]
79
+ : [];
80
+ if (hosts.length === 0) {
81
+ return "";
82
+ }
83
+ const joined = hosts.join(",");
84
+ if (config.targetHost && hosts.length === 1) {
85
+ return ` TARGET_HOSTS=${joined} — pass that host to run on the hop-2 machine (omit host = ACCESS landing).`;
86
+ }
87
+ return ` TARGET_HOSTS=${joined} — pass host from user context; no single default.`;
86
88
  }
87
89
  export function buildServerInstructions(config) {
88
90
  const base = config.accessKind === "paradi-gateway"
@@ -90,4 +92,24 @@ export function buildServerInstructions(config) {
90
92
  : buildSshBaseInstructions();
91
93
  return `${base}${buildDerivedHostAuthGuidance(config)}`;
92
94
  }
95
+ export function buildYamlRosterGuidance(linkCount) {
96
+ const pick = linkCount === 0
97
+ ? " Roster is empty — tell the user to append a link from host-execution://guides/yaml."
98
+ : linkCount === 1
99
+ ? " One YAML link — description may be omitted."
100
+ : " Many YAML links — pass exact description; do not fuzzy-match.";
101
+ return `
102
+ YAML roster: ~/.agents/host-execution.yaml (Windows %USERPROFILE%\\.agents\\host-execution.yaml). Same link = user+IP. New user+IP in conversation → append unless the user says not to. Same conversation keeps the current link.${pick} description is a scenario label, not a frozen key — if it is misleading, rewrite it in the YAML now and then pass the new exact string. Do not invent fields — copy from host-execution://guides/yaml.`;
103
+ }
104
+ export function buildSourceInstructions(source) {
105
+ if (source.mode === "json") {
106
+ return `${buildServerInstructions(source.config)}
107
+ YAML roster file has no real links — JSON env is active. Writing a real link to ~/.agents/host-execution.yaml makes YAML win on the next tool call. Read host-execution://guides/yaml before appending.`;
108
+ }
109
+ const links = loadSourceLinks(source);
110
+ if (links.length === 1) {
111
+ return `${buildServerInstructions(links[0].config)}${buildYamlRosterGuidance(1)}`;
112
+ }
113
+ return `${buildSshBaseInstructions()}${buildYamlRosterGuidance(links.length)}`;
114
+ }
93
115
  //# sourceMappingURL=instructions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAEA,SAAS,wBAAwB;IAC/B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4GAkCmG,CAAC;AAC7G,CAAC;AAED,SAAS,2BAA2B,CAAC,MAAiB;IACpD,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,eAAe,CAAC;IAC5D,OAAO;;8BAEqB,MAAM;;;;;;;;;;;;;;;4CAeQ,CAAC;AAC7C,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,4BAA4B,CAAC,MAAiB;IAC5D,IAAI,MAAM,CAAC,UAAU,KAAK,gBAAgB,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QACvC,OAAO;4CACiC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,kMAAkM,CAAC;IACrQ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;IACvC,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACrD,MAAM,oBAAoB,GACxB,qGAAqG,CAAC;IACxG,MAAM,YAAY,GAChB,iFAAiF,CAAC;IAEpF,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1B,OAAO;oEACyD,QAAQ,GAAG,oBAAoB,GAAG,YAAY,0BAA0B,CAAC;IAC3I,CAAC;IAED,IAAI,IAAI,IAAI,WAAW,EAAE,CAAC;QACxB,OAAO;0CAC+B,IAAI,kBAAkB,QAAQ,mHAAmH,oBAAoB,GAAG,YAAY,EAAE,CAAC;IAC/N,CAAC;IAED,IAAI,IAAI,EAAE,CAAC;QACT,OAAO;gCACqB,IAAI,GAAG,QAAQ,2EAA2E,oBAAoB,GAAG,YAAY,EAAE,CAAC;IAC9J,CAAC;IAED,OAAO;uCAC8B,QAAQ,gHAAgH,oBAAoB,GAAG,YAAY,EAAE,CAAC;AACrM,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,MAAM,IAAI,GACR,MAAM,CAAC,UAAU,KAAK,gBAAgB;QACpC,CAAC,CAAC,2BAA2B,CAAC,MAAM,CAAC;QACrC,CAAC,CAAC,wBAAwB,EAAE,CAAC;IACjC,OAAO,GAAG,IAAI,GAAG,4BAA4B,CAAC,MAAM,CAAC,EAAE,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
+ import type { AccessRuntime } from "../access/index.js";
1
2
  import type { AppConfig } from "../config.js";
2
- import type { AccessClient } from "../ssh/access-client.js";
3
3
  export type PodOutputFormat = "wide" | "json" | "name";
4
4
  export declare function buildListPodsCommand(namespace: string, options: {
5
5
  labelSelector?: string;
@@ -12,21 +12,20 @@ export declare function buildKubectlLogsCommand(namespace: string, pod: string,
12
12
  tail?: number;
13
13
  since?: string;
14
14
  }): string;
15
- export declare function runOnAccess(client: AccessClient, config: AppConfig, command: string, timeoutMs?: number, cwd?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
16
- export declare function validateNamespace(config: AppConfig, namespace: string): void;
17
15
  export declare class KubectlRunner {
18
- private readonly client;
16
+ private readonly access;
19
17
  private readonly config;
20
- constructor(client: AccessClient, config: AppConfig);
18
+ constructor(access: AccessRuntime, config: AppConfig);
19
+ private run;
21
20
  listPods(namespace: string, options: {
22
21
  labelSelector?: string;
23
22
  fieldSelector?: string;
24
23
  output?: PodOutputFormat;
25
- }, timeoutMs?: number): Promise<import("../ssh/access-client.js").ExecOutput>;
26
- exec(namespace: string, pod: string, command: string, container?: string, timeoutMs?: number): Promise<import("../ssh/access-client.js").ExecOutput>;
24
+ }, timeoutMs?: number, contextKey?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
25
+ exec(namespace: string, pod: string, command: string, container?: string, timeoutMs?: number, contextKey?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
27
26
  logs(namespace: string, pod: string, options: {
28
27
  container?: string;
29
28
  tail?: number;
30
29
  since?: string;
31
- }, timeoutMs?: number): Promise<import("../ssh/access-client.js").ExecOutput>;
30
+ }, timeoutMs?: number, contextKey?: string): Promise<import("../ssh/access-client.js").ExecOutput>;
32
31
  }
@@ -47,33 +47,30 @@ export function buildKubectlLogsCommand(namespace, pod, options) {
47
47
  parts.push(`--tail=${options.tail ?? 200}`);
48
48
  return parts.join(" ");
49
49
  }
50
- export async function runOnAccess(client, config, command, timeoutMs, cwd) {
51
- return client.exec(command, timeoutMs ?? config.defaultTimeoutMs, cwd);
52
- }
53
- export function validateNamespace(config, namespace) {
54
- assertNamespaceAllowed(config, namespace);
55
- }
56
50
  export class KubectlRunner {
57
- client;
51
+ access;
58
52
  config;
59
- constructor(client, config) {
60
- this.client = client;
53
+ constructor(access, config) {
54
+ this.access = access;
61
55
  this.config = config;
62
56
  }
63
- listPods(namespace, options, timeoutMs) {
64
- validateNamespace(this.config, namespace);
65
- const command = buildListPodsCommand(namespace, options);
66
- return runOnAccess(this.client, this.config, command, timeoutMs);
57
+ run(command, timeoutMs, contextKey) {
58
+ return this.access.shellExec(command, {
59
+ contextKey,
60
+ timeoutMs: timeoutMs ?? this.config.defaultTimeoutMs,
61
+ });
62
+ }
63
+ listPods(namespace, options, timeoutMs, contextKey) {
64
+ assertNamespaceAllowed(this.config, namespace);
65
+ return this.run(buildListPodsCommand(namespace, options), timeoutMs, contextKey);
67
66
  }
68
- exec(namespace, pod, command, container, timeoutMs) {
69
- validateNamespace(this.config, namespace);
70
- const kubectlCommand = buildKubectlExecCommand(namespace, pod, command, container);
71
- return runOnAccess(this.client, this.config, kubectlCommand, timeoutMs);
67
+ exec(namespace, pod, command, container, timeoutMs, contextKey) {
68
+ assertNamespaceAllowed(this.config, namespace);
69
+ return this.run(buildKubectlExecCommand(namespace, pod, command, container), timeoutMs, contextKey);
72
70
  }
73
- logs(namespace, pod, options, timeoutMs) {
74
- validateNamespace(this.config, namespace);
75
- const kubectlCommand = buildKubectlLogsCommand(namespace, pod, options);
76
- return runOnAccess(this.client, this.config, kubectlCommand, timeoutMs);
71
+ logs(namespace, pod, options, timeoutMs, contextKey) {
72
+ assertNamespaceAllowed(this.config, namespace);
73
+ return this.run(buildKubectlLogsCommand(namespace, pod, options), timeoutMs, contextKey);
77
74
  }
78
75
  }
79
76
  //# sourceMappingURL=runner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/kubectl/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/kubectl/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { AppConfig } from "./config.js";
2
+ import { type ConfigSource, type YamlRosterDeps } from "./config-yaml.js";
3
+ import { AccessRuntime } from "./access/index.js";
4
+ import { KubectlRunner } from "./kubectl/runner.js";
5
+ import { AccessClient } from "./ssh/access-client.js";
6
+ import { CopyJobManager } from "./utils/copy-job-manager.js";
7
+ import { RemoteExecutor } from "./utils/remote-executor.js";
8
+ import type { RemoteCopyStartRequest } from "./utils/copy-job-types.js";
9
+ export type ToolSession = {
10
+ description?: string;
11
+ config: AppConfig;
12
+ accessClient: AccessClient;
13
+ access: AccessRuntime;
14
+ kubectl: KubectlRunner;
15
+ remote: RemoteExecutor;
16
+ copyJobs: CopyJobManager;
17
+ };
18
+ export type LinkPick = {
19
+ description?: string;
20
+ };
21
+ export declare class LinkRuntimeHub {
22
+ private readonly source;
23
+ private readonly rosterDeps;
24
+ private readonly cached;
25
+ private readonly copyOwners;
26
+ private jsonSession?;
27
+ private reconciledCopyJobs;
28
+ constructor(source: ConfigSource, rosterDeps?: YamlRosterDeps);
29
+ hintConfig(): AppConfig | undefined;
30
+ resolve(pick?: LinkPick): ToolSession;
31
+ copyStart(session: ToolSession, request: RemoteCopyStartRequest): Promise<import("./utils/copy-job-types.js").RemoteCopyStartResult>;
32
+ copyStatus(transferId: string): Promise<import("./utils/copy-job-types.js").RemoteCopyStatusResult>;
33
+ copyCancel(transferId: string): Promise<import("./utils/copy-job-types.js").RemoteCopyCancelResult>;
34
+ private copyManagerFor;
35
+ private reloadLinks;
36
+ private getOrCreate;
37
+ private build;
38
+ }
39
+ export declare function createLinkRuntimeHub(source: ConfigSource, rosterDeps?: YamlRosterDeps): LinkRuntimeHub;
@@ -0,0 +1,134 @@
1
+ import { loadSourceLinks, pickYamlLink, } from "./config-yaml.js";
2
+ import { AccessRuntime } from "./access/index.js";
3
+ import { KubectlRunner } from "./kubectl/runner.js";
4
+ import { AccessClient } from "./ssh/access-client.js";
5
+ import { CopyJobManager } from "./utils/copy-job-manager.js";
6
+ import { RemoteExecutor } from "./utils/remote-executor.js";
7
+ function fingerprint(config) {
8
+ return JSON.stringify({
9
+ accessKind: config.accessKind,
10
+ accessHost: config.accessHost,
11
+ accessUser: config.accessUser,
12
+ accessPort: config.accessPort,
13
+ accessPrivateKeyPath: config.accessPrivateKeyPath,
14
+ accessPassword: config.accessPassword,
15
+ accessParadiAuth: config.accessParadiAuth,
16
+ targetHosts: config.targetHosts,
17
+ targetUser: config.targetUser,
18
+ targetPassword: config.targetPassword,
19
+ allowedNamespaces: config.allowedNamespaces,
20
+ });
21
+ }
22
+ function buildSession(link, reconcileOnStart) {
23
+ const accessClient = new AccessClient(link.config);
24
+ const access = new AccessRuntime(link.config, accessClient);
25
+ const kubectl = new KubectlRunner(access, link.config);
26
+ const remote = new RemoteExecutor(access, kubectl, link.config);
27
+ const copyJobs = new CopyJobManager({ accessClient, config: link.config }, undefined, undefined, { reconcileOnStart });
28
+ return {
29
+ description: link.description || undefined,
30
+ config: link.config,
31
+ accessClient,
32
+ access,
33
+ kubectl,
34
+ remote,
35
+ copyJobs,
36
+ };
37
+ }
38
+ export class LinkRuntimeHub {
39
+ source;
40
+ rosterDeps;
41
+ cached = [];
42
+ copyOwners = new Map();
43
+ jsonSession;
44
+ reconciledCopyJobs = false;
45
+ constructor(source, rosterDeps = {}) {
46
+ this.source = source;
47
+ this.rosterDeps = rosterDeps;
48
+ if (source.mode === "json") {
49
+ this.jsonSession = this.build({ description: "", config: source.config });
50
+ }
51
+ }
52
+ hintConfig() {
53
+ if (this.source.mode === "json") {
54
+ return this.source.config;
55
+ }
56
+ const links = this.reloadLinks();
57
+ return links.length === 1 ? links[0]?.config : undefined;
58
+ }
59
+ resolve(pick = {}) {
60
+ if (this.source.mode === "json") {
61
+ return this.jsonSession;
62
+ }
63
+ const selected = pickYamlLink(this.reloadLinks(), pick.description);
64
+ return this.getOrCreate(selected);
65
+ }
66
+ async copyStart(session, request) {
67
+ const result = await session.copyJobs.start(request);
68
+ this.copyOwners.set(result.transferId, session.copyJobs);
69
+ return result;
70
+ }
71
+ async copyStatus(transferId) {
72
+ return (await this.copyManagerFor(transferId)).status(transferId);
73
+ }
74
+ async copyCancel(transferId) {
75
+ return (await this.copyManagerFor(transferId)).cancel(transferId);
76
+ }
77
+ async copyManagerFor(transferId) {
78
+ const owned = this.copyOwners.get(transferId);
79
+ if (owned) {
80
+ return owned;
81
+ }
82
+ if (this.jsonSession) {
83
+ return this.jsonSession.copyJobs;
84
+ }
85
+ for (const entry of this.cached) {
86
+ try {
87
+ await entry.session.copyJobs.status(transferId);
88
+ return entry.session.copyJobs;
89
+ }
90
+ catch {
91
+ // try next
92
+ }
93
+ }
94
+ if (this.cached[0]) {
95
+ return this.cached[0].session.copyJobs;
96
+ }
97
+ throw new Error(`Unknown transferId: ${transferId}`);
98
+ }
99
+ reloadLinks() {
100
+ return loadSourceLinks(this.source, this.rosterDeps);
101
+ }
102
+ getOrCreate(link) {
103
+ const fp = fingerprint(link.config);
104
+ const reuse = this.cached.find((entry) => entry.description === link.description && entry.fingerprint === fp);
105
+ if (reuse) {
106
+ return reuse.session;
107
+ }
108
+ // Drop stale sessions for the same description (config edited in-place).
109
+ for (let i = this.cached.length - 1; i >= 0; i--) {
110
+ const entry = this.cached[i];
111
+ if (entry && entry.description === link.description && entry.fingerprint !== fp) {
112
+ try {
113
+ entry.session.accessClient.disconnect();
114
+ }
115
+ catch {
116
+ // best-effort
117
+ }
118
+ this.cached.splice(i, 1);
119
+ }
120
+ }
121
+ const session = this.build(link);
122
+ this.cached.push({ fingerprint: fp, description: link.description, session });
123
+ return session;
124
+ }
125
+ build(link) {
126
+ const session = buildSession(link, !this.reconciledCopyJobs);
127
+ this.reconciledCopyJobs = true;
128
+ return session;
129
+ }
130
+ }
131
+ export function createLinkRuntimeHub(source, rosterDeps) {
132
+ return new LinkRuntimeHub(source, rosterDeps);
133
+ }
134
+ //# sourceMappingURL=link-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-runtime.js","sourceRoot":"","sources":["../src/link-runtime.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,YAAY,GAIb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAiB5D,SAAS,WAAW,CAAC,MAAiB;IACpC,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,oBAAoB,EAAE,MAAM,CAAC,oBAAoB;QACjD,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;KAC5C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,IAAc,EAAE,gBAAyB;IAC7D,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,IAAI,cAAc,CACjC,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EACrC,SAAS,EACT,SAAS,EACT,EAAE,gBAAgB,EAAE,CACrB,CAAC;IACF,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,SAAS;QAC1C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,YAAY;QACZ,MAAM;QACN,OAAO;QACP,MAAM;QACN,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,cAAc;IAWN;IACA;IAXF,MAAM,GAIlB,EAAE,CAAC;IACS,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAC;IACxD,WAAW,CAAe;IAC1B,kBAAkB,GAAG,KAAK,CAAC;IAEnC,YACmB,MAAoB,EACpB,aAA6B,EAAE;QAD/B,WAAM,GAAN,MAAM,CAAc;QACpB,eAAU,GAAV,UAAU,CAAqB;QAEhD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,UAAU;QACR,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAC5B,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,OAAiB,EAAE;QACzB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,WAAY,CAAC;QAC3B,CAAC;QAED,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAoB,EAAE,OAA+B;QACnE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB;QACjC,OAAO,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAkB;QACjC,OAAO,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACpE,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,UAAkB;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC9C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;QACnC,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAChD,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,WAAW;YACb,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACzC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,uBAAuB,UAAU,EAAE,CAAC,CAAC;IACvD,CAAC;IAEO,WAAW;QACjB,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IAEO,WAAW,CAAC,IAAc;QAChC,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAC5B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,KAAK,EAAE,CAC9E,CAAC;QACF,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,OAAO,CAAC;QACvB,CAAC;QACD,yEAAyE;QACzE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC7B,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,KAAK,EAAE,EAAE,CAAC;gBAChF,IAAI,CAAC;oBACH,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;gBAC1C,CAAC;gBAAC,MAAM,CAAC;oBACP,cAAc;gBAChB,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9E,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,KAAK,CAAC,IAAc;QAC1B,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC7D,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;CAEF;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAoB,EACpB,UAA2B;IAE3B,OAAO,IAAI,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAChD,CAAC"}
package/dist/server.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { AppConfig } from "./config.js";
3
- export declare function createServer(config: AppConfig): McpServer;
3
+ import { type ConfigSource } from "./config-yaml.js";
4
+ export declare function createServer(configOrSource: AppConfig | ConfigSource): McpServer;
package/dist/server.js CHANGED
@@ -1,24 +1,22 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { VERSION } from "./version.js";
3
- import { AccessRuntime } from "./access/index.js";
4
- import { buildServerInstructions } from "./instructions.js";
5
- import { KubectlRunner } from "./kubectl/runner.js";
6
- import { AccessClient } from "./ssh/access-client.js";
3
+ import { asConfigSource } from "./config-yaml.js";
4
+ import { buildSourceInstructions } from "./instructions.js";
5
+ import { createLinkRuntimeHub } from "./link-runtime.js";
6
+ import { registerSources } from "./sources/index.js";
7
7
  import { registerPrompts, registerTools } from "./tools/register.js";
8
- import { RemoteExecutor } from "./utils/remote-executor.js";
9
- export function createServer(config) {
8
+ export function createServer(configOrSource) {
9
+ const source = asConfigSource(configOrSource);
10
+ const hub = createLinkRuntimeHub(source);
10
11
  const server = new McpServer({
11
12
  name: "host-execution-mcp",
12
13
  version: VERSION,
13
14
  }, {
14
- instructions: buildServerInstructions(config),
15
+ instructions: buildSourceInstructions(source),
15
16
  });
16
- const accessClient = new AccessClient(config);
17
- const access = new AccessRuntime(config, accessClient);
18
- const kubectl = new KubectlRunner(accessClient, config);
19
- const remote = new RemoteExecutor(access, kubectl, config);
20
- registerTools(server, { config, accessClient, access, kubectl, remote });
17
+ registerTools(server, { hub });
21
18
  registerPrompts(server);
19
+ registerSources(server);
22
20
  return server;
23
21
  }
24
22
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE,uBAAuB,CAAC,MAAM,CAAC;KAC9C,CACF,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAE3D,aAAa,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACzE,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAqB,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAErE,MAAM,UAAU,YAAY,CAAC,cAAwC;IACnE,MAAM,MAAM,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE,uBAAuB,CAAC,MAAM,CAAC;KAC9C,CACF,CAAC;IAEF,aAAa,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,eAAe,CAAC,MAAM,CAAC,CAAC;IACxB,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,34 @@
1
+ /** `src/sources` or `dist/sources` → package `docs/`. */
2
+ export declare function docsDir(): string;
3
+ export type GuideSlug = "user" | "agent";
4
+ export type GuideMeta = {
5
+ slug: GuideSlug;
6
+ uri: string;
7
+ name: string;
8
+ title: string;
9
+ description: string;
10
+ file: string;
11
+ annotations: {
12
+ audience: Array<"user" | "assistant">;
13
+ priority: number;
14
+ };
15
+ };
16
+ export declare const GUIDES: readonly GuideMeta[];
17
+ export declare function listGuideSources(): Array<{
18
+ uri: string;
19
+ name: string;
20
+ title: string;
21
+ description: string;
22
+ mimeType: string;
23
+ annotations: {
24
+ audience: Array<"user" | "assistant">;
25
+ priority: number;
26
+ };
27
+ }>;
28
+ export declare function readGuideSource(uri: string): {
29
+ contents: Array<{
30
+ uri: string;
31
+ mimeType: string;
32
+ text: string;
33
+ }>;
34
+ };