@aspectlylabs/mikka 0.0.82 → 0.0.84

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/cli.js CHANGED
@@ -3631,7 +3631,13 @@ var runAssignmentSchema = z14.object({
3631
3631
  * it stops working when the run ends. Absent: the server could not issue
3632
3632
  * one, and the run goes ahead without it.
3633
3633
  */
3634
- mcp: z14.object({ url: z14.url(), token: z14.string().min(1).max(200), mailbox: z14.literal(true).optional() }).optional(),
3634
+ mcp: z14.object({
3635
+ url: z14.url(),
3636
+ token: z14.string().min(1).max(200),
3637
+ mailbox: z14.literal(true).optional(),
3638
+ /** Apps (Composio toolkits) this run may use through the Mikka server, one MCP entry each. */
3639
+ apps: z14.array(z14.string().regex(/^[a-z][a-z0-9_]{0,63}$/)).max(64).optional()
3640
+ }).optional(),
3635
3641
  /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
3636
3642
  github: z14.object({
3637
3643
  endpoint: z14.url(),
@@ -4425,7 +4431,7 @@ import { join as join4 } from "node:path";
4425
4431
  // package.json
4426
4432
  var package_default = {
4427
4433
  name: "@mikka/daemon",
4428
- version: "0.0.82",
4434
+ version: "0.0.84",
4429
4435
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4430
4436
  type: "module",
4431
4437
  private: true,
@@ -4484,7 +4490,7 @@ var package_default = {
4484
4490
  engines: {
4485
4491
  node: ">=24"
4486
4492
  },
4487
- gitHead: "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc"
4493
+ gitHead: "c0f9e8eac73c0747211b504fe154f65dfd9b3082"
4488
4494
  };
4489
4495
 
4490
4496
  // src/paths.ts
@@ -4824,7 +4830,7 @@ function classifyWrite(worktree, target) {
4824
4830
  }
4825
4831
 
4826
4832
  // src/agents/tool-approval-policy.ts
4827
- function toolApprovalDecision(request, policy, worktree) {
4833
+ function toolApprovalDecision(request, policy, worktree, apps = []) {
4828
4834
  if (request.method === "sandbox/network" && policy) {
4829
4835
  const value = request.input;
4830
4836
  if (!value || typeof value.host !== "string" || /[*/:]/.test(value.host) || !networkDomainSchema.safeParse(value.host).success || !Number.isInteger(value.port) || Number(value.port) < 1 || Number(value.port) > 65535) return "deny";
@@ -4837,6 +4843,8 @@ function toolApprovalDecision(request, policy, worktree) {
4837
4843
  }
4838
4844
  if (["submit", "request_help", "ask_human", "report_blocked", "submit_capture"].some((name) => tool2 === `mcp__mikka__${name}`)) return "allow";
4839
4845
  if (tool2 === "Bash" || tool2 === "PowerShell") return rawCliShellAvailable(policy) ? "allow" : "unavailable";
4846
+ if (apps.some((name) => tool2.startsWith(`mcp__${name}__`) && tool2.length > `mcp__${name}__`.length)) return "allow";
4847
+ if (tool2 === "WebFetch" || tool2 === "WebSearch") return policy.permissions.network;
4840
4848
  const input = request.input;
4841
4849
  if (["Write", "Edit", "MultiEdit", "NotebookEdit"].includes(tool2)) {
4842
4850
  if (policy.readOnly) return "deny";
@@ -4848,6 +4856,26 @@ function toolApprovalDecision(request, policy, worktree) {
4848
4856
  return "unavailable";
4849
4857
  }
4850
4858
 
4859
+ // src/agents/run-apps.ts
4860
+ var TOOLKIT = /^[a-z][a-z0-9_]{0,63}$/;
4861
+ function runApps(mcp) {
4862
+ if (!mcp?.apps?.length) return void 0;
4863
+ let base;
4864
+ try {
4865
+ base = new URL(mcp.url);
4866
+ } catch {
4867
+ return void 0;
4868
+ }
4869
+ if (!/\/api\/mcp\/?$/.test(base.pathname) || base.username || base.password || base.search || base.hash || base.protocol !== "https:" && !(base.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(base.hostname)) || !/^mkw_[A-Za-z0-9_-]{43}$/.test(mcp.token)) return void 0;
4870
+ const names = [...new Set(mcp.apps)].filter((name) => TOOLKIT.test(name) && !name.startsWith("mikka"));
4871
+ if (!names.length) return void 0;
4872
+ return {
4873
+ token: mcp.token,
4874
+ apps: names.map((name) => ({ name, url: new URL(base.pathname.replace(/\/api\/mcp\/?$/, `/api/runs/mcp/${name}`), base).toString() }))
4875
+ };
4876
+ }
4877
+ var runAppsHost = (apps) => apps?.apps[0] ? new URL(apps.apps[0].url).host : void 0;
4878
+
4851
4879
  // ../protocol/src/capture.ts
4852
4880
  import { z as z23 } from "zod";
4853
4881
  var CAPTURE_CONTENT_TYPES = [
@@ -5165,7 +5193,7 @@ var HttpServerLink = class {
5165
5193
  const response = z26.object({ decision: z26.enum(["pending", "allow", "deny"]) });
5166
5194
  const liveness = new AbortController();
5167
5195
  const gate = new ToolApprovalGate(assignment.runId, {
5168
- permission: (request) => toolApprovalDecision(request, assignment.policy, worktree),
5196
+ permission: (request) => toolApprovalDecision(request, assignment.policy, worktree, runApps(assignment.mcp)?.apps.map((app) => app.name)),
5169
5197
  // Keep the callback pending at the tool boundary. The adapter's current
5170
5198
  // session and checkpoint remain intact; handback resolves this same call.
5171
5199
  isLive: async () => {
@@ -7044,6 +7072,7 @@ var RunContext = class {
7044
7072
  ],
7045
7073
  allowDomains: [
7046
7074
  ...HARNESS_DOMAINS[this.options.harness],
7075
+ ...runAppsHost(this.options.apps) ? [runAppsHost(this.options.apps)] : [],
7047
7076
  ...runDomains(
7048
7077
  runPolicy(this.options.policy),
7049
7078
  [...this.options.networkAllow ?? [], ...this.options.github ? ["github.com", "api.github.com", new URL(this.options.github.endpoint).host] : []]
@@ -7846,11 +7875,11 @@ ${error.message}`;
7846
7875
  }
7847
7876
 
7848
7877
  // src/agents/run-network.ts
7849
- function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint) {
7878
+ function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint, appHost) {
7850
7879
  if (gate.runId !== runId) throw new Error("Run approval scope mismatch");
7851
7880
  if (localComputerEndpoint !== void 0 && (!/^127\.0\.0\.1:[0-9]+$/.test(localComputerEndpoint) || Number(localComputerEndpoint.split(":")[1]) < 1 || Number(localComputerEndpoint.split(":")[1]) > 65535)) throw new Error("Invalid local computer endpoint");
7852
7881
  const ceiling = [...maximum];
7853
- const model = [...HARNESS_DOMAINS[harness]];
7882
+ const model = [...HARNESS_DOMAINS[harness], ...appHost ? [appHost] : []];
7854
7883
  return async (request, signal) => {
7855
7884
  if (signal.aborted || gate.revoked || !matchesRunSandboxDomain(request, ceiling)) return false;
7856
7885
  if (matchesRunSandboxDomain(request, model) || localComputerEndpoint === `${request.host}:${request.port}`) return await gate.checkLive() && !signal.aborted && !gate.revoked;
@@ -7962,6 +7991,9 @@ async function createNativeSubscriptionBroker(host) {
7962
7991
 
7963
7992
  // src/adapters/claude.ts
7964
7993
  var SUBSCRIPTION_ERROR = "Claude subscription authentication unavailable";
7994
+ function claudeAppServers(apps) {
7995
+ return Object.fromEntries((apps?.apps ?? []).map((app) => [app.name, { type: "http", url: app.url, headers: { Authorization: `Bearer ${apps.token}` } }]));
7996
+ }
7965
7997
  function claudeMailboxServer(mailbox) {
7966
7998
  const server = createSdkMcpServer2({ name: "mikka_mailbox", version: "1" });
7967
7999
  for (const [name, schema] of Object.entries(mailboxInputs).filter(([name2]) => mailbox.tools.some((tool2) => tool2.name === name2))) server.instance.registerTool(name, {
@@ -8225,6 +8257,7 @@ var ClaudeAdapter = class {
8225
8257
  if (nativeHome) ownDir(configDir);
8226
8258
  const ctx = new RunContext({
8227
8259
  github: options.github,
8260
+ apps: options.apps,
8228
8261
  githubRuntime: options.githubRuntime,
8229
8262
  childPath: options.env.PATH,
8230
8263
  mailboxEnabled: Boolean(options.mailbox),
@@ -8285,7 +8318,7 @@ var ClaudeAdapter = class {
8285
8318
  const policy = computerSandboxPolicy(ctx.policy(), computerMcp);
8286
8319
  const requested = this.options.networkCeiling;
8287
8320
  const maximum = requested === void 0 ? policy.allowDomains : policy.allowDomains.includes("*") ? [...requested] : requested.includes("*") ? policy.allowDomains : requested.filter((domain) => policy.allowDomains.includes(domain));
8288
- const child = spawnRunSandbox({ command: this.options.binary ?? config.command, args: config.args, cwd: config.cwd ?? ctx.worktree, env: config.env, policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "claude_code", options.toolApproval, maximum, computerDomain(computerMcp)), signal: config.signal, ...nativeToken ? { authToken: nativeToken } : {} });
8321
+ const child = spawnRunSandbox({ command: this.options.binary ?? config.command, args: config.args, cwd: config.cwd ?? ctx.worktree, env: config.env, policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "claude_code", options.toolApproval, maximum, computerDomain(computerMcp), runAppsHost(options.apps)), signal: config.signal, ...nativeToken ? { authToken: nativeToken } : {} });
8289
8322
  const off = options.toolApproval.onRevoke(() => {
8290
8323
  void child.revoke().catch(() => void 0);
8291
8324
  });
@@ -8318,7 +8351,8 @@ var ClaudeAdapter = class {
8318
8351
  mcpServers: {
8319
8352
  ...options.mailbox ? { mikka_mailbox: claudeMailboxServer(options.mailbox) } : {},
8320
8353
  [MCP_SERVER_NAME]: { type: "stdio", ...ctx.mcpServer() },
8321
- ...computerMcp ? { [COMPUTER_MCP_SERVER_NAME]: { type: "stdio", ...computerMcp } } : {}
8354
+ ...computerMcp ? { [COMPUTER_MCP_SERVER_NAME]: { type: "stdio", ...computerMcp } } : {},
8355
+ ...claudeAppServers(options.apps)
8322
8356
  },
8323
8357
  strictMcpConfig: true,
8324
8358
  systemPrompt: {
@@ -8499,6 +8533,14 @@ function subscriptionTokens(value, accountId) {
8499
8533
  };
8500
8534
  }
8501
8535
  var CODEX_HISTORY = ["sessions", "archived_sessions", "session_index.jsonl"];
8536
+ function codexAppArgs(apps) {
8537
+ return (apps?.apps ?? []).flatMap((app) => [
8538
+ "-c",
8539
+ `mcp_servers.${app.name}.url=${toml(app.url)}`,
8540
+ "-c",
8541
+ `mcp_servers.${app.name}.http_headers={ Authorization = ${toml(`Bearer ${apps.token}`)} }`
8542
+ ]);
8543
+ }
8502
8544
  function toml(value) {
8503
8545
  return JSON.stringify(value);
8504
8546
  }
@@ -8667,6 +8709,7 @@ var CodexAdapter = class {
8667
8709
  );
8668
8710
  const ctx = new RunContext({
8669
8711
  github: options.github,
8712
+ apps: options.apps,
8670
8713
  githubRuntime: options.githubRuntime,
8671
8714
  childPath: options.env.PATH,
8672
8715
  mailboxEnabled: Boolean(options.mailbox),
@@ -8712,6 +8755,7 @@ var CodexAdapter = class {
8712
8755
  ] : [],
8713
8756
  ...Object.entries(computerMcp.env).flatMap(([key2, value]) => ["-c", `mcp_servers.${COMPUTER_MCP_SERVER_NAME}.env.${key2}=${toml(value)}`])
8714
8757
  ] : [],
8758
+ ...codexAppArgs(options.apps),
8715
8759
  // Its shells get a filtered env; give them writable temp dirs.
8716
8760
  ...Object.entries(ctx.tempEnv()).flatMap(([key2, value]) => [
8717
8761
  "-c",
@@ -8729,7 +8773,7 @@ var CodexAdapter = class {
8729
8773
  const requestedCeiling = this.options.networkCeiling;
8730
8774
  const maximum = requestedCeiling === void 0 ? spawnOptions.policy.allowDomains : spawnOptions.policy.allowDomains.includes("*") ? [...requestedCeiling] : requestedCeiling.includes("*") ? spawnOptions.policy.allowDomains : requestedCeiling.filter((domain) => spawnOptions.policy.allowDomains.includes(domain));
8731
8775
  let launcher;
8732
- const child = this.options.spawnCli || this.options.sandbox.kind === "none" ? await (this.options.spawnCli ?? spawnCli)(this.options.sandbox, argv, spawnOptions) : launcher = spawnRunSandbox({ command: argv[0], args: argv.slice(1), cwd: spawnOptions.cwd, env: spawnOptions.env, policy: spawnOptions.policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "codex", options.toolApproval, maximum, computerDomain(computerMcp)) });
8776
+ const child = this.options.spawnCli || this.options.sandbox.kind === "none" ? await (this.options.spawnCli ?? spawnCli)(this.options.sandbox, argv, spawnOptions) : launcher = spawnRunSandbox({ command: argv[0], args: argv.slice(1), cwd: spawnOptions.cwd, env: spawnOptions.env, policy: spawnOptions.policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "codex", options.toolApproval, maximum, computerDomain(computerMcp), runAppsHost(options.apps)) });
8733
8777
  if (launcher) {
8734
8778
  const ownedLauncher = launcher;
8735
8779
  const off = options.toolApproval.onRevoke(() => {
@@ -8752,7 +8796,7 @@ var CodexAdapter = class {
8752
8796
  let lastError;
8753
8797
  let usage = { inputTokens: 0, outputTokens: 0 };
8754
8798
  const pendingMcp = /* @__PURE__ */ new Map();
8755
- const registeredMcpTool = (server, tool2) => server === MCP_SERVER_NAME && ["submit", "request_help", "ask_human", "report_blocked"].includes(tool2) || Boolean(computerMcp) && server === COMPUTER_MCP_SERVER_NAME && ["get_desktop_state", "click", "type_text", "press_key", "scroll"].includes(tool2);
8799
+ const registeredMcpTool = (server, tool2) => server === MCP_SERVER_NAME && ["submit", "request_help", "ask_human", "report_blocked"].includes(tool2) || Boolean(computerMcp) && server === COMPUTER_MCP_SERVER_NAME && ["get_desktop_state", "click", "type_text", "press_key", "scroll"].includes(tool2) || Boolean(options.apps?.apps.some((app) => app.name === server));
8756
8800
  let ended;
8757
8801
  const finish = (event) => {
8758
8802
  if (ended) return ended;
@@ -12826,6 +12870,7 @@ var RunSupervisor = class {
12826
12870
  }
12827
12871
  const options = {
12828
12872
  github: assignment.github && assignment.mcp && (assignment.kind === "implement" || assignment.kind === "fix") && !runPolicy(assignment.policy).readOnly ? { ...assignment.github, runToken: assignment.mcp.token, issueId: assignment.issueId } : void 0,
12873
+ apps: runApps(assignment.mcp),
12829
12874
  toolApproval,
12830
12875
  runId,
12831
12876
  requireSessionResume: assignment.requireSessionResume,
package/client.js CHANGED
@@ -3012,7 +3012,13 @@ var runAssignmentSchema = z14.object({
3012
3012
  * it stops working when the run ends. Absent: the server could not issue
3013
3013
  * one, and the run goes ahead without it.
3014
3014
  */
3015
- mcp: z14.object({ url: z14.url(), token: z14.string().min(1).max(200), mailbox: z14.literal(true).optional() }).optional(),
3015
+ mcp: z14.object({
3016
+ url: z14.url(),
3017
+ token: z14.string().min(1).max(200),
3018
+ mailbox: z14.literal(true).optional(),
3019
+ /** Apps (Composio toolkits) this run may use through the Mikka server, one MCP entry each. */
3020
+ apps: z14.array(z14.string().regex(/^[a-z][a-z0-9_]{0,63}$/)).max(64).optional()
3021
+ }).optional(),
3016
3022
  /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
3017
3023
  github: z14.object({
3018
3024
  endpoint: z14.url(),
@@ -3687,7 +3693,7 @@ import { join } from "node:path";
3687
3693
  // package.json
3688
3694
  var package_default = {
3689
3695
  name: "@mikka/daemon",
3690
- version: "0.0.82",
3696
+ version: "0.0.84",
3691
3697
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3692
3698
  type: "module",
3693
3699
  private: true,
@@ -3746,7 +3752,7 @@ var package_default = {
3746
3752
  engines: {
3747
3753
  node: ">=24"
3748
3754
  },
3749
- gitHead: "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc"
3755
+ gitHead: "c0f9e8eac73c0747211b504fe154f65dfd9b3082"
3750
3756
  };
3751
3757
 
3752
3758
  // src/paths.ts
package/http-link.js CHANGED
@@ -2411,7 +2411,7 @@ function classifyWrite(worktree, target) {
2411
2411
  }
2412
2412
 
2413
2413
  // src/agents/tool-approval-policy.ts
2414
- function toolApprovalDecision(request, policy, worktree) {
2414
+ function toolApprovalDecision(request, policy, worktree, apps = []) {
2415
2415
  if (request.method === "sandbox/network" && policy) {
2416
2416
  const value = request.input;
2417
2417
  if (!value || typeof value.host !== "string" || /[*/:]/.test(value.host) || !networkDomainSchema.safeParse(value.host).success || !Number.isInteger(value.port) || Number(value.port) < 1 || Number(value.port) > 65535) return "deny";
@@ -2424,6 +2424,8 @@ function toolApprovalDecision(request, policy, worktree) {
2424
2424
  }
2425
2425
  if (["submit", "request_help", "ask_human", "report_blocked", "submit_capture"].some((name) => tool === `mcp__mikka__${name}`)) return "allow";
2426
2426
  if (tool === "Bash" || tool === "PowerShell") return rawCliShellAvailable(policy) ? "allow" : "unavailable";
2427
+ if (apps.some((name) => tool.startsWith(`mcp__${name}__`) && tool.length > `mcp__${name}__`.length)) return "allow";
2428
+ if (tool === "WebFetch" || tool === "WebSearch") return policy.permissions.network;
2427
2429
  const input = request.input;
2428
2430
  if (["Write", "Edit", "MultiEdit", "NotebookEdit"].includes(tool)) {
2429
2431
  if (policy.readOnly) return "deny";
@@ -2435,6 +2437,25 @@ function toolApprovalDecision(request, policy, worktree) {
2435
2437
  return "unavailable";
2436
2438
  }
2437
2439
 
2440
+ // src/agents/run-apps.ts
2441
+ var TOOLKIT = /^[a-z][a-z0-9_]{0,63}$/;
2442
+ function runApps(mcp) {
2443
+ if (!mcp?.apps?.length) return void 0;
2444
+ let base;
2445
+ try {
2446
+ base = new URL(mcp.url);
2447
+ } catch {
2448
+ return void 0;
2449
+ }
2450
+ if (!/\/api\/mcp\/?$/.test(base.pathname) || base.username || base.password || base.search || base.hash || base.protocol !== "https:" && !(base.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(base.hostname)) || !/^mkw_[A-Za-z0-9_-]{43}$/.test(mcp.token)) return void 0;
2451
+ const names = [...new Set(mcp.apps)].filter((name) => TOOLKIT.test(name) && !name.startsWith("mikka"));
2452
+ if (!names.length) return void 0;
2453
+ return {
2454
+ token: mcp.token,
2455
+ apps: names.map((name) => ({ name, url: new URL(base.pathname.replace(/\/api\/mcp\/?$/, `/api/runs/mcp/${name}`), base).toString() }))
2456
+ };
2457
+ }
2458
+
2438
2459
  // ../protocol/src/skill.ts
2439
2460
  import { z as z5 } from "zod";
2440
2461
 
@@ -3499,7 +3520,13 @@ var runAssignmentSchema = z18.object({
3499
3520
  * it stops working when the run ends. Absent: the server could not issue
3500
3521
  * one, and the run goes ahead without it.
3501
3522
  */
3502
- mcp: z18.object({ url: z18.url(), token: z18.string().min(1).max(200), mailbox: z18.literal(true).optional() }).optional(),
3523
+ mcp: z18.object({
3524
+ url: z18.url(),
3525
+ token: z18.string().min(1).max(200),
3526
+ mailbox: z18.literal(true).optional(),
3527
+ /** Apps (Composio toolkits) this run may use through the Mikka server, one MCP entry each. */
3528
+ apps: z18.array(z18.string().regex(/^[a-z][a-z0-9_]{0,63}$/)).max(64).optional()
3529
+ }).optional(),
3503
3530
  /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
3504
3531
  github: z18.object({
3505
3532
  endpoint: z18.url(),
@@ -4065,7 +4092,7 @@ var InvalidIdError = class extends DaemonError {
4065
4092
  // package.json
4066
4093
  var package_default = {
4067
4094
  name: "@mikka/daemon",
4068
- version: "0.0.82",
4095
+ version: "0.0.84",
4069
4096
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4070
4097
  type: "module",
4071
4098
  private: true,
@@ -4124,7 +4151,7 @@ var package_default = {
4124
4151
  engines: {
4125
4152
  node: ">=24"
4126
4153
  },
4127
- gitHead: "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc"
4154
+ gitHead: "c0f9e8eac73c0747211b504fe154f65dfd9b3082"
4128
4155
  };
4129
4156
 
4130
4157
  // src/paths.ts
@@ -4349,7 +4376,7 @@ var HttpServerLink = class {
4349
4376
  const response = z26.object({ decision: z26.enum(["pending", "allow", "deny"]) });
4350
4377
  const liveness = new AbortController();
4351
4378
  const gate = new ToolApprovalGate(assignment.runId, {
4352
- permission: (request) => toolApprovalDecision(request, assignment.policy, worktree),
4379
+ permission: (request) => toolApprovalDecision(request, assignment.policy, worktree, runApps(assignment.mcp)?.apps.map((app) => app.name)),
4353
4380
  // Keep the callback pending at the tool boundary. The adapter's current
4354
4381
  // session and checkpoint remain intact; handback resolves this same call.
4355
4382
  isLive: async () => {
package/login.js CHANGED
@@ -3008,7 +3008,13 @@ var runAssignmentSchema = z14.object({
3008
3008
  * it stops working when the run ends. Absent: the server could not issue
3009
3009
  * one, and the run goes ahead without it.
3010
3010
  */
3011
- mcp: z14.object({ url: z14.url(), token: z14.string().min(1).max(200), mailbox: z14.literal(true).optional() }).optional(),
3011
+ mcp: z14.object({
3012
+ url: z14.url(),
3013
+ token: z14.string().min(1).max(200),
3014
+ mailbox: z14.literal(true).optional(),
3015
+ /** Apps (Composio toolkits) this run may use through the Mikka server, one MCP entry each. */
3016
+ apps: z14.array(z14.string().regex(/^[a-z][a-z0-9_]{0,63}$/)).max(64).optional()
3017
+ }).optional(),
3012
3018
  /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
3013
3019
  github: z14.object({
3014
3020
  endpoint: z14.url(),
@@ -3694,7 +3700,7 @@ var ServerUnreachableError = class extends DaemonError {
3694
3700
  // package.json
3695
3701
  var package_default = {
3696
3702
  name: "@mikka/daemon",
3697
- version: "0.0.82",
3703
+ version: "0.0.84",
3698
3704
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3699
3705
  type: "module",
3700
3706
  private: true,
@@ -3753,7 +3759,7 @@ var package_default = {
3753
3759
  engines: {
3754
3760
  node: ">=24"
3755
3761
  },
3756
- gitHead: "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc"
3762
+ gitHead: "c0f9e8eac73c0747211b504fe154f65dfd9b3082"
3757
3763
  };
3758
3764
 
3759
3765
  // src/paths.ts
package/main.js CHANGED
@@ -3335,6 +3335,26 @@ async function agentPublishedReceipt(input) {
3335
3335
  }
3336
3336
  }
3337
3337
 
3338
+ // src/agents/run-apps.ts
3339
+ var TOOLKIT = /^[a-z][a-z0-9_]{0,63}$/;
3340
+ function runApps(mcp) {
3341
+ if (!mcp?.apps?.length) return void 0;
3342
+ let base;
3343
+ try {
3344
+ base = new URL(mcp.url);
3345
+ } catch {
3346
+ return void 0;
3347
+ }
3348
+ if (!/\/api\/mcp\/?$/.test(base.pathname) || base.username || base.password || base.search || base.hash || base.protocol !== "https:" && !(base.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(base.hostname)) || !/^mkw_[A-Za-z0-9_-]{43}$/.test(mcp.token)) return void 0;
3349
+ const names = [...new Set(mcp.apps)].filter((name) => TOOLKIT.test(name) && !name.startsWith("mikka"));
3350
+ if (!names.length) return void 0;
3351
+ return {
3352
+ token: mcp.token,
3353
+ apps: names.map((name) => ({ name, url: new URL(base.pathname.replace(/\/api\/mcp\/?$/, `/api/runs/mcp/${name}`), base).toString() }))
3354
+ };
3355
+ }
3356
+ var runAppsHost = (apps) => apps?.apps[0] ? new URL(apps.apps[0].url).host : void 0;
3357
+
3338
3358
  // src/agents/run-context.ts
3339
3359
  import { execFileSync } from "node:child_process";
3340
3360
  import {
@@ -3728,7 +3748,7 @@ import { join as join5 } from "node:path";
3728
3748
  // package.json
3729
3749
  var package_default = {
3730
3750
  name: "@mikka/daemon",
3731
- version: "0.0.82",
3751
+ version: "0.0.84",
3732
3752
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
3733
3753
  type: "module",
3734
3754
  private: true,
@@ -3787,7 +3807,7 @@ var package_default = {
3787
3807
  engines: {
3788
3808
  node: ">=24"
3789
3809
  },
3790
- gitHead: "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc"
3810
+ gitHead: "c0f9e8eac73c0747211b504fe154f65dfd9b3082"
3791
3811
  };
3792
3812
 
3793
3813
  // src/paths.ts
@@ -4721,7 +4741,13 @@ var runAssignmentSchema = z15.object({
4721
4741
  * it stops working when the run ends. Absent: the server could not issue
4722
4742
  * one, and the run goes ahead without it.
4723
4743
  */
4724
- mcp: z15.object({ url: z15.url(), token: z15.string().min(1).max(200), mailbox: z15.literal(true).optional() }).optional(),
4744
+ mcp: z15.object({
4745
+ url: z15.url(),
4746
+ token: z15.string().min(1).max(200),
4747
+ mailbox: z15.literal(true).optional(),
4748
+ /** Apps (Composio toolkits) this run may use through the Mikka server, one MCP entry each. */
4749
+ apps: z15.array(z15.string().regex(/^[a-z][a-z0-9_]{0,63}$/)).max(64).optional()
4750
+ }).optional(),
4725
4751
  /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
4726
4752
  github: z15.object({
4727
4753
  endpoint: z15.url(),
@@ -5836,6 +5862,7 @@ var RunContext = class {
5836
5862
  ],
5837
5863
  allowDomains: [
5838
5864
  ...HARNESS_DOMAINS[this.options.harness],
5865
+ ...runAppsHost(this.options.apps) ? [runAppsHost(this.options.apps)] : [],
5839
5866
  ...runDomains(
5840
5867
  runPolicy(this.options.policy),
5841
5868
  [...this.options.networkAllow ?? [], ...this.options.github ? ["github.com", "api.github.com", new URL(this.options.github.endpoint).host] : []]
@@ -6644,11 +6671,11 @@ ${error.message}`;
6644
6671
  }
6645
6672
 
6646
6673
  // src/agents/run-network.ts
6647
- function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint) {
6674
+ function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint, appHost) {
6648
6675
  if (gate.runId !== runId) throw new Error("Run approval scope mismatch");
6649
6676
  if (localComputerEndpoint !== void 0 && (!/^127\.0\.0\.1:[0-9]+$/.test(localComputerEndpoint) || Number(localComputerEndpoint.split(":")[1]) < 1 || Number(localComputerEndpoint.split(":")[1]) > 65535)) throw new Error("Invalid local computer endpoint");
6650
6677
  const ceiling = [...maximum];
6651
- const model = [...HARNESS_DOMAINS[harness]];
6678
+ const model = [...HARNESS_DOMAINS[harness], ...appHost ? [appHost] : []];
6652
6679
  return async (request, signal) => {
6653
6680
  if (signal.aborted || gate.revoked || !matchesRunSandboxDomain(request, ceiling)) return false;
6654
6681
  if (matchesRunSandboxDomain(request, model) || localComputerEndpoint === `${request.host}:${request.port}`) return await gate.checkLive() && !signal.aborted && !gate.revoked;
@@ -6789,6 +6816,9 @@ async function createNativeSubscriptionBroker(host) {
6789
6816
 
6790
6817
  // src/adapters/claude.ts
6791
6818
  var SUBSCRIPTION_ERROR = "Claude subscription authentication unavailable";
6819
+ function claudeAppServers(apps) {
6820
+ return Object.fromEntries((apps?.apps ?? []).map((app) => [app.name, { type: "http", url: app.url, headers: { Authorization: `Bearer ${apps.token}` } }]));
6821
+ }
6792
6822
  function claudeMailboxServer(mailbox) {
6793
6823
  const server = createSdkMcpServer2({ name: "mikka_mailbox", version: "1" });
6794
6824
  for (const [name, schema] of Object.entries(mailboxInputs).filter(([name2]) => mailbox.tools.some((tool2) => tool2.name === name2))) server.instance.registerTool(name, {
@@ -7052,6 +7082,7 @@ var ClaudeAdapter = class {
7052
7082
  if (nativeHome) ownDir(configDir);
7053
7083
  const ctx = new RunContext({
7054
7084
  github: options.github,
7085
+ apps: options.apps,
7055
7086
  githubRuntime: options.githubRuntime,
7056
7087
  childPath: options.env.PATH,
7057
7088
  mailboxEnabled: Boolean(options.mailbox),
@@ -7112,7 +7143,7 @@ var ClaudeAdapter = class {
7112
7143
  const policy = computerSandboxPolicy(ctx.policy(), computerMcp);
7113
7144
  const requested = this.options.networkCeiling;
7114
7145
  const maximum = requested === void 0 ? policy.allowDomains : policy.allowDomains.includes("*") ? [...requested] : requested.includes("*") ? policy.allowDomains : requested.filter((domain) => policy.allowDomains.includes(domain));
7115
- const child = spawnRunSandbox({ command: this.options.binary ?? config.command, args: config.args, cwd: config.cwd ?? ctx.worktree, env: config.env, policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "claude_code", options.toolApproval, maximum, computerDomain(computerMcp)), signal: config.signal, ...nativeToken ? { authToken: nativeToken } : {} });
7146
+ const child = spawnRunSandbox({ command: this.options.binary ?? config.command, args: config.args, cwd: config.cwd ?? ctx.worktree, env: config.env, policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "claude_code", options.toolApproval, maximum, computerDomain(computerMcp), runAppsHost(options.apps)), signal: config.signal, ...nativeToken ? { authToken: nativeToken } : {} });
7116
7147
  const off = options.toolApproval.onRevoke(() => {
7117
7148
  void child.revoke().catch(() => void 0);
7118
7149
  });
@@ -7145,7 +7176,8 @@ var ClaudeAdapter = class {
7145
7176
  mcpServers: {
7146
7177
  ...options.mailbox ? { mikka_mailbox: claudeMailboxServer(options.mailbox) } : {},
7147
7178
  [MCP_SERVER_NAME]: { type: "stdio", ...ctx.mcpServer() },
7148
- ...computerMcp ? { [COMPUTER_MCP_SERVER_NAME]: { type: "stdio", ...computerMcp } } : {}
7179
+ ...computerMcp ? { [COMPUTER_MCP_SERVER_NAME]: { type: "stdio", ...computerMcp } } : {},
7180
+ ...claudeAppServers(options.apps)
7149
7181
  },
7150
7182
  strictMcpConfig: true,
7151
7183
  systemPrompt: {
@@ -7326,6 +7358,14 @@ function subscriptionTokens(value, accountId) {
7326
7358
  };
7327
7359
  }
7328
7360
  var CODEX_HISTORY = ["sessions", "archived_sessions", "session_index.jsonl"];
7361
+ function codexAppArgs(apps) {
7362
+ return (apps?.apps ?? []).flatMap((app) => [
7363
+ "-c",
7364
+ `mcp_servers.${app.name}.url=${toml(app.url)}`,
7365
+ "-c",
7366
+ `mcp_servers.${app.name}.http_headers={ Authorization = ${toml(`Bearer ${apps.token}`)} }`
7367
+ ]);
7368
+ }
7329
7369
  function toml(value) {
7330
7370
  return JSON.stringify(value);
7331
7371
  }
@@ -7494,6 +7534,7 @@ var CodexAdapter = class {
7494
7534
  );
7495
7535
  const ctx = new RunContext({
7496
7536
  github: options.github,
7537
+ apps: options.apps,
7497
7538
  githubRuntime: options.githubRuntime,
7498
7539
  childPath: options.env.PATH,
7499
7540
  mailboxEnabled: Boolean(options.mailbox),
@@ -7539,6 +7580,7 @@ var CodexAdapter = class {
7539
7580
  ] : [],
7540
7581
  ...Object.entries(computerMcp.env).flatMap(([key2, value]) => ["-c", `mcp_servers.${COMPUTER_MCP_SERVER_NAME}.env.${key2}=${toml(value)}`])
7541
7582
  ] : [],
7583
+ ...codexAppArgs(options.apps),
7542
7584
  // Its shells get a filtered env; give them writable temp dirs.
7543
7585
  ...Object.entries(ctx.tempEnv()).flatMap(([key2, value]) => [
7544
7586
  "-c",
@@ -7556,7 +7598,7 @@ var CodexAdapter = class {
7556
7598
  const requestedCeiling = this.options.networkCeiling;
7557
7599
  const maximum = requestedCeiling === void 0 ? spawnOptions.policy.allowDomains : spawnOptions.policy.allowDomains.includes("*") ? [...requestedCeiling] : requestedCeiling.includes("*") ? spawnOptions.policy.allowDomains : requestedCeiling.filter((domain) => spawnOptions.policy.allowDomains.includes(domain));
7558
7600
  let launcher;
7559
- const child = this.options.spawnCli || this.options.sandbox.kind === "none" ? await (this.options.spawnCli ?? spawnCli)(this.options.sandbox, argv, spawnOptions) : launcher = spawnRunSandbox({ command: argv[0], args: argv.slice(1), cwd: spawnOptions.cwd, env: spawnOptions.env, policy: spawnOptions.policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "codex", options.toolApproval, maximum, computerDomain(computerMcp)) });
7601
+ const child = this.options.spawnCli || this.options.sandbox.kind === "none" ? await (this.options.spawnCli ?? spawnCli)(this.options.sandbox, argv, spawnOptions) : launcher = spawnRunSandbox({ command: argv[0], args: argv.slice(1), cwd: spawnOptions.cwd, env: spawnOptions.env, policy: spawnOptions.policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "codex", options.toolApproval, maximum, computerDomain(computerMcp), runAppsHost(options.apps)) });
7560
7602
  if (launcher) {
7561
7603
  const ownedLauncher = launcher;
7562
7604
  const off = options.toolApproval.onRevoke(() => {
@@ -7579,7 +7621,7 @@ var CodexAdapter = class {
7579
7621
  let lastError;
7580
7622
  let usage = { inputTokens: 0, outputTokens: 0 };
7581
7623
  const pendingMcp = /* @__PURE__ */ new Map();
7582
- const registeredMcpTool = (server, tool2) => server === MCP_SERVER_NAME && ["submit", "request_help", "ask_human", "report_blocked"].includes(tool2) || Boolean(computerMcp) && server === COMPUTER_MCP_SERVER_NAME && ["get_desktop_state", "click", "type_text", "press_key", "scroll"].includes(tool2);
7624
+ const registeredMcpTool = (server, tool2) => server === MCP_SERVER_NAME && ["submit", "request_help", "ask_human", "report_blocked"].includes(tool2) || Boolean(computerMcp) && server === COMPUTER_MCP_SERVER_NAME && ["get_desktop_state", "click", "type_text", "press_key", "scroll"].includes(tool2) || Boolean(options.apps?.apps.some((app) => app.name === server));
7583
7625
  let ended;
7584
7626
  const finish = (event) => {
7585
7627
  if (ended) return ended;
@@ -11894,6 +11936,7 @@ var RunSupervisor = class {
11894
11936
  }
11895
11937
  const options = {
11896
11938
  github: assignment.github && assignment.mcp && (assignment.kind === "implement" || assignment.kind === "fix") && !runPolicy(assignment.policy).readOnly ? { ...assignment.github, runToken: assignment.mcp.token, issueId: assignment.issueId } : void 0,
11939
+ apps: runApps(assignment.mcp),
11897
11940
  toolApproval,
11898
11941
  runId,
11899
11942
  requireSessionResume: assignment.requireSessionResume,
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "version": 1,
3
- "sourceSha": "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc",
3
+ "sourceSha": "c0f9e8eac73c0747211b504fe154f65dfd9b3082",
4
4
  "repository": "alexj11324/Mikka",
5
- "buildRunId": "41235331563",
5
+ "buildRunId": "41237598294",
6
6
  "buildKind": "github-actions-main",
7
7
  "sourceLockSha256": "333de14ab33e455ec8a3a699f59b49d7a125caebb37d557cc6cfa5024f0c15f7",
8
- "createdAt": "2026-10-31T19:42:29.825Z",
8
+ "createdAt": "2026-10-31T20:11:38.645Z",
9
9
  "sbom": "sbom.cdx.json",
10
10
  "files": [
11
11
  {
@@ -35,13 +35,13 @@
35
35
  },
36
36
  {
37
37
  "path": "cli.js",
38
- "size": 621856,
39
- "sha256": "ff406de2f66e83777d8320ae6fd516ca3500ca00db6ff0a8d0b5841ea83156c5"
38
+ "size": 624106,
39
+ "sha256": "4b7394188ed96a234f17681cf47a29fc074b8d9346c53a6cdd48d93692dca8d2"
40
40
  },
41
41
  {
42
42
  "path": "client.js",
43
- "size": 138369,
44
- "sha256": "7dc81e62163ec91dc4860ed03e1ab711f3e7d44734e02990c5d00fba2974c485"
43
+ "size": 138568,
44
+ "sha256": "c557e3ef82bfefdf8e1bd560b31657ad47c8291944ae8ce5c2fd7af9615911ea"
45
45
  },
46
46
  {
47
47
  "path": "computer/driver.mjs",
@@ -145,8 +145,8 @@
145
145
  },
146
146
  {
147
147
  "path": "http-link.js",
148
- "size": 178124,
149
- "sha256": "41f94a8aac301414461700f48278ab42b43212c2241dda53fd6c945b66aeac95"
148
+ "size": 179427,
149
+ "sha256": "08c9992dde744f8859f9e6810055b0ff414a826ea79c1a4a9cd37829d0a978e9"
150
150
  },
151
151
  {
152
152
  "path": "log.js",
@@ -155,13 +155,13 @@
155
155
  },
156
156
  {
157
157
  "path": "login.js",
158
- "size": 142938,
159
- "sha256": "d8c63004f28a91e1aa27fc3ea84804144bd712fc32cc754f8af710dd917ea30b"
158
+ "size": 143137,
159
+ "sha256": "d705d5181fe37d36e4e7c6e7a66589f878592f10e073551446422f4ecc9ed1e2"
160
160
  },
161
161
  {
162
162
  "path": "main.js",
163
- "size": 567990,
164
- "sha256": "d05ee42d76de2851cacb09e9cded96b2f80d9e07a459b15aeeb4874c5127bed9"
163
+ "size": 569962,
164
+ "sha256": "7ce65cd4243adc1f26b0d060d7578357cbeb41950b3a4748f3decf43bd30c01d"
165
165
  },
166
166
  {
167
167
  "path": "mikka-mcp.mjs",
@@ -170,23 +170,23 @@
170
170
  },
171
171
  {
172
172
  "path": "mikka.js",
173
- "size": 621872,
174
- "sha256": "ed217f527322c8dfe5ed80fe46552b003cb90aa8c590bc133ecc530ba7edcc62"
173
+ "size": 624122,
174
+ "sha256": "bd4bfd1c9d51095e095e580782ef63544f7f3a2f067b6e36f893a87b24ed7917"
175
175
  },
176
176
  {
177
177
  "path": "npm-shrinkwrap.json",
178
178
  "size": 78115,
179
- "sha256": "02428ba917cd4934e40b317a8e4cfd3970b1adfd663db1d113155f1393c5cc9c"
179
+ "sha256": "fb853a81752c910860acadda27290dc605253be0ced337b4497268f648dcbb2e"
180
180
  },
181
181
  {
182
182
  "path": "package.json",
183
183
  "size": 1246,
184
- "sha256": "2e6a3c8a41eb394578e07dc8715b912c2f3853b45bc4f1153b3c842a76a9d844"
184
+ "sha256": "0ce2c96ce161393a5241fa0940d505337db8bb6a7f920baf2a98f79f567c8a83"
185
185
  },
186
186
  {
187
187
  "path": "paths.js",
188
188
  "size": 3914,
189
- "sha256": "82f2406ed3bd7e521ce9a0fb03061ebf1b6ac82f702e814b680414b412a84ce8"
189
+ "sha256": "a74d181cffa978c7089484f3a8cf15283ec45beeeeee88dfcd526bafc18685b4"
190
190
  },
191
191
  {
192
192
  "path": "sandbox.js",
@@ -196,7 +196,7 @@
196
196
  {
197
197
  "path": "sbom.cdx.json",
198
198
  "size": 144310,
199
- "sha256": "b5145136d73c9778b0a8bae31e36e659bd96280eb069ed99e11ca7655b68563a"
199
+ "sha256": "31c261ab1c6335fb5509e8a16de2aaece282dc38d8e75d191f2b0d5ab5f2acd2"
200
200
  }
201
201
  ]
202
202
  }
package/mikka.js CHANGED
@@ -3632,7 +3632,13 @@ var runAssignmentSchema = z14.object({
3632
3632
  * it stops working when the run ends. Absent: the server could not issue
3633
3633
  * one, and the run goes ahead without it.
3634
3634
  */
3635
- mcp: z14.object({ url: z14.url(), token: z14.string().min(1).max(200), mailbox: z14.literal(true).optional() }).optional(),
3635
+ mcp: z14.object({
3636
+ url: z14.url(),
3637
+ token: z14.string().min(1).max(200),
3638
+ mailbox: z14.literal(true).optional(),
3639
+ /** Apps (Composio toolkits) this run may use through the Mikka server, one MCP entry each. */
3640
+ apps: z14.array(z14.string().regex(/^[a-z][a-z0-9_]{0,63}$/)).max(64).optional()
3641
+ }).optional(),
3636
3642
  /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
3637
3643
  github: z14.object({
3638
3644
  endpoint: z14.url(),
@@ -4426,7 +4432,7 @@ import { join as join4 } from "node:path";
4426
4432
  // package.json
4427
4433
  var package_default = {
4428
4434
  name: "@mikka/daemon",
4429
- version: "0.0.82",
4435
+ version: "0.0.84",
4430
4436
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4431
4437
  type: "module",
4432
4438
  private: true,
@@ -4485,7 +4491,7 @@ var package_default = {
4485
4491
  engines: {
4486
4492
  node: ">=24"
4487
4493
  },
4488
- gitHead: "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc"
4494
+ gitHead: "c0f9e8eac73c0747211b504fe154f65dfd9b3082"
4489
4495
  };
4490
4496
 
4491
4497
  // src/paths.ts
@@ -4825,7 +4831,7 @@ function classifyWrite(worktree, target) {
4825
4831
  }
4826
4832
 
4827
4833
  // src/agents/tool-approval-policy.ts
4828
- function toolApprovalDecision(request, policy, worktree) {
4834
+ function toolApprovalDecision(request, policy, worktree, apps = []) {
4829
4835
  if (request.method === "sandbox/network" && policy) {
4830
4836
  const value = request.input;
4831
4837
  if (!value || typeof value.host !== "string" || /[*/:]/.test(value.host) || !networkDomainSchema.safeParse(value.host).success || !Number.isInteger(value.port) || Number(value.port) < 1 || Number(value.port) > 65535) return "deny";
@@ -4838,6 +4844,8 @@ function toolApprovalDecision(request, policy, worktree) {
4838
4844
  }
4839
4845
  if (["submit", "request_help", "ask_human", "report_blocked", "submit_capture"].some((name) => tool2 === `mcp__mikka__${name}`)) return "allow";
4840
4846
  if (tool2 === "Bash" || tool2 === "PowerShell") return rawCliShellAvailable(policy) ? "allow" : "unavailable";
4847
+ if (apps.some((name) => tool2.startsWith(`mcp__${name}__`) && tool2.length > `mcp__${name}__`.length)) return "allow";
4848
+ if (tool2 === "WebFetch" || tool2 === "WebSearch") return policy.permissions.network;
4841
4849
  const input = request.input;
4842
4850
  if (["Write", "Edit", "MultiEdit", "NotebookEdit"].includes(tool2)) {
4843
4851
  if (policy.readOnly) return "deny";
@@ -4849,6 +4857,26 @@ function toolApprovalDecision(request, policy, worktree) {
4849
4857
  return "unavailable";
4850
4858
  }
4851
4859
 
4860
+ // src/agents/run-apps.ts
4861
+ var TOOLKIT = /^[a-z][a-z0-9_]{0,63}$/;
4862
+ function runApps(mcp) {
4863
+ if (!mcp?.apps?.length) return void 0;
4864
+ let base;
4865
+ try {
4866
+ base = new URL(mcp.url);
4867
+ } catch {
4868
+ return void 0;
4869
+ }
4870
+ if (!/\/api\/mcp\/?$/.test(base.pathname) || base.username || base.password || base.search || base.hash || base.protocol !== "https:" && !(base.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(base.hostname)) || !/^mkw_[A-Za-z0-9_-]{43}$/.test(mcp.token)) return void 0;
4871
+ const names = [...new Set(mcp.apps)].filter((name) => TOOLKIT.test(name) && !name.startsWith("mikka"));
4872
+ if (!names.length) return void 0;
4873
+ return {
4874
+ token: mcp.token,
4875
+ apps: names.map((name) => ({ name, url: new URL(base.pathname.replace(/\/api\/mcp\/?$/, `/api/runs/mcp/${name}`), base).toString() }))
4876
+ };
4877
+ }
4878
+ var runAppsHost = (apps) => apps?.apps[0] ? new URL(apps.apps[0].url).host : void 0;
4879
+
4852
4880
  // ../protocol/src/capture.ts
4853
4881
  import { z as z23 } from "zod";
4854
4882
  var CAPTURE_CONTENT_TYPES = [
@@ -5166,7 +5194,7 @@ var HttpServerLink = class {
5166
5194
  const response = z26.object({ decision: z26.enum(["pending", "allow", "deny"]) });
5167
5195
  const liveness = new AbortController();
5168
5196
  const gate = new ToolApprovalGate(assignment.runId, {
5169
- permission: (request) => toolApprovalDecision(request, assignment.policy, worktree),
5197
+ permission: (request) => toolApprovalDecision(request, assignment.policy, worktree, runApps(assignment.mcp)?.apps.map((app) => app.name)),
5170
5198
  // Keep the callback pending at the tool boundary. The adapter's current
5171
5199
  // session and checkpoint remain intact; handback resolves this same call.
5172
5200
  isLive: async () => {
@@ -7045,6 +7073,7 @@ var RunContext = class {
7045
7073
  ],
7046
7074
  allowDomains: [
7047
7075
  ...HARNESS_DOMAINS[this.options.harness],
7076
+ ...runAppsHost(this.options.apps) ? [runAppsHost(this.options.apps)] : [],
7048
7077
  ...runDomains(
7049
7078
  runPolicy(this.options.policy),
7050
7079
  [...this.options.networkAllow ?? [], ...this.options.github ? ["github.com", "api.github.com", new URL(this.options.github.endpoint).host] : []]
@@ -7847,11 +7876,11 @@ ${error.message}`;
7847
7876
  }
7848
7877
 
7849
7878
  // src/agents/run-network.ts
7850
- function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint) {
7879
+ function runNetworkApproval(runId, harness, gate, maximum, localComputerEndpoint, appHost) {
7851
7880
  if (gate.runId !== runId) throw new Error("Run approval scope mismatch");
7852
7881
  if (localComputerEndpoint !== void 0 && (!/^127\.0\.0\.1:[0-9]+$/.test(localComputerEndpoint) || Number(localComputerEndpoint.split(":")[1]) < 1 || Number(localComputerEndpoint.split(":")[1]) > 65535)) throw new Error("Invalid local computer endpoint");
7853
7882
  const ceiling = [...maximum];
7854
- const model = [...HARNESS_DOMAINS[harness]];
7883
+ const model = [...HARNESS_DOMAINS[harness], ...appHost ? [appHost] : []];
7855
7884
  return async (request, signal) => {
7856
7885
  if (signal.aborted || gate.revoked || !matchesRunSandboxDomain(request, ceiling)) return false;
7857
7886
  if (matchesRunSandboxDomain(request, model) || localComputerEndpoint === `${request.host}:${request.port}`) return await gate.checkLive() && !signal.aborted && !gate.revoked;
@@ -7963,6 +7992,9 @@ async function createNativeSubscriptionBroker(host) {
7963
7992
 
7964
7993
  // src/adapters/claude.ts
7965
7994
  var SUBSCRIPTION_ERROR = "Claude subscription authentication unavailable";
7995
+ function claudeAppServers(apps) {
7996
+ return Object.fromEntries((apps?.apps ?? []).map((app) => [app.name, { type: "http", url: app.url, headers: { Authorization: `Bearer ${apps.token}` } }]));
7997
+ }
7966
7998
  function claudeMailboxServer(mailbox) {
7967
7999
  const server = createSdkMcpServer2({ name: "mikka_mailbox", version: "1" });
7968
8000
  for (const [name, schema] of Object.entries(mailboxInputs).filter(([name2]) => mailbox.tools.some((tool2) => tool2.name === name2))) server.instance.registerTool(name, {
@@ -8226,6 +8258,7 @@ var ClaudeAdapter = class {
8226
8258
  if (nativeHome) ownDir(configDir);
8227
8259
  const ctx = new RunContext({
8228
8260
  github: options.github,
8261
+ apps: options.apps,
8229
8262
  githubRuntime: options.githubRuntime,
8230
8263
  childPath: options.env.PATH,
8231
8264
  mailboxEnabled: Boolean(options.mailbox),
@@ -8286,7 +8319,7 @@ var ClaudeAdapter = class {
8286
8319
  const policy = computerSandboxPolicy(ctx.policy(), computerMcp);
8287
8320
  const requested = this.options.networkCeiling;
8288
8321
  const maximum = requested === void 0 ? policy.allowDomains : policy.allowDomains.includes("*") ? [...requested] : requested.includes("*") ? policy.allowDomains : requested.filter((domain) => policy.allowDomains.includes(domain));
8289
- const child = spawnRunSandbox({ command: this.options.binary ?? config.command, args: config.args, cwd: config.cwd ?? ctx.worktree, env: config.env, policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "claude_code", options.toolApproval, maximum, computerDomain(computerMcp)), signal: config.signal, ...nativeToken ? { authToken: nativeToken } : {} });
8322
+ const child = spawnRunSandbox({ command: this.options.binary ?? config.command, args: config.args, cwd: config.cwd ?? ctx.worktree, env: config.env, policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "claude_code", options.toolApproval, maximum, computerDomain(computerMcp), runAppsHost(options.apps)), signal: config.signal, ...nativeToken ? { authToken: nativeToken } : {} });
8290
8323
  const off = options.toolApproval.onRevoke(() => {
8291
8324
  void child.revoke().catch(() => void 0);
8292
8325
  });
@@ -8319,7 +8352,8 @@ var ClaudeAdapter = class {
8319
8352
  mcpServers: {
8320
8353
  ...options.mailbox ? { mikka_mailbox: claudeMailboxServer(options.mailbox) } : {},
8321
8354
  [MCP_SERVER_NAME]: { type: "stdio", ...ctx.mcpServer() },
8322
- ...computerMcp ? { [COMPUTER_MCP_SERVER_NAME]: { type: "stdio", ...computerMcp } } : {}
8355
+ ...computerMcp ? { [COMPUTER_MCP_SERVER_NAME]: { type: "stdio", ...computerMcp } } : {},
8356
+ ...claudeAppServers(options.apps)
8323
8357
  },
8324
8358
  strictMcpConfig: true,
8325
8359
  systemPrompt: {
@@ -8500,6 +8534,14 @@ function subscriptionTokens(value, accountId) {
8500
8534
  };
8501
8535
  }
8502
8536
  var CODEX_HISTORY = ["sessions", "archived_sessions", "session_index.jsonl"];
8537
+ function codexAppArgs(apps) {
8538
+ return (apps?.apps ?? []).flatMap((app) => [
8539
+ "-c",
8540
+ `mcp_servers.${app.name}.url=${toml(app.url)}`,
8541
+ "-c",
8542
+ `mcp_servers.${app.name}.http_headers={ Authorization = ${toml(`Bearer ${apps.token}`)} }`
8543
+ ]);
8544
+ }
8503
8545
  function toml(value) {
8504
8546
  return JSON.stringify(value);
8505
8547
  }
@@ -8668,6 +8710,7 @@ var CodexAdapter = class {
8668
8710
  );
8669
8711
  const ctx = new RunContext({
8670
8712
  github: options.github,
8713
+ apps: options.apps,
8671
8714
  githubRuntime: options.githubRuntime,
8672
8715
  childPath: options.env.PATH,
8673
8716
  mailboxEnabled: Boolean(options.mailbox),
@@ -8713,6 +8756,7 @@ var CodexAdapter = class {
8713
8756
  ] : [],
8714
8757
  ...Object.entries(computerMcp.env).flatMap(([key2, value]) => ["-c", `mcp_servers.${COMPUTER_MCP_SERVER_NAME}.env.${key2}=${toml(value)}`])
8715
8758
  ] : [],
8759
+ ...codexAppArgs(options.apps),
8716
8760
  // Its shells get a filtered env; give them writable temp dirs.
8717
8761
  ...Object.entries(ctx.tempEnv()).flatMap(([key2, value]) => [
8718
8762
  "-c",
@@ -8730,7 +8774,7 @@ var CodexAdapter = class {
8730
8774
  const requestedCeiling = this.options.networkCeiling;
8731
8775
  const maximum = requestedCeiling === void 0 ? spawnOptions.policy.allowDomains : spawnOptions.policy.allowDomains.includes("*") ? [...requestedCeiling] : requestedCeiling.includes("*") ? spawnOptions.policy.allowDomains : requestedCeiling.filter((domain) => spawnOptions.policy.allowDomains.includes(domain));
8732
8776
  let launcher;
8733
- const child = this.options.spawnCli || this.options.sandbox.kind === "none" ? await (this.options.spawnCli ?? spawnCli)(this.options.sandbox, argv, spawnOptions) : launcher = spawnRunSandbox({ command: argv[0], args: argv.slice(1), cwd: spawnOptions.cwd, env: spawnOptions.env, policy: spawnOptions.policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "codex", options.toolApproval, maximum, computerDomain(computerMcp)) });
8777
+ const child = this.options.spawnCli || this.options.sandbox.kind === "none" ? await (this.options.spawnCli ?? spawnCli)(this.options.sandbox, argv, spawnOptions) : launcher = spawnRunSandbox({ command: argv[0], args: argv.slice(1), cwd: spawnOptions.cwd, env: spawnOptions.env, policy: spawnOptions.policy, maxAllowDomains: maximum, onNetwork: runNetworkApproval(options.runId, "codex", options.toolApproval, maximum, computerDomain(computerMcp), runAppsHost(options.apps)) });
8734
8778
  if (launcher) {
8735
8779
  const ownedLauncher = launcher;
8736
8780
  const off = options.toolApproval.onRevoke(() => {
@@ -8753,7 +8797,7 @@ var CodexAdapter = class {
8753
8797
  let lastError;
8754
8798
  let usage = { inputTokens: 0, outputTokens: 0 };
8755
8799
  const pendingMcp = /* @__PURE__ */ new Map();
8756
- const registeredMcpTool = (server, tool2) => server === MCP_SERVER_NAME && ["submit", "request_help", "ask_human", "report_blocked"].includes(tool2) || Boolean(computerMcp) && server === COMPUTER_MCP_SERVER_NAME && ["get_desktop_state", "click", "type_text", "press_key", "scroll"].includes(tool2);
8800
+ const registeredMcpTool = (server, tool2) => server === MCP_SERVER_NAME && ["submit", "request_help", "ask_human", "report_blocked"].includes(tool2) || Boolean(computerMcp) && server === COMPUTER_MCP_SERVER_NAME && ["get_desktop_state", "click", "type_text", "press_key", "scroll"].includes(tool2) || Boolean(options.apps?.apps.some((app) => app.name === server));
8757
8801
  let ended;
8758
8802
  const finish = (event) => {
8759
8803
  if (ended) return ended;
@@ -12827,6 +12871,7 @@ var RunSupervisor = class {
12827
12871
  }
12828
12872
  const options = {
12829
12873
  github: assignment.github && assignment.mcp && (assignment.kind === "implement" || assignment.kind === "fix") && !runPolicy(assignment.policy).readOnly ? { ...assignment.github, runToken: assignment.mcp.token, issueId: assignment.issueId } : void 0,
12874
+ apps: runApps(assignment.mcp),
12830
12875
  toolApproval,
12831
12876
  runId,
12832
12877
  requireSessionResume: assignment.requireSessionResume,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@aspectlylabs/mikka",
3
- "version": "0.0.82",
3
+ "version": "0.0.84",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@aspectlylabs/mikka",
9
- "version": "0.0.82",
9
+ "version": "0.0.84",
10
10
  "license": "AGPL-3.0-only",
11
11
  "dependencies": {
12
12
  "@agentclientprotocol/sdk": "1.9.0",
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@aspectlylabs/mikka",
3
- "version": "0.0.82",
3
+ "version": "0.0.84",
4
4
  "description": "Local Mikka daemon: runs agents through the user's own CLIs",
5
- "gitHead": "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc",
5
+ "gitHead": "c0f9e8eac73c0747211b504fe154f65dfd9b3082",
6
6
  "type": "module",
7
7
  "private": false,
8
8
  "license": "AGPL-3.0-only",
package/paths.js CHANGED
@@ -6,7 +6,7 @@ import { join } from "node:path";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@mikka/daemon",
9
- version: "0.0.82",
9
+ version: "0.0.84",
10
10
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
11
11
  type: "module",
12
12
  private: true,
@@ -65,7 +65,7 @@ var package_default = {
65
65
  engines: {
66
66
  node: ">=24"
67
67
  },
68
- gitHead: "2e77d3a51ade3932b2260dd115c8931f5a6a7cbc"
68
+ gitHead: "c0f9e8eac73c0747211b504fe154f65dfd9b3082"
69
69
  };
70
70
 
71
71
  // src/paths.ts
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:843fcfbc-0b74-4ade-ad5c-4aebcbd4af86",
5
+ "serialNumber": "urn:uuid:404e3aaa-40c5-4b39-8322-b453c4964dff",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-10-31T19:42:29.025Z",
8
+ "timestamp": "2026-10-31T20:11:37.982Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "pre-build"
@@ -19,13 +19,13 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@aspectlylabs/mikka@0.0.82",
22
+ "bom-ref": "@aspectlylabs/mikka@0.0.84",
23
23
  "type": "library",
24
- "name": ".retained-build-6pTAzZ",
25
- "version": "0.0.82",
24
+ "name": ".retained-build-QGbSoL",
25
+ "version": "0.0.84",
26
26
  "scope": "required",
27
27
  "description": "Local Mikka daemon: runs agents through the user's own CLIs",
28
- "purl": "pkg:npm/%40aspectlylabs/mikka@0.0.82",
28
+ "purl": "pkg:npm/%40aspectlylabs/mikka@0.0.84",
29
29
  "properties": [],
30
30
  "externalReferences": [
31
31
  {
@@ -4627,7 +4627,7 @@
4627
4627
  ],
4628
4628
  "dependencies": [
4629
4629
  {
4630
- "ref": "@aspectlylabs/mikka@0.0.82",
4630
+ "ref": "@aspectlylabs/mikka@0.0.84",
4631
4631
  "dependsOn": [
4632
4632
  "@agentclientprotocol/sdk@1.9.0",
4633
4633
  "@anthropic-ai/claude-agent-sdk@0.3.305",