topchester-ai 0.60.0 → 0.62.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/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as runTopchesterCli } from "./cli-BCDXfYWi.mjs";
2
+ import { t as runTopchesterCli } from "./cli-DfwFfA-w.mjs";
3
3
  //#region src/bin.ts
4
4
  await runTopchesterCli();
5
5
  //#endregion
@@ -6555,6 +6555,37 @@ async function addProjectBashAllowExactRule(workspaceRoot, command) {
6555
6555
  allowExact
6556
6556
  };
6557
6557
  }
6558
+ async function addMcpStdioServerConfig(configPath, options) {
6559
+ const serverName = options.serverName.trim();
6560
+ if (!isValidMcpServerName(serverName)) throw new Error(`invalid MCP server name "${options.serverName}" (use letters, numbers, "-", "_")`);
6561
+ const command = options.command.trim();
6562
+ if (!command) throw new Error("MCP stdio command is required.");
6563
+ const config = readConfigObject(configPath);
6564
+ const mcp = ensurePlainObjectProperty(config, "mcp");
6565
+ const replaced = mcp[serverName] !== void 0;
6566
+ const env = options.env ?? {};
6567
+ const server = {
6568
+ type: "stdio",
6569
+ command,
6570
+ args: options.args ?? [],
6571
+ ...Object.keys(env).length > 0 ? { env } : {}
6572
+ };
6573
+ mcp[serverName] = server;
6574
+ mkdirSync(dirname(configPath), {
6575
+ recursive: true,
6576
+ mode: 448
6577
+ });
6578
+ parseConfigFile(configPath, config);
6579
+ await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`);
6580
+ return {
6581
+ path: configPath,
6582
+ serverName,
6583
+ command,
6584
+ args: server.args,
6585
+ env,
6586
+ replaced
6587
+ };
6588
+ }
6558
6589
  function readProjectConfigObject(configPath) {
6559
6590
  return readConfigObject(configPath);
6560
6591
  }
@@ -6592,6 +6623,9 @@ function ensureStringArrayProperty(parent, key) {
6592
6623
  if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string")) throw new Error(`Invalid Topchester config property '${key}': expected a string array.`);
6593
6624
  return value;
6594
6625
  }
6626
+ function isValidMcpServerName(name) {
6627
+ return name.length > 0 && /^[A-Za-z0-9_-]+$/u.test(name);
6628
+ }
6595
6629
  function readConfigFile(path) {
6596
6630
  try {
6597
6631
  return parseJsonc(readFileSync(path, "utf8"));
@@ -9140,6 +9174,17 @@ const messagePayloadSchema = z.object({
9140
9174
  text: z.string(),
9141
9175
  meta: jsonValueSchema.optional()
9142
9176
  });
9177
+ const permissionAutoApprovedPayloadSchema = z.object({
9178
+ kind: z.literal("permission_auto_approved"),
9179
+ permissionMode: z.literal("bash"),
9180
+ approvalMode: z.literal("auto_allow"),
9181
+ toolName: z.string(),
9182
+ command: z.string(),
9183
+ workdir: z.string(),
9184
+ reason: z.string(),
9185
+ label: z.string(),
9186
+ toolCallId: z.string().optional()
9187
+ });
9143
9188
  const toolCallPayloadSchema = z.object({
9144
9189
  kind: z.literal("tool_call"),
9145
9190
  label: z.string(),
@@ -9217,6 +9262,7 @@ const subagentFailedPayloadSchema = subagentLifecycleBasePayloadSchema.extend({
9217
9262
  });
9218
9263
  const sessionEventPayloadSchema = z.discriminatedUnion("kind", [
9219
9264
  messagePayloadSchema,
9265
+ permissionAutoApprovedPayloadSchema,
9220
9266
  toolCallPayloadSchema,
9221
9267
  hookStatusPayloadSchema,
9222
9268
  taskPlanPayloadSchema,
@@ -9469,6 +9515,7 @@ function rehydrateSession(events) {
9469
9515
  });
9470
9516
  if (event.role === "user") visibleOnlyActionValues = /* @__PURE__ */ new Set();
9471
9517
  break;
9518
+ case "permission_auto_approved": break;
9472
9519
  case "tool_call":
9473
9520
  messages.push(toolCallMessage(event.call, event.label, void 0, event.diff));
9474
9521
  break;
@@ -10192,6 +10239,14 @@ const agentEvent = {
10192
10239
  meta
10193
10240
  };
10194
10241
  },
10242
+ permissionAutoApproved(options) {
10243
+ return {
10244
+ type: "permission_auto_approved",
10245
+ approvalMode: "auto_allow",
10246
+ label: `auto-approved ${options.permissionMode} permission: ${options.command}`,
10247
+ ...options
10248
+ };
10249
+ },
10195
10250
  toolCall(call, label, diff) {
10196
10251
  return diff === void 0 ? {
10197
10252
  type: "tool_call",
@@ -12220,6 +12275,17 @@ function runtimeEventToSessionPayload(event) {
12220
12275
  text: event.text,
12221
12276
  ...event.meta === void 0 ? {} : { meta: event.meta }
12222
12277
  };
12278
+ case "permission_auto_approved": return {
12279
+ kind: "permission_auto_approved",
12280
+ permissionMode: event.permissionMode,
12281
+ approvalMode: event.approvalMode,
12282
+ toolName: event.toolName,
12283
+ command: event.command,
12284
+ workdir: event.workdir,
12285
+ reason: event.reason,
12286
+ label: event.label,
12287
+ ...event.toolCallId === void 0 ? {} : { toolCallId: event.toolCallId }
12288
+ };
12223
12289
  case "tool_call": return {
12224
12290
  kind: "tool_call",
12225
12291
  label: event.label,
@@ -13514,7 +13580,13 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
13514
13580
  approvedCommands,
13515
13581
  events: []
13516
13582
  };
13517
- if (!isBashApprovalRequired(decision) || !options.requestBashApproval) return {
13583
+ if (!isBashApprovalRequired(decision)) return {
13584
+ cancelled: false,
13585
+ approvedCommands,
13586
+ events: []
13587
+ };
13588
+ const approvalMode = options.userApprovalMode ?? "interactive";
13589
+ if (approvalMode !== "auto_allow" && !options.requestBashApproval) return {
13518
13590
  cancelled: false,
13519
13591
  approvedCommands,
13520
13592
  events: []
@@ -13525,7 +13597,11 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
13525
13597
  permission_mode: "bash",
13526
13598
  command,
13527
13599
  workdir: parsed.data.workdir,
13528
- reason: decision.reason
13600
+ reason: decision.reason,
13601
+ ...approvalMode === "auto_allow" ? {
13602
+ approval_mode: "auto_allow",
13603
+ auto_approved: true
13604
+ } : {}
13529
13605
  }), {
13530
13606
  toolName: call.tool,
13531
13607
  abortSignal
@@ -13542,6 +13618,36 @@ var TopchesterAgentRuntime = class TopchesterAgentRuntime {
13542
13618
  reason: actionRequiredHook.blocked.message,
13543
13619
  events
13544
13620
  };
13621
+ if (approvalMode === "auto_allow") {
13622
+ const event = agentEvent.permissionAutoApproved({
13623
+ permissionMode: "bash",
13624
+ toolName: call.tool,
13625
+ ...toolCallId === void 0 ? {} : { toolCallId },
13626
+ command,
13627
+ workdir: parsed.data.workdir,
13628
+ reason: decision.reason
13629
+ });
13630
+ this.context.logger.info({
13631
+ event: "permission_auto_approved",
13632
+ approvalMode: "auto_allow",
13633
+ permissionMode: "bash",
13634
+ toolName: call.tool,
13635
+ toolCallId,
13636
+ command,
13637
+ workdir: parsed.data.workdir,
13638
+ reason: decision.reason
13639
+ }, "permission request auto-approved");
13640
+ return {
13641
+ cancelled: false,
13642
+ approvedCommands: [...approvedCommands, command],
13643
+ events: [...events, event]
13644
+ };
13645
+ }
13646
+ if (!options.requestBashApproval) return {
13647
+ cancelled: false,
13648
+ approvedCommands,
13649
+ events
13650
+ };
13545
13651
  const approval = await options.requestBashApproval({
13546
13652
  command,
13547
13653
  workdir: parsed.data.workdir,
@@ -13704,6 +13810,7 @@ function createInstructionContextEvents(sources, persistedKeys) {
13704
13810
  function renderRuntimeEvent(event) {
13705
13811
  switch (event.type) {
13706
13812
  case "message": return [event.role === "assistant" ? agentMessage(event.text, event.meta) : systemMessage(event.text)];
13813
+ case "permission_auto_approved": return [systemMessage(event.label)];
13707
13814
  case "tool_call": return [toolCallMessage(event.call, event.label, void 0, event.diff)];
13708
13815
  case "hook_status": return [hookStatusMessage(event.label, event.eventName, event.statusMessage)];
13709
13816
  case "knowledge_status": return [systemMessage([`KB status: ${formatKnowledgePathStatus(event.status)}${formatKbPathSource(event.status)}`, event.guidance].filter(Boolean).join("\n"))];
@@ -15238,11 +15345,13 @@ async function executeRunCommand(context, options) {
15238
15345
  promptLength: options.prompt.length,
15239
15346
  json: Boolean(options.json),
15240
15347
  outputJson: options.outputJson,
15241
- timeoutMs
15348
+ timeoutMs,
15349
+ dangerouslyAutoApprove: Boolean(options.dangerouslyAutoApprove)
15242
15350
  }, "run started");
15243
15351
  pushJson(jsonEvents, runId, session.sessionId, "run.started", {
15244
15352
  workspaceRoot: runContext.workspaceRoot,
15245
- timeoutMs
15353
+ timeoutMs,
15354
+ dangerouslyAutoApprove: Boolean(options.dangerouslyAutoApprove)
15246
15355
  });
15247
15356
  try {
15248
15357
  if (!options.resume) await persistStartupMessages(session, runContext);
@@ -15297,7 +15406,10 @@ async function executeRunCommand(context, options) {
15297
15406
  text: options.prompt,
15298
15407
  inputType: "prompt"
15299
15408
  });
15300
- for await (const event of runtime.submitMessageStream(conversation, options.prompt, abortController.signal, { session })) await applyRuntimeEvent({
15409
+ for await (const event of runtime.submitMessageStream(conversation, options.prompt, abortController.signal, {
15410
+ session,
15411
+ userApprovalMode: options.dangerouslyAutoApprove ? "auto_allow" : "interactive"
15412
+ })) await applyRuntimeEvent({
15301
15413
  event,
15302
15414
  session,
15303
15415
  jsonEvents,
@@ -15378,6 +15490,10 @@ function printPlainEvent(event) {
15378
15490
  console.log(event.text);
15379
15491
  return;
15380
15492
  }
15493
+ if (event.type === "permission_auto_approved") {
15494
+ console.log(event.label);
15495
+ return;
15496
+ }
15381
15497
  if (event.type === "tool_call") {
15382
15498
  console.log(event.label);
15383
15499
  return;
@@ -15729,7 +15845,26 @@ function createTopchesterProgram() {
15729
15845
  process.exitCode = 1;
15730
15846
  }
15731
15847
  });
15732
- program.command("run").description("run one prompt or slash command without opening the TUI").argument("<prompt...>", "prompt text or slash command").option("--model <model>", "override the agent.primary model for this run").option("--timeout <ms>", "timeout for the run in milliseconds", parsePositiveInteger).option("--json", "write JSONL run events to stdout").option("--output-json <path>", "write JSONL run events to a file").action(async (promptParts, options) => {
15848
+ program.command("mcp").description("manage MCP servers").command("add").usage("[options] <server-name> -- <stdio server-command>").description("add or replace a stdio MCP server").argument("<server-name>", "server name").argument("<command...>", "stdio server command after --").option("--env <KEY=VALUE>", "environment variable for the server process", collectEnvPair, {}).addHelpText("after", formatMcpAddHelp).action(async (serverName, commandParts, options) => {
15849
+ try {
15850
+ const [command, ...args] = commandParts;
15851
+ if (!command) throw new Error("Usage: topchester mcp add <server-name> -- <stdio server-command>");
15852
+ const result = await addMcpStdioServerConfig(getWritableConfigPathFromProgram(program), {
15853
+ serverName,
15854
+ command,
15855
+ args,
15856
+ env: options.env
15857
+ });
15858
+ console.log(`${result.replaced ? "Updated" : "Added"} MCP stdio server "${result.serverName}".`);
15859
+ console.log(`config: ${result.path}`);
15860
+ console.log(`command: ${[result.command, ...result.args].join(" ")}`);
15861
+ if (Object.keys(result.env).length > 0) console.log(`env: ${Object.keys(result.env).join(", ")}`);
15862
+ } catch (error) {
15863
+ console.error(formatStartupError(error));
15864
+ process.exitCode = 1;
15865
+ }
15866
+ });
15867
+ program.command("run").description("run one prompt or slash command without opening the TUI").argument("<prompt...>", "prompt text or slash command").option("--model <model>", "override the agent.primary model for this run").option("--timeout <ms>", "timeout for the run in milliseconds", parsePositiveInteger).option("--json", "write JSONL run events to stdout").option("--output-json <path>", "write JSONL run events to a file").option("--dangerously-auto-approve", "auto-approve prompt-gated tool calls for this non-interactive run").action(async (promptParts, options) => {
15733
15868
  const context = createContextFromOptions(program);
15734
15869
  const globalOptions = program.opts();
15735
15870
  try {
@@ -15739,7 +15874,8 @@ function createTopchesterProgram() {
15739
15874
  timeoutMs: options.timeout,
15740
15875
  json: options.json,
15741
15876
  outputJson: options.outputJson,
15742
- resume: globalOptions.resume
15877
+ resume: globalOptions.resume,
15878
+ dangerouslyAutoApprove: options.dangerouslyAutoApprove
15743
15879
  });
15744
15880
  } catch (error) {
15745
15881
  console.error(formatStartupError(error));
@@ -15876,6 +16012,17 @@ function formatAuthLoginHelp() {
15876
16012
  " Topchester prints a browser URL and one-time code, waits for approval, then stores tokens in the global auth store."
15877
16013
  ].join("\n");
15878
16014
  }
16015
+ function formatMcpAddHelp() {
16016
+ return [
16017
+ "",
16018
+ ui.label("Examples:"),
16019
+ " topchester mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem .",
16020
+ " topchester mcp add github --env GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx -- npx -y @modelcontextprotocol/server-github",
16021
+ "",
16022
+ ui.label("What happens:"),
16023
+ " Writes to --config when provided, otherwise to the global user config."
16024
+ ].join("\n");
16025
+ }
15879
16026
  function formatAuthLoginUsageError(reason) {
15880
16027
  return [
15881
16028
  ui.error(reason),
@@ -15950,6 +16097,10 @@ function getContextOptionsFromProgram(program) {
15950
16097
  devFlags: options.dev
15951
16098
  };
15952
16099
  }
16100
+ function getWritableConfigPathFromProgram(program) {
16101
+ const options = program.opts();
16102
+ return options.config ? isAbsolute(options.config) ? options.config : resolve(cwd(), options.config) : getGlobalTopchesterConfigPath();
16103
+ }
15953
16104
  async function executeKbSearchCommand(program, queryParts, options) {
15954
16105
  const context = createContextFromOptions(program);
15955
16106
  const query = queryParts.join(" ");
@@ -15983,6 +16134,16 @@ function formatStartupError(error) {
15983
16134
  function collectDevFlag(flag, flags) {
15984
16135
  return [...flags, flag];
15985
16136
  }
16137
+ function collectEnvPair(raw, env) {
16138
+ const separatorIndex = raw.indexOf("=");
16139
+ if (separatorIndex <= 0) throw new Error("Environment entries must be in KEY=VALUE form.");
16140
+ const key = raw.slice(0, separatorIndex).trim();
16141
+ if (!key) throw new Error("Environment entries must be in KEY=VALUE form.");
16142
+ return {
16143
+ ...env,
16144
+ [key]: raw.slice(separatorIndex + 1)
16145
+ };
16146
+ }
15986
16147
  function parsePositiveInteger(value) {
15987
16148
  const parsed = Number(value);
15988
16149
  if (!Number.isInteger(parsed) || parsed <= 0) throw new Error("Expected a positive integer.");
@@ -16004,4 +16165,4 @@ function formatDryRunSyncStatus(status) {
16004
16165
  //#endregion
16005
16166
  export { runTopchesterCli as t };
16006
16167
 
16007
- //# sourceMappingURL=cli-BCDXfYWi.mjs.map
16168
+ //# sourceMappingURL=cli-DfwFfA-w.mjs.map