@wirecat/cli-core 0.466.0 → 0.467.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.
- package/CHANGELOG.md +36 -0
- package/README.md +4 -2
- package/dist/cli/command-runs.d.ts +38 -10
- package/dist/cli/command-runs.js +51 -17
- package/dist/cli/context.d.ts +3 -0
- package/dist/cli/context.js +15 -3
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.js +1 -1
- package/dist/cli/messenger/context.js +1 -1
- package/dist/cli/messenger/observed.js +10 -2
- package/dist/cli/messenger/report.js +48 -3
- package/dist/cli/program.d.ts +1 -1
- package/dist/cli/program.js +7 -3
- package/dist/cli/settings.d.ts +19 -6
- package/dist/cli/settings.js +14 -3
- package/dist/cli/shared-command-exports.d.ts +12 -4
- package/dist/entities/index.d.ts +39 -0
- package/dist/entities/recorded-run.d.ts +39 -0
- package/dist/entities/recorded-run.js +14 -1
- package/dist/mcp/agent.d.ts +3 -0
- package/dist/mcp/agent.js +2 -0
- package/dist/mcp/all-profiles.d.ts +2 -0
- package/dist/mcp/all-profiles.js +16 -3
- package/dist/mcp/bot/server.js +8 -3
- package/dist/mcp/caller.d.ts +38 -0
- package/dist/mcp/caller.js +95 -0
- package/dist/mcp/http/oauth.js +5 -1
- package/dist/mcp/server.js +19 -7
- package/dist/mcp/surface.js +11 -2
- package/dist/mcp/tool.d.ts +4 -1
- package/dist/mcp/tool.js +21 -11
- package/dist/runs/events.d.ts +16 -4
- package/dist/runs/events.js +4 -0
- package/dist/runs/log-attributes.js +7 -1
- package/dist/runs/log-events.js +5 -0
- package/dist/runs/recording.d.ts +10 -3
- package/dist/runs/recording.js +59 -15
- package/dist/runs/run-context.d.ts +55 -4
- package/dist/runs/run-context.js +34 -3
- package/dist/runs/run.d.ts +37 -11
- package/dist/runs/run.js +201 -52
- package/dist/runs/scope.d.ts +12 -0
- package/dist/runs/scope.js +6 -0
- package/dist/services/patience.js +5 -1
- package/package.json +1 -1
package/dist/cli/settings.js
CHANGED
|
@@ -5,6 +5,7 @@ import { AI_ENTRIES, resolveAISettings } from "../analysis/settings.js";
|
|
|
5
5
|
import { parseDuration } from "../domain/duration.js";
|
|
6
6
|
import { DEFAULT_RERANK_MODEL, RERANK_MODELS } from "../embeddings/models.js";
|
|
7
7
|
import { envName, readOnlyLockOf } from "../ports/app.js";
|
|
8
|
+
import { KEEP_SUCCESSFUL_RUNS_FOR_DAYS, RUNS_SIZE_LIMIT_MB } from "../runs/run.js";
|
|
8
9
|
import { assertOverridesTighten, CEILING_KEY, COMMAND_PATH_KEY, LEVELS, layerPermissions, permissionOverrides, RESOURCE_KEY, RESOURCES, } from "../sends/permissions.js";
|
|
9
10
|
import { storePath } from "../store/path.js";
|
|
10
11
|
import { sharedConfigPath } from "../store/shared-config.js";
|
|
@@ -33,6 +34,8 @@ export const count = v.pipe(v.number(wholeNumber), v.integer(wholeNumber), v.min
|
|
|
33
34
|
const zeroOrMore = plain("has to be a whole number, 0 or more");
|
|
34
35
|
const countOrZero = v.pipe(v.number(zeroOrMore), v.integer(zeroOrMore), v.minValue(0, zeroOrMore));
|
|
35
36
|
export const flag = v.boolean(plain("has to be true or false"));
|
|
37
|
+
/** `record_input`: true, false, or "failed" — the words typed kept only in a run that failed. */
|
|
38
|
+
export const recordInputSetting = v.union([v.boolean(), v.literal("failed")], plain('has to be true, false or "failed"'));
|
|
36
39
|
const wholeOrZero = (text, name) => {
|
|
37
40
|
const value = Number(text);
|
|
38
41
|
if (!Number.isInteger(value) || value < 0)
|
|
@@ -58,8 +61,10 @@ const SHARED_PROFILE_ENTRIES = {
|
|
|
58
61
|
color: v.optional(flag),
|
|
59
62
|
sender_colors: v.optional(flag),
|
|
60
63
|
record: v.optional(flag),
|
|
61
|
-
record_input: v.optional(
|
|
64
|
+
record_input: v.optional(recordInputSetting),
|
|
62
65
|
keep_runs_for_days: v.optional(count),
|
|
66
|
+
keep_successful_runs_for_days: v.optional(count),
|
|
67
|
+
runs_size_limit_mb: v.optional(count),
|
|
63
68
|
permissions: v.optional(permissionLevels),
|
|
64
69
|
sends_per_hour: v.optional(count),
|
|
65
70
|
requests_per_minute: v.optional(countOrZero),
|
|
@@ -232,7 +237,7 @@ export const settingsFor = (app, extension = {}) => {
|
|
|
232
237
|
const fromLayers = (key, fallback, only = layers) => first(only.map(([from, scope]) => [from, scope?.[key]]), fallback);
|
|
233
238
|
const kindLayers = layers.filter(([from]) => from.startsWith(`config file: ${kind}.`));
|
|
234
239
|
const limit = flags.limit === undefined ? fromLayers("limit", DEFAULT_LIMIT) : { value: flags.limit, from: "flag" };
|
|
235
|
-
const record = flags.record === undefined ? fromLayers("record",
|
|
240
|
+
const record = flags.record === undefined ? fromLayers("record", true) : { value: flags.record, from: "flag" };
|
|
236
241
|
const timeoutMs = fromLayers("timeout_ms", undefined);
|
|
237
242
|
const color = fromLayers("color", undefined);
|
|
238
243
|
const senderColors = fromLayers("sender_colors", false);
|
|
@@ -241,6 +246,8 @@ export const settingsFor = (app, extension = {}) => {
|
|
|
241
246
|
const searchReranker = fromLayers("search_reranker", DEFAULT_RERANK_MODEL);
|
|
242
247
|
const recordInput = fromLayers("record_input", true);
|
|
243
248
|
const keepRunsForDays = fromLayers("keep_runs_for_days", DEFAULT_KEEP_RUNS_FOR_DAYS);
|
|
249
|
+
const keepSuccessfulRunsForDays = fromLayers("keep_successful_runs_for_days", KEEP_SUCCESSFUL_RUNS_FOR_DAYS);
|
|
250
|
+
const runsSizeLimitMb = fromLayers("runs_size_limit_mb", RUNS_SIZE_LIMIT_MB);
|
|
244
251
|
// Set where an agent runs unattended; the config file and `--permission` cannot undo it.
|
|
245
252
|
const readOnlyLock = readOnlyLockOf(app, env);
|
|
246
253
|
// A bot has no hourly limit unless the bot section gives it one: a bot that answers people is
|
|
@@ -297,8 +304,10 @@ export const settingsFor = (app, extension = {}) => {
|
|
|
297
304
|
: (extension.parseDuration ?? parseDuration)(timeout.value, timeout.from === TIMEOUT ? TIMEOUT : "--timeout"),
|
|
298
305
|
record: record.value,
|
|
299
306
|
recordInput: recordInput.value,
|
|
300
|
-
keepFailedRuns: record.value || record.from
|
|
307
|
+
keepFailedRuns: record.value || record.from !== "flag",
|
|
301
308
|
keepRunsForDays: keepRunsForDays.value,
|
|
309
|
+
keepSuccessfulRunsForDays: keepSuccessfulRunsForDays.value,
|
|
310
|
+
runsSizeLimitMb: runsSizeLimitMb.value,
|
|
302
311
|
...(readOnlyLock ? { readOnlyLock } : {}),
|
|
303
312
|
permissions: permissions.levels,
|
|
304
313
|
permissionSources: permissions.sources,
|
|
@@ -326,6 +335,8 @@ export const settingsFor = (app, extension = {}) => {
|
|
|
326
335
|
record: record.from,
|
|
327
336
|
recordInput: recordInput.from,
|
|
328
337
|
keepRunsForDays: keepRunsForDays.from,
|
|
338
|
+
keepSuccessfulRunsForDays: keepSuccessfulRunsForDays.from,
|
|
339
|
+
runsSizeLimitMb: runsSizeLimitMb.from,
|
|
329
340
|
sendsPerHour: sendsPerHour.from,
|
|
330
341
|
requestsPerMinute: requestsPerMinute.from,
|
|
331
342
|
readOtherBots: readOtherBots.from,
|
|
@@ -79,8 +79,10 @@ export declare const configCommand: (app: import("./entry.js").AppIdentity, conf
|
|
|
79
79
|
color: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
80
80
|
sender_colors: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
81
81
|
record: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
82
|
-
record_input: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
82
|
+
record_input: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").BooleanSchema<undefined>, import("valibot").LiteralSchema<"failed", undefined>], (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
83
83
|
keep_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
84
|
+
keep_successful_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
85
|
+
runs_size_limit_mb: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
84
86
|
permissions: import("valibot").OptionalSchema<import("valibot").RecordSchema<import("valibot").GenericSchema<string>, import("valibot").PicklistSchema<readonly ["deny", "readonly", "ask", "allow"], (issue: import("valibot").PicklistIssue) => string>, (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
85
87
|
sends_per_hour: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
86
88
|
requests_per_minute: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 0, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
@@ -153,8 +155,10 @@ export declare const configCommand: (app: import("./entry.js").AppIdentity, conf
|
|
|
153
155
|
color: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
154
156
|
sender_colors: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
155
157
|
record: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
156
|
-
record_input: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
158
|
+
record_input: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").BooleanSchema<undefined>, import("valibot").LiteralSchema<"failed", undefined>], (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
157
159
|
keep_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
160
|
+
keep_successful_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
161
|
+
runs_size_limit_mb: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
158
162
|
permissions: import("valibot").OptionalSchema<import("valibot").RecordSchema<import("valibot").GenericSchema<string>, import("valibot").PicklistSchema<readonly ["deny", "readonly", "ask", "allow"], (issue: import("valibot").PicklistIssue) => string>, (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
159
163
|
sends_per_hour: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
160
164
|
requests_per_minute: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 0, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
@@ -283,8 +287,10 @@ export declare const completeCommand: (messenger: import("./index.js").Messenger
|
|
|
283
287
|
color: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
284
288
|
sender_colors: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
285
289
|
record: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
286
|
-
record_input: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
290
|
+
record_input: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").BooleanSchema<undefined>, import("valibot").LiteralSchema<"failed", undefined>], (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
287
291
|
keep_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
292
|
+
keep_successful_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
293
|
+
runs_size_limit_mb: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
288
294
|
permissions: import("valibot").OptionalSchema<import("valibot").RecordSchema<import("valibot").GenericSchema<string>, import("valibot").PicklistSchema<readonly ["deny", "readonly", "ask", "allow"], (issue: import("valibot").PicklistIssue) => string>, (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
289
295
|
sends_per_hour: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
290
296
|
requests_per_minute: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 0, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
@@ -357,8 +363,10 @@ export declare const completeCommand: (messenger: import("./index.js").Messenger
|
|
|
357
363
|
color: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
358
364
|
sender_colors: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
359
365
|
record: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
360
|
-
record_input: import("valibot").OptionalSchema<import("valibot").BooleanSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
366
|
+
record_input: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").BooleanSchema<undefined>, import("valibot").LiteralSchema<"failed", undefined>], (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
361
367
|
keep_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
368
|
+
keep_successful_runs_for_days: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
369
|
+
runs_size_limit_mb: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
362
370
|
permissions: import("valibot").OptionalSchema<import("valibot").RecordSchema<import("valibot").GenericSchema<string>, import("valibot").PicklistSchema<readonly ["deny", "readonly", "ask", "allow"], (issue: import("valibot").PicklistIssue) => string>, (issue: import("valibot").BaseIssue<unknown>) => string>, undefined>;
|
|
363
371
|
sends_per_hour: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 1, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
|
364
372
|
requests_per_minute: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<(issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").IntegerAction<number, (issue: import("valibot").BaseIssue<unknown>) => string>, import("valibot").MinValueAction<number, 0, (issue: import("valibot").BaseIssue<unknown>) => string>]>, undefined>;
|
package/dist/entities/index.d.ts
CHANGED
|
@@ -6312,7 +6312,20 @@ export declare const ENTITIES: {
|
|
|
6312
6312
|
readonly kind: v.StringSchema<undefined>;
|
|
6313
6313
|
readonly session_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
6314
6314
|
readonly from_chat: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
6315
|
+
readonly client: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6316
|
+
readonly name: v.StringSchema<undefined>;
|
|
6317
|
+
readonly version: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6318
|
+
readonly id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6319
|
+
}, undefined>, undefined>;
|
|
6315
6320
|
}, undefined>, undefined>;
|
|
6321
|
+
readonly via: v.OptionalSchema<v.PicklistSchema<["cli", "mcp-stdio", "mcp-http", "desktop"], undefined>, undefined>;
|
|
6322
|
+
readonly mcp: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6323
|
+
readonly tool: v.StringSchema<undefined>;
|
|
6324
|
+
readonly request_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6325
|
+
readonly connection_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6326
|
+
readonly proxied: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
6327
|
+
}, undefined>, undefined>;
|
|
6328
|
+
readonly events_dropped: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
6316
6329
|
readonly error: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6317
6330
|
readonly class: v.StringSchema<undefined>;
|
|
6318
6331
|
readonly code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -6375,7 +6388,20 @@ export declare const ENTITIES: {
|
|
|
6375
6388
|
readonly kind: v.StringSchema<undefined>;
|
|
6376
6389
|
readonly session_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
6377
6390
|
readonly from_chat: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
6391
|
+
readonly client: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6392
|
+
readonly name: v.StringSchema<undefined>;
|
|
6393
|
+
readonly version: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6394
|
+
readonly id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6395
|
+
}, undefined>, undefined>;
|
|
6396
|
+
}, undefined>, undefined>;
|
|
6397
|
+
readonly via: v.OptionalSchema<v.PicklistSchema<["cli", "mcp-stdio", "mcp-http", "desktop"], undefined>, undefined>;
|
|
6398
|
+
readonly mcp: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6399
|
+
readonly tool: v.StringSchema<undefined>;
|
|
6400
|
+
readonly request_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6401
|
+
readonly connection_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6402
|
+
readonly proxied: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
6378
6403
|
}, undefined>, undefined>;
|
|
6404
|
+
readonly events_dropped: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
6379
6405
|
readonly error: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6380
6406
|
readonly class: v.StringSchema<undefined>;
|
|
6381
6407
|
readonly code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -6437,7 +6463,20 @@ export declare const ENTITIES: {
|
|
|
6437
6463
|
readonly kind: v.StringSchema<undefined>;
|
|
6438
6464
|
readonly session_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
6439
6465
|
readonly from_chat: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
6466
|
+
readonly client: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6467
|
+
readonly name: v.StringSchema<undefined>;
|
|
6468
|
+
readonly version: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6469
|
+
readonly id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6470
|
+
}, undefined>, undefined>;
|
|
6471
|
+
}, undefined>, undefined>;
|
|
6472
|
+
readonly via: v.OptionalSchema<v.PicklistSchema<["cli", "mcp-stdio", "mcp-http", "desktop"], undefined>, undefined>;
|
|
6473
|
+
readonly mcp: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6474
|
+
readonly tool: v.StringSchema<undefined>;
|
|
6475
|
+
readonly request_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6476
|
+
readonly connection_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
6477
|
+
readonly proxied: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
6440
6478
|
}, undefined>, undefined>;
|
|
6479
|
+
readonly events_dropped: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
6441
6480
|
readonly error: v.OptionalSchema<v.StrictObjectSchema<{
|
|
6442
6481
|
readonly class: v.StringSchema<undefined>;
|
|
6443
6482
|
readonly code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -35,7 +35,20 @@ export declare const recordedRun: v.StrictObjectSchema<{
|
|
|
35
35
|
readonly kind: v.StringSchema<undefined>;
|
|
36
36
|
readonly session_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
37
37
|
readonly from_chat: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
38
|
+
readonly client: v.OptionalSchema<v.StrictObjectSchema<{
|
|
39
|
+
readonly name: v.StringSchema<undefined>;
|
|
40
|
+
readonly version: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
41
|
+
readonly id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
42
|
+
}, undefined>, undefined>;
|
|
43
|
+
}, undefined>, undefined>;
|
|
44
|
+
readonly via: v.OptionalSchema<v.PicklistSchema<["cli", "mcp-stdio", "mcp-http", "desktop"], undefined>, undefined>;
|
|
45
|
+
readonly mcp: v.OptionalSchema<v.StrictObjectSchema<{
|
|
46
|
+
readonly tool: v.StringSchema<undefined>;
|
|
47
|
+
readonly request_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
48
|
+
readonly connection_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
49
|
+
readonly proxied: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
38
50
|
}, undefined>, undefined>;
|
|
51
|
+
readonly events_dropped: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
39
52
|
readonly error: v.OptionalSchema<v.StrictObjectSchema<{
|
|
40
53
|
readonly class: v.StringSchema<undefined>;
|
|
41
54
|
readonly code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -98,7 +111,20 @@ export declare const runDetails: v.StrictObjectSchema<{
|
|
|
98
111
|
readonly kind: v.StringSchema<undefined>;
|
|
99
112
|
readonly session_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
100
113
|
readonly from_chat: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
114
|
+
readonly client: v.OptionalSchema<v.StrictObjectSchema<{
|
|
115
|
+
readonly name: v.StringSchema<undefined>;
|
|
116
|
+
readonly version: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
117
|
+
readonly id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
118
|
+
}, undefined>, undefined>;
|
|
101
119
|
}, undefined>, undefined>;
|
|
120
|
+
readonly via: v.OptionalSchema<v.PicklistSchema<["cli", "mcp-stdio", "mcp-http", "desktop"], undefined>, undefined>;
|
|
121
|
+
readonly mcp: v.OptionalSchema<v.StrictObjectSchema<{
|
|
122
|
+
readonly tool: v.StringSchema<undefined>;
|
|
123
|
+
readonly request_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
124
|
+
readonly connection_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
125
|
+
readonly proxied: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
126
|
+
}, undefined>, undefined>;
|
|
127
|
+
readonly events_dropped: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
102
128
|
readonly error: v.OptionalSchema<v.StrictObjectSchema<{
|
|
103
129
|
readonly class: v.StringSchema<undefined>;
|
|
104
130
|
readonly code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -160,7 +186,20 @@ export declare const runHit: v.StrictObjectSchema<{
|
|
|
160
186
|
readonly kind: v.StringSchema<undefined>;
|
|
161
187
|
readonly session_id: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
162
188
|
readonly from_chat: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
189
|
+
readonly client: v.OptionalSchema<v.StrictObjectSchema<{
|
|
190
|
+
readonly name: v.StringSchema<undefined>;
|
|
191
|
+
readonly version: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
192
|
+
readonly id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
193
|
+
}, undefined>, undefined>;
|
|
194
|
+
}, undefined>, undefined>;
|
|
195
|
+
readonly via: v.OptionalSchema<v.PicklistSchema<["cli", "mcp-stdio", "mcp-http", "desktop"], undefined>, undefined>;
|
|
196
|
+
readonly mcp: v.OptionalSchema<v.StrictObjectSchema<{
|
|
197
|
+
readonly tool: v.StringSchema<undefined>;
|
|
198
|
+
readonly request_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
199
|
+
readonly connection_id: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
200
|
+
readonly proxied: v.OptionalSchema<v.LiteralSchema<true, undefined>, undefined>;
|
|
163
201
|
}, undefined>, undefined>;
|
|
202
|
+
readonly events_dropped: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>, undefined>;
|
|
164
203
|
readonly error: v.OptionalSchema<v.StrictObjectSchema<{
|
|
165
204
|
readonly class: v.StringSchema<undefined>;
|
|
166
205
|
readonly code: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -28,7 +28,20 @@ export const recordedRun = v.strictObject({
|
|
|
28
28
|
cli_command: v.optional(text),
|
|
29
29
|
argv: v.optional(v.array(text)),
|
|
30
30
|
unknown_command: v.optional(text),
|
|
31
|
-
agent: v.optional(v.strictObject({
|
|
31
|
+
agent: v.optional(v.strictObject({
|
|
32
|
+
kind: text,
|
|
33
|
+
session_id: v.nullable(text),
|
|
34
|
+
from_chat: v.optional(v.literal(true)),
|
|
35
|
+
client: v.optional(v.strictObject({ name: text, version: v.optional(text), id: v.optional(text) })),
|
|
36
|
+
})),
|
|
37
|
+
via: v.optional(v.picklist(["cli", "mcp-stdio", "mcp-http", "desktop"])),
|
|
38
|
+
mcp: v.optional(v.strictObject({
|
|
39
|
+
tool: text,
|
|
40
|
+
request_id: v.optional(text),
|
|
41
|
+
connection_id: v.optional(text),
|
|
42
|
+
proxied: v.optional(v.literal(true)),
|
|
43
|
+
})),
|
|
44
|
+
events_dropped: v.optional(count),
|
|
32
45
|
error: v.optional(v.strictObject({
|
|
33
46
|
class: text,
|
|
34
47
|
code: v.optional(text),
|
package/dist/mcp/agent.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export type { CommandAvailability } from "../cli/command-availability.js";
|
|
|
7
7
|
import type { RunOptions } from "../cli/program.js";
|
|
8
8
|
import type { StdinField } from "../cli/stdin-field.js";
|
|
9
9
|
import type { MessengerAdapter } from "../ports/messenger.js";
|
|
10
|
+
import type { RunCaller } from "../runs/run-context.js";
|
|
10
11
|
import { type Level, type PermissionKey } from "../sends/permissions.js";
|
|
11
12
|
/** The CLI's own `run` — a fresh program on every call — and its command tree as `commands --json` describes it. */
|
|
12
13
|
export interface AgentProgram {
|
|
@@ -32,6 +33,8 @@ export interface AgentContext {
|
|
|
32
33
|
stdin?: (path: readonly string[]) => StdinField | undefined;
|
|
33
34
|
/** More of the run's environment, read by the commands that look for it: the server's `spawnJob`, `embedders`. */
|
|
34
35
|
environment?: Readonly<Record<string, unknown>>;
|
|
36
|
+
/** Who made the call (`callerOf`); the run records it rather than this server's environment. */
|
|
37
|
+
caller?: RunCaller;
|
|
35
38
|
}
|
|
36
39
|
export type AgentAnswer = {
|
|
37
40
|
result: unknown;
|
package/dist/mcp/agent.js
CHANGED
|
@@ -8,6 +8,7 @@ import { commandAvailability } from "../cli/command-availability.js";
|
|
|
8
8
|
import { changesMessenger } from "../cli/effects.js";
|
|
9
9
|
import { lentConnection } from "../cli/messenger/serve-relay.js";
|
|
10
10
|
import { authorityAllowed, botApiAllowed } from "../sends/permissions.js";
|
|
11
|
+
import { currentCaller } from "./caller.js";
|
|
11
12
|
const TYPES = new Map(VOCABULARY.flags.map((flag) => [flag.name, flag.type]));
|
|
12
13
|
// `<name|id>` is one argument: its field is `name_or_id`.
|
|
13
14
|
const snake = (name) => name.replaceAll("|", "_or_").replace(/[^a-z0-9]+/gi, "_");
|
|
@@ -231,6 +232,7 @@ export const runCommandForAgent = async (program, path, input, ctx) => {
|
|
|
231
232
|
...(ctx.overrides?.length ? { overrides: ctx.overrides } : {}),
|
|
232
233
|
authority: levels !== undefined && authorityAllowed(levels),
|
|
233
234
|
botApi: levels !== undefined && botApiAllowed(levels),
|
|
235
|
+
...((ctx.caller ?? currentCaller()) ? { caller: ctx.caller ?? currentCaller() } : {}),
|
|
234
236
|
},
|
|
235
237
|
// Opened only when the command asks: a read the store answers never connects.
|
|
236
238
|
...(lend
|
|
@@ -25,6 +25,8 @@ export interface AllProfilesOptions {
|
|
|
25
25
|
idleMs?: number;
|
|
26
26
|
/** A child's stderr, line by line; never this process's stdout, which carries the protocol. */
|
|
27
27
|
note?: (line: string) => void;
|
|
28
|
+
/** This server's environment, which names the agent that started it on stdio; `process.env` when left out. */
|
|
29
|
+
env?: NodeJS.ProcessEnv;
|
|
28
30
|
}
|
|
29
31
|
/**
|
|
30
32
|
* The child's tool with the one field that picks the profile, required and without a default. Each profile carries
|
package/dist/mcp/all-profiles.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { McpServer } from "@modelcontextprotocol/server";
|
|
3
4
|
import { StdioServerTransport, serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
5
|
+
import { CALLER_META_KEY, callerOf, PROXY_CLIENT_NAME } from "./caller.js";
|
|
4
6
|
import { answeredWire } from "./stdio-wire.js";
|
|
5
7
|
const PROTOCOL = "2025-06-18";
|
|
6
8
|
const START_MS = 30_000;
|
|
@@ -82,7 +84,7 @@ const startChild = (spec, note, onExit) => {
|
|
|
82
84
|
return request("initialize", {
|
|
83
85
|
protocolVersion: PROTOCOL,
|
|
84
86
|
capabilities: {},
|
|
85
|
-
clientInfo: { name:
|
|
87
|
+
clientInfo: { name: PROXY_CLIENT_NAME, version: "1" },
|
|
86
88
|
})
|
|
87
89
|
.then(() => {
|
|
88
90
|
send({ method: "notifications/initialized" });
|
|
@@ -202,7 +204,12 @@ export const allProfilesServer = (options) => {
|
|
|
202
204
|
? []
|
|
203
205
|
: (await tools(profiles)).map((one) => withProfile(one, profiles, options.name, signedIn)),
|
|
204
206
|
}));
|
|
205
|
-
|
|
207
|
+
const callers = {
|
|
208
|
+
env: options.env ?? process.env,
|
|
209
|
+
client: () => server.server.getClientVersion(),
|
|
210
|
+
connectionId: randomUUID(),
|
|
211
|
+
};
|
|
212
|
+
server.server.setRequestHandler("tools/call", async (request, ctx) => {
|
|
206
213
|
const { name, arguments: given = {}, _meta } = request.params;
|
|
207
214
|
const { profile, ...rest } = given;
|
|
208
215
|
if (typeof profile !== "string" || !profiles.includes(profile))
|
|
@@ -210,7 +217,13 @@ export const allProfilesServer = (options) => {
|
|
|
210
217
|
if (!signedIn(profile))
|
|
211
218
|
return refusal(options.signIn?.(profile) ?? `profile ${profile} is not signed in.`);
|
|
212
219
|
try {
|
|
213
|
-
return (await children.use(profile, (child) =>
|
|
220
|
+
return (await children.use(profile, (child) =>
|
|
221
|
+
// Children are shared by every session, so each call names its own caller.
|
|
222
|
+
child.request("tools/call", {
|
|
223
|
+
name,
|
|
224
|
+
arguments: rest,
|
|
225
|
+
_meta: { ..._meta, [CALLER_META_KEY]: callerOf(ctx, name, callers) },
|
|
226
|
+
})));
|
|
214
227
|
}
|
|
215
228
|
catch (error) {
|
|
216
229
|
return refusal(`profile ${profile}: ${error instanceof Error ? error.message : String(error)}`);
|
package/dist/mcp/bot/server.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { McpServer } from "@modelcontextprotocol/server";
|
|
2
3
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
3
4
|
import { mcpErrorResult } from "@wirecat/cli-base";
|
|
@@ -9,6 +10,7 @@ import { itemOf } from "../../cli/envelope.js";
|
|
|
9
10
|
import { wholeList } from "../../cli/messenger/chat-answers.js";
|
|
10
11
|
import { MESSENGER_CHANGE_REFUSAL, readOnlyLockOf, readOnlyRefusal } from "../../ports/app.js";
|
|
11
12
|
import { runCommandForAgent, toolsFromCommands } from "../agent.js";
|
|
13
|
+
import { callerOf } from "../caller.js";
|
|
12
14
|
import { normal, registerCommands } from "../surface.js";
|
|
13
15
|
import { agentJson } from "../text.js";
|
|
14
16
|
import { answered } from "../tool.js";
|
|
@@ -48,7 +50,7 @@ export const createBotServer = (options) => {
|
|
|
48
50
|
const skill = options.skill ? skillResource(bot.app, options.skill) : undefined;
|
|
49
51
|
// One at a time: the commands share the journal, the registry and the local copy.
|
|
50
52
|
let queue = Promise.resolve();
|
|
51
|
-
const invoke = (path, input) => {
|
|
53
|
+
const invoke = (path, input, caller) => {
|
|
52
54
|
const next = queue.then(() => runCommandForAgent(program, path, path[0] === "config" ? { ...input, bot: true } : input, {
|
|
53
55
|
profile: settings.profile,
|
|
54
56
|
readOnly: readOnlyLockOf(bot.app, env) !== undefined,
|
|
@@ -56,11 +58,13 @@ export const createBotServer = (options) => {
|
|
|
56
58
|
levels,
|
|
57
59
|
...(options.keyOf ? { keyOf: options.keyOf } : {}),
|
|
58
60
|
authority,
|
|
61
|
+
...(caller ? { caller } : {}),
|
|
59
62
|
}));
|
|
60
63
|
queue = next.catch(() => undefined);
|
|
61
64
|
return next;
|
|
62
65
|
};
|
|
63
66
|
const build = () => {
|
|
67
|
+
const callers = { env, client: () => server.server.getClientVersion(), connectionId: randomUUID() };
|
|
64
68
|
const server = new McpServer({ name: `${command}-bot-${settings.profile}`, version: bot.app.version }, {
|
|
65
69
|
instructions: botInstructions({
|
|
66
70
|
command,
|
|
@@ -82,8 +86,9 @@ export const createBotServer = (options) => {
|
|
|
82
86
|
writes: tool.writes,
|
|
83
87
|
availability: tool.availability,
|
|
84
88
|
input: tool.input,
|
|
85
|
-
run: async (args) => {
|
|
86
|
-
const
|
|
89
|
+
run: async (args, ctx) => {
|
|
90
|
+
const caller = callerOf(ctx, `${command}_${tool.command.replaceAll(" ", "_")}`, callers);
|
|
91
|
+
const answer = await invoke(tool.path, args, caller);
|
|
87
92
|
return "error" in answer
|
|
88
93
|
? mcpErrorResult(JSON.parse(agentJson(answer.error)))
|
|
89
94
|
: answered(body(tool.command, answer.result));
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type RunCaller } from "../runs/run-context.js";
|
|
2
|
+
export { currentCaller, withCaller } from "../runs/run-context.js";
|
|
3
|
+
/** The `_meta` key the every-profile server names the real caller under, for the profile server it passes a call to. */
|
|
4
|
+
export declare const CALLER_META_KEY = "wirecat.dev/caller";
|
|
5
|
+
/** The name the every-profile server gives itself in `initialize`; only a connection from it may name a caller. */
|
|
6
|
+
export declare const PROXY_CLIENT_NAME = "all-profiles";
|
|
7
|
+
/** What a tool call's handler is given, reduced to what identifies the caller. */
|
|
8
|
+
export interface CallContext {
|
|
9
|
+
sessionId?: string | undefined;
|
|
10
|
+
mcpReq?: {
|
|
11
|
+
id?: string | number;
|
|
12
|
+
_meta?: Record<string, unknown> | undefined;
|
|
13
|
+
} | undefined;
|
|
14
|
+
http?: {
|
|
15
|
+
authInfo?: {
|
|
16
|
+
clientId: string;
|
|
17
|
+
extra?: Record<string, unknown> | undefined;
|
|
18
|
+
} | undefined;
|
|
19
|
+
} | undefined;
|
|
20
|
+
}
|
|
21
|
+
export interface CallerSource {
|
|
22
|
+
/** This server's environment: the coding agent that started a stdio server. Never read for an HTTP call. */
|
|
23
|
+
env: NodeJS.ProcessEnv;
|
|
24
|
+
/** The client's `initialize`, when this connection had one. */
|
|
25
|
+
client?: () => {
|
|
26
|
+
name: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
} | undefined;
|
|
29
|
+
/** One id per stdio connection, made when the server starts. */
|
|
30
|
+
connectionId?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Who made one MCP call. Over HTTP the server's own environment is somebody else's — whoever started `mcp --http` —
|
|
34
|
+
* so the caller is the OAuth client (its registered name and a hash of its id) and the HTTP session, if any. Over
|
|
35
|
+
* stdio the agent that started the server is the caller, and `initialize` names its client. A call the every-profile
|
|
36
|
+
* server passed on carries the caller it worked out, trusted only on a connection that server opened.
|
|
37
|
+
*/
|
|
38
|
+
export declare const callerOf: (ctx: CallContext | undefined, tool: string, source: CallerSource) => RunCaller;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { CLIENT_INFO_META_KEY } from "@modelcontextprotocol/server";
|
|
2
|
+
import { agentOf, clientHash } from "../runs/run-context.js";
|
|
3
|
+
export { currentCaller, withCaller } from "../runs/run-context.js";
|
|
4
|
+
/** The `_meta` key the every-profile server names the real caller under, for the profile server it passes a call to. */
|
|
5
|
+
export const CALLER_META_KEY = "wirecat.dev/caller";
|
|
6
|
+
/** The name the every-profile server gives itself in `initialize`; only a connection from it may name a caller. */
|
|
7
|
+
export const PROXY_CLIENT_NAME = "all-profiles";
|
|
8
|
+
const NAME = /^[\w .@()/+-]{1,64}$/;
|
|
9
|
+
const plain = (value) => typeof value === "string" && NAME.test(value.trim()) ? value.trim() : undefined;
|
|
10
|
+
const clientFrom = (value) => {
|
|
11
|
+
if (!value || typeof value !== "object")
|
|
12
|
+
return undefined;
|
|
13
|
+
const { name, version } = value;
|
|
14
|
+
const named = plain(name);
|
|
15
|
+
if (!named)
|
|
16
|
+
return undefined;
|
|
17
|
+
const versioned = plain(version);
|
|
18
|
+
return { name: named, ...(versioned ? { version: versioned } : {}) };
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Who made one MCP call. Over HTTP the server's own environment is somebody else's — whoever started `mcp --http` —
|
|
22
|
+
* so the caller is the OAuth client (its registered name and a hash of its id) and the HTTP session, if any. Over
|
|
23
|
+
* stdio the agent that started the server is the caller, and `initialize` names its client. A call the every-profile
|
|
24
|
+
* server passed on carries the caller it worked out, trusted only on a connection that server opened.
|
|
25
|
+
*/
|
|
26
|
+
export const callerOf = (ctx, tool, source) => {
|
|
27
|
+
const meta = ctx?.mcpReq?._meta;
|
|
28
|
+
const requestId = ctx?.mcpReq?.id;
|
|
29
|
+
const initialized = source.client?.();
|
|
30
|
+
const proxied = initialized?.name === PROXY_CLIENT_NAME ? passedOn(meta?.[CALLER_META_KEY], tool) : undefined;
|
|
31
|
+
if (proxied)
|
|
32
|
+
return proxied;
|
|
33
|
+
const client = clientFrom(meta?.[CLIENT_INFO_META_KEY]) ?? clientFrom(initialized);
|
|
34
|
+
const mcp = (connection) => ({
|
|
35
|
+
tool,
|
|
36
|
+
...(requestId === undefined ? {} : { request_id: String(requestId) }),
|
|
37
|
+
...(connection ? { connection_id: connection } : {}),
|
|
38
|
+
});
|
|
39
|
+
const auth = ctx?.http?.authInfo;
|
|
40
|
+
if (auth) {
|
|
41
|
+
const registered = plain(auth.extra?.clientName);
|
|
42
|
+
return {
|
|
43
|
+
via: "mcp-http",
|
|
44
|
+
agent: {
|
|
45
|
+
kind: "mcp-client",
|
|
46
|
+
session_id: ctx?.sessionId ?? null,
|
|
47
|
+
client: {
|
|
48
|
+
name: registered ?? client?.name ?? "unknown",
|
|
49
|
+
...(client?.version ? { version: client.version } : {}),
|
|
50
|
+
id: clientHash(auth.clientId),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
mcp: mcp(ctx?.sessionId),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const agent = agentOf(source.env) ?? { kind: "mcp-client", session_id: null };
|
|
57
|
+
return { via: "mcp-stdio", agent: { ...agent, ...(client ? { client } : {}) }, mcp: mcp(source.connectionId) };
|
|
58
|
+
};
|
|
59
|
+
/** The caller the every-profile server named, field by field: nothing else it sent reaches a run. */
|
|
60
|
+
const passedOn = (value, tool) => {
|
|
61
|
+
if (!value || typeof value !== "object")
|
|
62
|
+
return undefined;
|
|
63
|
+
const { via, agent, mcp } = value;
|
|
64
|
+
if (via !== "mcp-stdio" && via !== "mcp-http")
|
|
65
|
+
return undefined;
|
|
66
|
+
const a = agent && typeof agent === "object" ? agent : undefined;
|
|
67
|
+
const kind = plain(a?.kind);
|
|
68
|
+
const session = typeof a?.session_id === "string" && /^[A-Za-z0-9._:-]{1,128}$/.test(a.session_id) ? a.session_id : null;
|
|
69
|
+
const client = clientFrom(a?.client);
|
|
70
|
+
const id = a?.client && typeof a.client === "object" ? a.client.id : undefined;
|
|
71
|
+
const m = mcp && typeof mcp === "object" ? mcp : {};
|
|
72
|
+
const request = plain(m.request_id);
|
|
73
|
+
const connection = typeof m.connection_id === "string" && /^[\w-]{1,128}$/.test(m.connection_id) ? m.connection_id : undefined;
|
|
74
|
+
return {
|
|
75
|
+
via,
|
|
76
|
+
...(kind
|
|
77
|
+
? {
|
|
78
|
+
agent: {
|
|
79
|
+
kind,
|
|
80
|
+
session_id: session,
|
|
81
|
+
...(a?.from_chat === true ? { from_chat: true } : {}),
|
|
82
|
+
...(client
|
|
83
|
+
? { client: { ...client, ...(typeof id === "string" && /^[0-9a-f]{8}$/.test(id) ? { id } : {}) } }
|
|
84
|
+
: {}),
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
: {}),
|
|
88
|
+
mcp: {
|
|
89
|
+
tool,
|
|
90
|
+
...(request ? { request_id: request } : {}),
|
|
91
|
+
...(connection ? { connection_id: connection } : {}),
|
|
92
|
+
proxied: true,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
};
|
package/dist/mcp/http/oauth.js
CHANGED
|
@@ -258,15 +258,19 @@ export const ownerLogin = ({ issuer, resource, file, appName, onCode, now = () =
|
|
|
258
258
|
const verifier = {
|
|
259
259
|
verifyAccessToken: async (presented) => {
|
|
260
260
|
const seconds = Math.floor(now() / 1000);
|
|
261
|
-
const
|
|
261
|
+
const stored = store.read();
|
|
262
|
+
const found = stored.tokens.find((one) => one.kind === "access" && one.hash === hash(presented));
|
|
262
263
|
if (!found || found.expiresAt <= seconds)
|
|
263
264
|
throw new OAuthError(OAuthErrorCode.InvalidToken, "the token is unknown or expired");
|
|
265
|
+
// The name the app registered with, so a run can say which app called; the id itself never leaves here unhashed.
|
|
266
|
+
const clientName = stored.clients.find((one) => one.id === found.clientId)?.name;
|
|
264
267
|
return {
|
|
265
268
|
token: presented,
|
|
266
269
|
clientId: found.clientId,
|
|
267
270
|
scopes: [],
|
|
268
271
|
expiresAt: found.expiresAt,
|
|
269
272
|
resource,
|
|
273
|
+
...(clientName ? { extra: { clientName } } : {}),
|
|
270
274
|
};
|
|
271
275
|
},
|
|
272
276
|
};
|