@scotthuang/agent-knock-knock 0.12.15 → 0.12.16

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 (64) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +5 -1
  3. package/dist/src/cli-core.js +61 -2
  4. package/dist/src/cli-core.js.map +1 -1
  5. package/dist/src/command-json-callback-transport.d.ts +38 -0
  6. package/dist/src/command-json-callback-transport.js +298 -0
  7. package/dist/src/command-json-callback-transport.js.map +1 -0
  8. package/dist/src/host-adapter.d.ts +52 -0
  9. package/dist/src/host-adapter.js +123 -0
  10. package/dist/src/host-adapter.js.map +1 -0
  11. package/dist/src/host-bridge-mcp.d.ts +22 -0
  12. package/dist/src/host-bridge-mcp.js +145 -0
  13. package/dist/src/host-bridge-mcp.js.map +1 -0
  14. package/dist/src/host-bridge-tools.d.ts +61 -0
  15. package/dist/src/host-bridge-tools.js +130 -0
  16. package/dist/src/host-bridge-tools.js.map +1 -0
  17. package/dist/src/host-bridge.d.ts +28 -0
  18. package/dist/src/host-bridge.js +156 -0
  19. package/dist/src/host-bridge.js.map +1 -0
  20. package/dist/src/host-lifecycle-service.d.ts +39 -0
  21. package/dist/src/host-lifecycle-service.js +101 -0
  22. package/dist/src/host-lifecycle-service.js.map +1 -0
  23. package/dist/src/host-profile-callback-transport.d.ts +14 -0
  24. package/dist/src/host-profile-callback-transport.js +70 -0
  25. package/dist/src/host-profile-callback-transport.js.map +1 -0
  26. package/dist/src/host-profile-cli-adapter.d.ts +8 -0
  27. package/dist/src/host-profile-cli-adapter.js +169 -0
  28. package/dist/src/host-profile-cli-adapter.js.map +1 -0
  29. package/dist/src/host-profile-runtime.d.ts +55 -0
  30. package/dist/src/host-profile-runtime.js +152 -0
  31. package/dist/src/host-profile-runtime.js.map +1 -0
  32. package/dist/src/host-profile.d.ts +121 -0
  33. package/dist/src/host-profile.js +723 -0
  34. package/dist/src/host-profile.js.map +1 -0
  35. package/dist/src/native-thread-resume-snapshot.js +1 -1
  36. package/dist/src/native-thread-resume-snapshot.js.map +1 -1
  37. package/dist/src/openclaw-plugin-command-adapter.d.ts +13 -0
  38. package/dist/src/openclaw-plugin-command-adapter.js +125 -47
  39. package/dist/src/openclaw-plugin-command-adapter.js.map +1 -1
  40. package/dist/src/openclaw-plugin-helpers.js +1 -1
  41. package/dist/src/openclaw-plugin-helpers.js.map +1 -1
  42. package/dist/src/openclaw-plugin-supervisor.d.ts +1 -1
  43. package/dist/src/openclaw-plugin-supervisor.js +44 -72
  44. package/dist/src/openclaw-plugin-supervisor.js.map +1 -1
  45. package/dist/src/terminal-command-cli-adapter.js +4 -4
  46. package/dist/src/terminal-command-cli-adapter.js.map +1 -1
  47. package/dist/src/terminal-dispatch-presenter.js +1 -1
  48. package/dist/src/terminal-dispatch-presenter.js.map +1 -1
  49. package/dist/src/terminal-watch-callback-cli-adapter.d.ts +2 -1
  50. package/dist/src/terminal-watch-callback-cli-adapter.js +4 -3
  51. package/dist/src/terminal-watch-callback-cli-adapter.js.map +1 -1
  52. package/dist/src/terminal-watch-cli-adapter.d.ts +4 -0
  53. package/dist/src/terminal-watch-cli-adapter.js +33 -3
  54. package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
  55. package/dist/src/terminal-watch-service.d.ts +5 -0
  56. package/dist/src/terminal-watch-service.js +6 -1
  57. package/dist/src/terminal-watch-service.js.map +1 -1
  58. package/dist/src/terminal-watch-store.d.ts +2 -0
  59. package/dist/src/terminal-watch-store.js +13 -0
  60. package/dist/src/terminal-watch-store.js.map +1 -1
  61. package/docs/host-bridge-profiles.md +325 -0
  62. package/examples/host-profiles/command-json-starter.json +62 -0
  63. package/package.json +30 -2
  64. package/schemas/host-profile-v1.schema.json +266 -0
@@ -0,0 +1,298 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { parseHostProfileV1 } from "./host-profile.js";
3
+ import { callbackEnvelopeMatchesRoute, parseCallbackRoute } from "./callback-transport.js";
4
+ /*
5
+ * Keep the callback driver behind the canonical transport port. Profile
6
+ * parsing owns untrusted-document validation and is deliberately re-applied
7
+ * here so programmatic callers cannot bypass the same fail-closed contract.
8
+ */
9
+ export const COMMAND_JSON_CALLBACK_TRANSPORT_KIND = "command_json_v1";
10
+ class CommandJsonAcknowledgementError extends Error {
11
+ errorCode;
12
+ constructor(errorCode, message) {
13
+ super(message);
14
+ this.name = "CommandJsonAcknowledgementError";
15
+ this.errorCode = errorCode;
16
+ }
17
+ }
18
+ /**
19
+ * Deliver canonical AKK callback envelopes through one administrator-selected
20
+ * command Profile. The Profile and trusted controller identity are captured at
21
+ * construction time and cannot be supplied by a model-facing delivery call.
22
+ */
23
+ export function createCommandJsonCallbackTransport(options) {
24
+ const profile = parseHostProfileV1(options.profile, { source: "built_in" });
25
+ const profileId = profile.id;
26
+ const profileRevision = profile.revision;
27
+ const controllerSessionId = requiredNonBlank(options.controllerSessionId, "controller session id");
28
+ const callback = Object.freeze({
29
+ executable: profile.callback.executable,
30
+ arguments: profile.callback.arguments,
31
+ stdin: profile.callback.stdin,
32
+ environmentVariables: profile.callback.environment.allow,
33
+ timeoutMs: profile.callback.timeoutMs,
34
+ maxOutputBytes: profile.callback.maxOutputBytes,
35
+ acknowledgement: profile.callback.acknowledgement
36
+ });
37
+ const now = options.now ?? (() => new Date());
38
+ const environment = options.environment ?? (() => process.env);
39
+ const runSync = options.spawnSync ??
40
+ ((executable, arguments_, spawnOptions) => spawnSync(executable, arguments_, spawnOptions));
41
+ return Object.freeze({
42
+ kind: COMMAND_JSON_CALLBACK_TRANSPORT_KIND,
43
+ deliver(input) {
44
+ let route;
45
+ try {
46
+ route = parseCallbackRoute(input.route);
47
+ }
48
+ catch {
49
+ return permanentFailure("command_json_callback_route_invalid");
50
+ }
51
+ if (route.transport !== COMMAND_JSON_CALLBACK_TRANSPORT_KIND) {
52
+ return permanentFailure("unsupported_callback_transport");
53
+ }
54
+ if (route.profile_id !== profileId) {
55
+ return permanentFailure("command_json_callback_profile_mismatch");
56
+ }
57
+ if (route.profile_revision !== profileRevision) {
58
+ return permanentFailure("command_json_callback_profile_revision_mismatch");
59
+ }
60
+ if (route.controller_session_id !== controllerSessionId) {
61
+ return permanentFailure("command_json_controller_session_mismatch");
62
+ }
63
+ if (!callbackEnvelopeMatchesRoute(input.envelope, route)) {
64
+ return permanentFailure("callback_envelope_route_mismatch");
65
+ }
66
+ if (!Number.isSafeInteger(input.attempt.number) ||
67
+ input.attempt.number < 1 ||
68
+ !nonBlank(input.attempt.id)) {
69
+ return permanentFailure("command_json_callback_attempt_invalid");
70
+ }
71
+ let arguments_;
72
+ let stdin;
73
+ let env;
74
+ try {
75
+ const values = interpolationValues(input.envelope, controllerSessionId);
76
+ arguments_ = callback.arguments.map((argument) => interpolate(argument, values, "argument"));
77
+ stdin = interpolate(callback.stdin, values, "stdin");
78
+ env = filteredEnvironment(environment(), callback.environmentVariables);
79
+ }
80
+ catch {
81
+ return permanentFailure("command_json_callback_configuration_error");
82
+ }
83
+ let result;
84
+ try {
85
+ result = runSync(callback.executable, arguments_, {
86
+ encoding: "utf8",
87
+ env,
88
+ input: stdin,
89
+ killSignal: "SIGKILL",
90
+ maxBuffer: callback.maxOutputBytes,
91
+ shell: false,
92
+ timeout: callback.timeoutMs,
93
+ windowsHide: true
94
+ });
95
+ }
96
+ catch (error) {
97
+ return processExecutionFailure(error, now());
98
+ }
99
+ // A spawn error means the process did not complete inside the bounded
100
+ // execution contract. In particular, stdout emitted before a timeout or
101
+ // output-limit kill cannot prove that the Host finished processing the
102
+ // callback, even when it happens to contain an exact accepted payload.
103
+ if (result.error) {
104
+ return processExecutionFailure(result.error, now());
105
+ }
106
+ const acknowledgement = acknowledgementOutcome({
107
+ callback,
108
+ envelope: input.envelope,
109
+ result,
110
+ now: now()
111
+ });
112
+ if (acknowledgement) {
113
+ if (acknowledgement.disposition === "accepted") {
114
+ try {
115
+ input.reportCheckpoint?.(acknowledgement);
116
+ }
117
+ catch {
118
+ // The exact command acknowledgement remains authoritative even when
119
+ // the caller cannot persist the optional early checkpoint here.
120
+ }
121
+ }
122
+ return acknowledgement;
123
+ }
124
+ return uncertainFailure(result.status === 0
125
+ ? "command_json_callback_acknowledgement_invalid"
126
+ : "command_json_callback_exit_unacknowledged", now());
127
+ }
128
+ });
129
+ }
130
+ function acknowledgementOutcome(input) {
131
+ const stdout = typeof input.result.stdout === "string"
132
+ ? input.result.stdout.trim()
133
+ : "";
134
+ if (!stdout)
135
+ return undefined;
136
+ let acknowledgement;
137
+ try {
138
+ acknowledgement = JSON.parse(stdout);
139
+ }
140
+ catch {
141
+ return undefined;
142
+ }
143
+ try {
144
+ const definition = input.callback.acknowledgement;
145
+ const hostDisposition = requiredPointerString(acknowledgement, definition.disposition, "disposition");
146
+ const disposition = Object.hasOwn(definition.disposition.mapping, hostDisposition)
147
+ ? definition.disposition.mapping[hostDisposition]
148
+ : undefined;
149
+ if (!disposition) {
150
+ throw new CommandJsonAcknowledgementError("command_json_callback_acknowledgement_disposition_unknown", "callback acknowledgement disposition is not mapped");
151
+ }
152
+ const deliveryId = requiredPointerString(acknowledgement, definition.acknowledgedDeliveryId, "acknowledged delivery id");
153
+ const messageId = requiredPointerString(acknowledgement, definition.acknowledgedMessageId, "acknowledged message id");
154
+ if (deliveryId !== input.envelope.delivery_id ||
155
+ messageId !== input.envelope.event.id) {
156
+ throw new CommandJsonAcknowledgementError("command_json_callback_acknowledgement_identity_mismatch", "callback acknowledgement does not bind the exact delivery and message");
157
+ }
158
+ if (disposition === "accepted") {
159
+ const acceptanceId = requiredPointerString(acknowledgement, definition.acceptanceId, "acceptance id");
160
+ return {
161
+ disposition,
162
+ accepted_at: input.now.toISOString(),
163
+ acceptance_id: acceptanceId,
164
+ evidence: processEvidence(input.result)
165
+ };
166
+ }
167
+ const errorCode = defaultOutcomeErrorCode(disposition);
168
+ if (disposition === "uncertain") {
169
+ return {
170
+ disposition,
171
+ error_code: errorCode,
172
+ observed_at: input.now.toISOString(),
173
+ evidence: processEvidence(input.result)
174
+ };
175
+ }
176
+ return {
177
+ disposition,
178
+ error_code: errorCode,
179
+ evidence: processEvidence(input.result)
180
+ };
181
+ }
182
+ catch (error) {
183
+ const errorCode = error instanceof CommandJsonAcknowledgementError
184
+ ? error.errorCode
185
+ : "command_json_callback_acknowledgement_invalid";
186
+ return uncertainFailure(errorCode, input.now);
187
+ }
188
+ }
189
+ function processEvidence(result) {
190
+ return {
191
+ transport: COMMAND_JSON_CALLBACK_TRANSPORT_KIND,
192
+ process_status: result.status,
193
+ ...(result.signal ? { process_signal: result.signal } : {})
194
+ };
195
+ }
196
+ function processExecutionFailure(error, observedAt) {
197
+ const code = errorCode(error);
198
+ if (["ENOENT", "ENOTDIR", "EACCES", "EPERM"].includes(code ?? "")) {
199
+ return permanentFailure("command_json_callback_executable_unavailable");
200
+ }
201
+ return uncertainFailure(code === "ETIMEDOUT" || code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ||
202
+ code === "ENOBUFS"
203
+ ? "command_json_callback_execution_limit_uncertain"
204
+ : "command_json_callback_execution_uncertain", observedAt);
205
+ }
206
+ function interpolationValues(envelope, controllerSessionId) {
207
+ const values = new Map();
208
+ const add = (name, value, sensitiveBody = false) => {
209
+ if (value !== undefined) {
210
+ values.set(name, { value: String(value), sensitiveBody });
211
+ }
212
+ };
213
+ add("controller.session_id", controllerSessionId);
214
+ add("envelope.delivery_id", envelope.delivery_id);
215
+ add("envelope.idempotency_key", envelope.idempotency_key);
216
+ add("envelope.message_id", envelope.event.id);
217
+ add("envelope.body", envelope.event.body, true);
218
+ return values;
219
+ }
220
+ function interpolate(template, values, destination) {
221
+ let malformed = false;
222
+ const rendered = template.replace(/\$\{([^{}]+)\}/gu, (_match, name) => {
223
+ const resolved = values.get(String(name));
224
+ if (!resolved || (destination === "argument" && resolved.sensitiveBody)) {
225
+ malformed = true;
226
+ return "";
227
+ }
228
+ return resolved.value;
229
+ });
230
+ if (malformed || rendered.includes("${")) {
231
+ throw new Error("command_json_v1 interpolation is unsupported or malformed");
232
+ }
233
+ assertNoNullByte(rendered, `command_json_v1 ${destination}`);
234
+ return rendered;
235
+ }
236
+ function filteredEnvironment(source, allowed) {
237
+ const filtered = Object.create(null);
238
+ for (const name of allowed) {
239
+ if (Object.hasOwn(source, name) && source[name] !== undefined) {
240
+ filtered[name] = source[name];
241
+ }
242
+ }
243
+ return filtered;
244
+ }
245
+ function requiredPointerString(document, definition, label) {
246
+ const value = resolveJsonPointer(document, definition.jsonPointer);
247
+ if (!nonBlank(value)) {
248
+ throw new CommandJsonAcknowledgementError("command_json_callback_acknowledgement_invalid", `callback acknowledgement ${label} must be a non-empty string`);
249
+ }
250
+ return value;
251
+ }
252
+ function resolveJsonPointer(document, pointer) {
253
+ if (pointer === "")
254
+ return document;
255
+ let current = document;
256
+ for (const encoded of pointer.slice(1).split("/")) {
257
+ const token = encoded.replace(/~1/gu, "/").replace(/~0/gu, "~");
258
+ if (current === null ||
259
+ typeof current !== "object" ||
260
+ !Object.hasOwn(current, token)) {
261
+ return undefined;
262
+ }
263
+ current = current[token];
264
+ }
265
+ return current;
266
+ }
267
+ function defaultOutcomeErrorCode(disposition) {
268
+ return `command_json_callback_${disposition}`;
269
+ }
270
+ function permanentFailure(errorCode) {
271
+ return { disposition: "permanent_failure", error_code: errorCode };
272
+ }
273
+ function uncertainFailure(errorCode, observedAt) {
274
+ return {
275
+ disposition: "uncertain",
276
+ error_code: errorCode,
277
+ observed_at: observedAt.toISOString()
278
+ };
279
+ }
280
+ function requiredNonBlank(value, label) {
281
+ if (!nonBlank(value))
282
+ throw new Error(`${label} must be a non-empty string`);
283
+ return value;
284
+ }
285
+ function nonBlank(value) {
286
+ return typeof value === "string" && value.trim().length > 0;
287
+ }
288
+ function assertNoNullByte(value, label) {
289
+ if (value.includes("\0"))
290
+ throw new Error(`${label} contains a null byte`);
291
+ }
292
+ function errorCode(error) {
293
+ if (!error || typeof error !== "object")
294
+ return undefined;
295
+ const value = error.code;
296
+ return typeof value === "string" ? value : undefined;
297
+ }
298
+ //# sourceMappingURL=command-json-callback-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-json-callback-transport.js","sourceRoot":"","sources":["../../src/command-json-callback-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { type HostBridgeCommandResult, type HostBridgeToolContext, type HostBridgeToolLogger, type HostBridgeToolResult } from "./host-bridge-tools.js";
2
+ export type { HostBridgeCommandResult, HostBridgeToolContext, HostBridgeToolLogger, HostBridgeToolResult } from "./host-bridge-tools.js";
3
+ export { createTrustedHostProfileRuntime, hostProfileRelayEnvironment } from "./host-profile-runtime.js";
4
+ export type { CreateTrustedHostProfileRuntimeOptions, TrustedHostProfileRuntimeV1 } from "./host-profile-runtime.js";
5
+ /** Stable relay entrypoint for native Host connector packages. */
6
+ export declare const defaultHostAdapterRelayPath: string;
7
+ export interface HostAdapterControllerContext extends HostBridgeToolContext {
8
+ /** Exact Host-owned controller incarnation; never derive this from text. */
9
+ readonly authority: object;
10
+ }
11
+ export type HostAdapterEnvironmentContext = HostBridgeToolContext;
12
+ export interface HostAdapterToolMetadata {
13
+ readonly name: string;
14
+ readonly description: string;
15
+ readonly inputSchema: Readonly<Record<string, unknown>>;
16
+ }
17
+ export interface HostAdapterCommandMetadata {
18
+ readonly name: string;
19
+ readonly description: string;
20
+ readonly acceptsArgs: boolean;
21
+ }
22
+ export interface HostAdapterLifecycle {
23
+ readonly id: string;
24
+ start(): void;
25
+ stop(): Promise<void>;
26
+ }
27
+ export interface CreateHostAdapterOptions {
28
+ readonly relayPath?: string;
29
+ readonly environmentForContext: (context: HostAdapterEnvironmentContext) => NodeJS.ProcessEnv;
30
+ /** Fixed child environment used by the one Host-owned lifecycle service. */
31
+ readonly lifecycleEnvironment?: NodeJS.ProcessEnv;
32
+ readonly lifecycleIntervalMs?: number;
33
+ readonly pluginConfig?: Readonly<Record<string, unknown>>;
34
+ readonly logger: HostBridgeToolLogger;
35
+ }
36
+ export interface HostAdapter {
37
+ readonly command: HostAdapterCommandMetadata;
38
+ readonly tools: readonly HostAdapterToolMetadata[];
39
+ readonly lifecycle: HostAdapterLifecycle;
40
+ executeCommand(context: HostAdapterControllerContext, args: string, signal?: AbortSignal): Promise<HostBridgeCommandResult>;
41
+ executeTool(context: HostAdapterControllerContext, name: string, toolCallId: string, args: Readonly<Record<string, unknown>>, signal?: AbortSignal): Promise<HostBridgeToolResult>;
42
+ /** Drop private action/snapshot authority when the Host disposes an owner. */
43
+ disposeContext(authority: object): void;
44
+ }
45
+ /**
46
+ * Adapt AKK's established slash command and 16 semantic tools to a native Host.
47
+ *
48
+ * Public metadata is captured exactly once. Executable registries are created
49
+ * lazily per exact Host authority object so private approvals, action offers,
50
+ * resume snapshots, and idempotency identities cannot leak across controllers.
51
+ */
52
+ export declare function createHostAdapter(options: CreateHostAdapterOptions): HostAdapter;
@@ -0,0 +1,123 @@
1
+ import { createHostBridgeToolRegistry } from "./host-bridge-tools.js";
2
+ import { bindOpenClawRelayEnvironment, bindOpenClawRelayPath, defaultOpenClawRelayPath, withHostBridgeInvocationSignal } from "./openclaw-plugin-command-adapter.js";
3
+ import { createMonitorReconciliationService, MONITOR_SUPERVISOR_INTERVAL_MS } from "./openclaw-plugin-supervisor.js";
4
+ export { createTrustedHostProfileRuntime, hostProfileRelayEnvironment } from "./host-profile-runtime.js";
5
+ /** Stable relay entrypoint for native Host connector packages. */
6
+ export const defaultHostAdapterRelayPath = defaultOpenClawRelayPath;
7
+ const METADATA_CONTEXT = Object.freeze({
8
+ sessionKey: "host-adapter:metadata",
9
+ sessionId: "host-adapter:metadata"
10
+ });
11
+ /**
12
+ * Adapt AKK's established slash command and 16 semantic tools to a native Host.
13
+ *
14
+ * Public metadata is captured exactly once. Executable registries are created
15
+ * lazily per exact Host authority object so private approvals, action offers,
16
+ * resume snapshots, and idempotency identities cannot leak across controllers.
17
+ */
18
+ export function createHostAdapter(options) {
19
+ const relayPath = requiredString(options.relayPath ?? defaultHostAdapterRelayPath, "relayPath");
20
+ const pluginConfig = options.pluginConfig ?? {};
21
+ const metadataRegistry = createHostBridgeToolRegistry({
22
+ relayPath,
23
+ relayEnvironment: {},
24
+ pluginConfig,
25
+ logger: options.logger,
26
+ context: METADATA_CONTEXT
27
+ });
28
+ const commandMetadata = immutableMetadataClone({
29
+ name: metadataRegistry.command().name,
30
+ description: metadataRegistry.command().description,
31
+ acceptsArgs: metadataRegistry.command().acceptsArgs
32
+ });
33
+ const toolMetadata = immutableMetadataClone(metadataRegistry.list().map((tool) => ({
34
+ name: tool.name,
35
+ description: tool.description,
36
+ inputSchema: tool.inputSchema
37
+ })));
38
+ const registries = new WeakMap();
39
+ const lifecycleApi = {
40
+ pluginConfig,
41
+ logger: options.logger
42
+ };
43
+ bindOpenClawRelayPath(lifecycleApi, relayPath);
44
+ bindOpenClawRelayEnvironment(lifecycleApi, options.lifecycleEnvironment ?? process.env);
45
+ const lifecycle = createMonitorReconciliationService(lifecycleApi, options.lifecycleIntervalMs ?? MONITOR_SUPERVISOR_INTERVAL_MS);
46
+ const registryFor = (context) => {
47
+ const trusted = trustedControllerContext(context);
48
+ const cached = registries.get(context.authority);
49
+ if (cached) {
50
+ if (cached.context.sessionKey !== trusted.sessionKey ||
51
+ cached.context.sessionId !== trusted.sessionId) {
52
+ throw new Error("Host adapter authority cannot be reused with another controller context");
53
+ }
54
+ return cached.registry;
55
+ }
56
+ const environment = options.environmentForContext(trusted);
57
+ if (!environment || typeof environment !== "object") {
58
+ throw new Error("environmentForContext must return a process environment");
59
+ }
60
+ const registry = createHostBridgeToolRegistry({
61
+ relayPath,
62
+ relayEnvironment: environment,
63
+ pluginConfig,
64
+ logger: options.logger,
65
+ context: trusted
66
+ });
67
+ registries.set(context.authority, { context: trusted, registry });
68
+ return registry;
69
+ };
70
+ return Object.freeze({
71
+ command: commandMetadata,
72
+ tools: toolMetadata,
73
+ lifecycle,
74
+ executeCommand(context, args, signal) {
75
+ return withHostBridgeInvocationSignal(signal, () => registryFor(context).command().execute(args));
76
+ },
77
+ executeTool(context, name, toolCallId, args, signal) {
78
+ return withHostBridgeInvocationSignal(signal, () => registryFor(context).execute(name, toolCallId, args));
79
+ },
80
+ disposeContext(authority) {
81
+ requiredAuthority(authority);
82
+ registries.delete(authority);
83
+ }
84
+ });
85
+ }
86
+ function trustedControllerContext(context) {
87
+ requiredAuthority(context?.authority);
88
+ return Object.freeze({
89
+ sessionKey: requiredString(context?.sessionKey, "context.sessionKey"),
90
+ sessionId: requiredString(context?.sessionId, "context.sessionId")
91
+ });
92
+ }
93
+ function requiredAuthority(value) {
94
+ if (value === null ||
95
+ (typeof value !== "object" && typeof value !== "function")) {
96
+ throw new Error("context.authority must be an exact Host-owned object");
97
+ }
98
+ }
99
+ function requiredString(value, label) {
100
+ if (typeof value !== "string" || value.trim().length === 0) {
101
+ throw new Error(`${label} is required`);
102
+ }
103
+ return value;
104
+ }
105
+ function immutableMetadataClone(value) {
106
+ return deepFreezeMetadata(structuredClone(value));
107
+ }
108
+ function deepFreezeMetadata(value, seen = new WeakSet()) {
109
+ if (value === null ||
110
+ (typeof value !== "object" && typeof value !== "function")) {
111
+ return value;
112
+ }
113
+ const objectValue = value;
114
+ if (seen.has(objectValue)) {
115
+ return value;
116
+ }
117
+ seen.add(objectValue);
118
+ for (const key of Reflect.ownKeys(objectValue)) {
119
+ deepFreezeMetadata(objectValue[key], seen);
120
+ }
121
+ return Object.freeze(value);
122
+ }
123
+ //# sourceMappingURL=host-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-adapter.js","sourceRoot":"","sources":["../../src/host-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import type { HostBridgeToolRegistry } from "./host-bridge-tools.js";
3
+ export declare const HOST_BRIDGE_MCP_SERVER_NAME = "agent-knock-knock-host-bridge";
4
+ export interface CreateHostBridgeMcpServerOptions {
5
+ readonly registry: HostBridgeToolRegistry;
6
+ readonly version: string;
7
+ /** Test seam; production callers receive a fresh identity per Bridge. */
8
+ readonly instanceId?: string;
9
+ }
10
+ /**
11
+ * Expose the established AKK semantic tool registry over MCP.
12
+ *
13
+ * The low-level SDK server intentionally does not infer validation from the
14
+ * schemas returned by tools/list, so every schema is compiled once here and
15
+ * enforced again before any semantic tool can execute.
16
+ */
17
+ export declare function createHostBridgeMcpServer(options: CreateHostBridgeMcpServerOptions): Server;
18
+ export declare function getHostBridgeMcpActiveCallCount(server: Server): number;
19
+ /** Preserve both JSON-RPC request-id type and value inside one Bridge. */
20
+ export declare function hostBridgeToolCallId(instanceId: string, requestId: string | number): string;
21
+ /** Wait until every already accepted MCP tool call has produced a result. */
22
+ export declare function drainHostBridgeMcpCalls(server: Server): Promise<void>;
@@ -0,0 +1,145 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js";
4
+ import { AjvJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/ajv";
5
+ export const HOST_BRIDGE_MCP_SERVER_NAME = "agent-knock-knock-host-bridge";
6
+ const MAX_MODEL_ERROR_LENGTH = 1_024;
7
+ const activeCallsByServer = new WeakMap();
8
+ /**
9
+ * Expose the established AKK semantic tool registry over MCP.
10
+ *
11
+ * The low-level SDK server intentionally does not infer validation from the
12
+ * schemas returned by tools/list, so every schema is compiled once here and
13
+ * enforced again before any semantic tool can execute.
14
+ */
15
+ export function createHostBridgeMcpServer(options) {
16
+ const version = requiredString(options.version, "version");
17
+ const instanceId = requiredString(options.instanceId ?? randomUUID(), "instanceId");
18
+ const descriptors = [...options.registry.list()];
19
+ const validatorProvider = new AjvJsonSchemaValidator();
20
+ const compiledByName = new Map();
21
+ for (const descriptor of descriptors) {
22
+ if (compiledByName.has(descriptor.name)) {
23
+ throw new Error(`duplicate host bridge MCP tool ${descriptor.name}`);
24
+ }
25
+ const validate = validatorProvider.getValidator(descriptor.inputSchema);
26
+ compiledByName.set(descriptor.name, { validate });
27
+ }
28
+ const advertisedTools = descriptors.map((descriptor) => ({
29
+ name: descriptor.name,
30
+ description: descriptor.description,
31
+ inputSchema: descriptor.inputSchema
32
+ }));
33
+ const server = new Server({ name: HOST_BRIDGE_MCP_SERVER_NAME, version }, { capabilities: { tools: {} } });
34
+ const activeCalls = new Set();
35
+ activeCallsByServer.set(server, activeCalls);
36
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: advertisedTools }));
37
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
38
+ const name = request.params.name;
39
+ const compiled = compiledByName.get(name);
40
+ if (!compiled) {
41
+ throw invalidParams(`Unknown host bridge tool: ${name}`);
42
+ }
43
+ if (request.params.task !== undefined ||
44
+ hasLegacyTaskRequest(request.params._meta)) {
45
+ throw invalidParams(`Task execution is not supported for tool: ${name}`);
46
+ }
47
+ const validation = compiled.validate(request.params.arguments ?? {});
48
+ if (!validation.valid) {
49
+ throw invalidParams(`Invalid arguments for ${name}: ${validation.errorMessage}`);
50
+ }
51
+ const execution = executeToolCall(options.registry, name, hostBridgeToolCallId(instanceId, extra.requestId), validation.data);
52
+ activeCalls.add(execution);
53
+ try {
54
+ return await execution;
55
+ }
56
+ finally {
57
+ activeCalls.delete(execution);
58
+ }
59
+ });
60
+ return server;
61
+ }
62
+ export function getHostBridgeMcpActiveCallCount(server) {
63
+ return activeCallsByServer.get(server)?.size ?? 0;
64
+ }
65
+ /** Preserve both JSON-RPC request-id type and value inside one Bridge. */
66
+ export function hostBridgeToolCallId(instanceId, requestId) {
67
+ if ((typeof requestId !== "string" && typeof requestId !== "number") ||
68
+ (typeof requestId === "number" && !Number.isFinite(requestId))) {
69
+ throw new Error("MCP request id must be a finite number or string");
70
+ }
71
+ return `host-bridge:${JSON.stringify([instanceId, requestId])}`;
72
+ }
73
+ /** Wait until every already accepted MCP tool call has produced a result. */
74
+ export async function drainHostBridgeMcpCalls(server) {
75
+ const activeCalls = activeCallsByServer.get(server);
76
+ while (activeCalls && activeCalls.size > 0) {
77
+ await Promise.allSettled([...activeCalls]);
78
+ }
79
+ }
80
+ async function executeToolCall(registry, name, toolCallId, args) {
81
+ try {
82
+ const result = await registry.execute(name, toolCallId, args);
83
+ return mapToolResult(result);
84
+ }
85
+ catch (error) {
86
+ return {
87
+ content: [{ type: "text", text: modelFacingErrorMessage(error) }],
88
+ isError: true
89
+ };
90
+ }
91
+ }
92
+ function mapToolResult(result) {
93
+ const mapped = {
94
+ content: [...(result.content ?? [])]
95
+ };
96
+ if (isRecord(result.details)) {
97
+ mapped.structuredContent = result.details;
98
+ }
99
+ if (typeof result.isError === "boolean") {
100
+ mapped.isError = result.isError;
101
+ }
102
+ return mapped;
103
+ }
104
+ function invalidParams(message) {
105
+ return new McpError(ErrorCode.InvalidParams, boundedSingleLine(message));
106
+ }
107
+ function modelFacingErrorMessage(error) {
108
+ const message = error instanceof Error
109
+ ? error.message
110
+ : typeof error === "string"
111
+ ? error
112
+ : "Tool execution failed.";
113
+ return boundedSingleLine(message) || "Tool execution failed.";
114
+ }
115
+ function boundedSingleLine(value) {
116
+ const sanitized = value
117
+ .replace(/\u001B\[[0-?]*[ -/]*[@-~]/gu, "")
118
+ .replace(/[\u0000-\u001F\u007F-\u009F]/gu, " ")
119
+ .replace(/\s+/gu, " ")
120
+ .trim();
121
+ if (sanitized.length <= MAX_MODEL_ERROR_LENGTH) {
122
+ return sanitized;
123
+ }
124
+ let prefix = "";
125
+ for (const character of sanitized) {
126
+ if (prefix.length + character.length > MAX_MODEL_ERROR_LENGTH - 3) {
127
+ break;
128
+ }
129
+ prefix += character;
130
+ }
131
+ return `${prefix}...`;
132
+ }
133
+ function hasLegacyTaskRequest(meta) {
134
+ return isRecord(meta) && meta.task !== undefined;
135
+ }
136
+ function requiredString(value, label) {
137
+ if (typeof value !== "string" || value.trim().length === 0) {
138
+ throw new Error(`${label} is required`);
139
+ }
140
+ return value;
141
+ }
142
+ function isRecord(value) {
143
+ return typeof value === "object" && value !== null && !Array.isArray(value);
144
+ }
145
+ //# sourceMappingURL=host-bridge-mcp.js.map