@p4code/cli 0.1.21 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/bin.mjs +229 -37
  2. package/dist/client/assets/{DiffPanel-2Gqo7b0N.js → DiffPanel-Cdf69_RS.js} +2 -2
  3. package/dist/client/assets/{FilePreviewPanel-Po3D7bHa.js → FilePreviewPanel-CkKXCbcG.js} +2 -2
  4. package/dist/client/assets/{PreviewPanel-ebSBxbsf.js → PreviewPanel-BtqdQqtN.js} +2 -2
  5. package/dist/client/assets/{angular-html-BhHAxMde.js → angular-html-BPHFZwgm.js} +2 -2
  6. package/dist/client/assets/{angular-ts-CxZFyQM4.js → angular-ts-CXoIeuGh.js} +2 -2
  7. package/dist/client/assets/{apl-D8rOr4fH.js → apl-C6oPUNZZ.js} +2 -2
  8. package/dist/client/assets/arrow-right-7YX6fLbL.js +2 -0
  9. package/dist/client/assets/{astro-DYSYdOU9.js → astro-Bq_n5uKv.js} +2 -2
  10. package/dist/client/assets/{blade-DaHnYPa_.js → blade-DYe65h_C.js} +2 -2
  11. package/dist/client/assets/{c-oRWOBveW.js → c-BsDji_bt.js} +2 -2
  12. package/dist/client/assets/{cobol-Djebq6RA.js → cobol-CoC31Rpg.js} +2 -2
  13. package/dist/client/assets/{coffee-CKhxS88r.js → coffee-DU1_O9cH.js} +2 -2
  14. package/dist/client/assets/{cpp-BjVgWq1h.js → cpp-D5_eYHZr.js} +2 -2
  15. package/dist/client/assets/{crystal-DXzIaEKx.js → crystal-3iIyvfhL.js} +2 -2
  16. package/dist/client/assets/{css-7AulbBAq.js → css-B4bpFXEv.js} +2 -2
  17. package/dist/client/assets/{edge-B3VgcX6t.js → edge--YoYp8s_.js} +2 -2
  18. package/dist/client/assets/{elixir-DGUU7Wwf.js → elixir-CZ1wqlQn.js} +2 -2
  19. package/dist/client/assets/{elm-B9tr8qBJ.js → elm-DKdyYY92.js} +2 -2
  20. package/dist/client/assets/{erb-BgSl2c_f.js → erb-PeUqy_9N.js} +2 -2
  21. package/dist/client/assets/{fileCommentAnnotations-C06ZwrTh.js → fileCommentAnnotations-BTb-0nj3.js} +2 -2
  22. package/dist/client/assets/{git-rebase-CJMhrhmS.js → git-rebase-1Z5OxWid.js} +2 -2
  23. package/dist/client/assets/{glimmer-js-Dzf5VMSx.js → glimmer-js-Br0y4u5b.js} +2 -2
  24. package/dist/client/assets/{glimmer-ts-CHD8gl5-.js → glimmer-ts-Oh0AMNJv.js} +2 -2
  25. package/dist/client/assets/{glsl-CDpKClnF.js → glsl-DI6kM2gF.js} +2 -2
  26. package/dist/client/assets/{graphql-DX6Ul3G5.js → graphql-VCSJCQkl.js} +2 -2
  27. package/dist/client/assets/{hack-NU-7p0gC.js → hack-4xJQMtbZ.js} +2 -2
  28. package/dist/client/assets/{haml-Cf7Y-ZgP.js → haml-Bc0kPVkr.js} +2 -2
  29. package/dist/client/assets/{handlebars-BOvzNDfr.js → handlebars-Znb8TzWA.js} +2 -2
  30. package/dist/client/assets/{html-CokKN6Uo.js → html-_Zw71zQT.js} +2 -2
  31. package/dist/client/assets/{html-derivative-CcTOncd6.js → html-derivative-D6Fn1mLE.js} +2 -2
  32. package/dist/client/assets/{http-CGr88I6S.js → http-CSdnm1Wh.js} +2 -2
  33. package/dist/client/assets/{hurl-BfdIF20D.js → hurl-DKOuNoWT.js} +2 -2
  34. package/dist/client/assets/{index-BwGqPoA8.js → index-CeztlSXj.js} +13 -7
  35. package/dist/client/assets/{java-DjcrYPKU.js → java-Czo4Dn1f.js} +2 -2
  36. package/dist/client/assets/{javascript-C1msiELJ.js → javascript-fyReKHSS.js} +2 -2
  37. package/dist/client/assets/{jinja-BP-z74Sl.js → jinja-CvJhR5Z5.js} +2 -2
  38. package/dist/client/assets/{jison-DTU_ib6_.js → jison-DSlj1sEU.js} +2 -2
  39. package/dist/client/assets/{json-n2oR8huX.js → json-fCB7n2pX.js} +2 -2
  40. package/dist/client/assets/{jsx-DLc8ZGPF.js → jsx-C1OJlXdb.js} +2 -2
  41. package/dist/client/assets/{julia-BFtTfktg.js → julia-CmLSMgqX.js} +2 -2
  42. package/dist/client/assets/{just-CBZfmiGm.js → just-D9KdTXpD.js} +2 -2
  43. package/dist/client/assets/{latex-B9jcgQKp.js → latex-BZoE-Z3X.js} +2 -2
  44. package/dist/client/assets/{liquid-D-PCb97a.js → liquid-DW5UrT3Q.js} +2 -2
  45. package/dist/client/assets/{lua-CeAbwjz7.js → lua-DMAjig-8.js} +2 -2
  46. package/dist/client/assets/{marko-D2oCpzm8.js → marko-EN2dMS-t.js} +2 -2
  47. package/dist/client/assets/{mdc-BN4ff7dr.js → mdc-DV5R0Zdp.js} +2 -2
  48. package/dist/client/assets/{nginx-TigpgX3q.js → nginx-BhF2pPjp.js} +2 -2
  49. package/dist/client/assets/{nim-BbkIxZP5.js → nim-Ck0oR8VY.js} +2 -2
  50. package/dist/client/assets/{perl-Dq3UNlmA.js → perl-B4V1RSOt.js} +2 -2
  51. package/dist/client/assets/{php-CDBbIDUr.js → php-BvwSzqRH.js} +2 -2
  52. package/dist/client/assets/{pug-X1om8_0C.js → pug-DB3guzOM.js} +2 -2
  53. package/dist/client/assets/{qml-C_aweCjl.js → qml-CohVRZGq.js} +2 -2
  54. package/dist/client/assets/{r-BH02pZo7.js → r-Doi-hRR2.js} +2 -2
  55. package/dist/client/assets/{razor-DFd9duVt.js → razor-CtBV-RZa.js} +2 -2
  56. package/dist/client/assets/{regexp-BYgWQcZZ.js → regexp-DgF6jh6T.js} +2 -2
  57. package/dist/client/assets/{rst-DS4ajG1_.js → rst-1GlNPFb8.js} +2 -2
  58. package/dist/client/assets/{ruby-rrP3E-yX.js → ruby-C_Jg-W0j.js} +2 -2
  59. package/dist/client/assets/{sas-qOp3AbMp.js → sas-IRPqQRQC.js} +2 -2
  60. package/dist/client/assets/{scss-BePdknOf.js → scss-BPKDbfld.js} +2 -2
  61. package/dist/client/assets/{shellscript-Di7DOIUv.js → shellscript-D5KbVhsx.js} +2 -2
  62. package/dist/client/assets/{shellsession-DS-qEJoT.js → shellsession-bEniUyPe.js} +2 -2
  63. package/dist/client/assets/{soy-CT_pCK5o.js → soy-D0Pcy9LW.js} +2 -2
  64. package/dist/client/assets/{sql-CVynNG6j.js → sql-DF2TL966.js} +2 -2
  65. package/dist/client/assets/{stata-B2fKxQHN.js → stata-BLI2BTCU.js} +2 -2
  66. package/dist/client/assets/{surrealql-BOcosx9e.js → surrealql-BjtO5tmi.js} +2 -2
  67. package/dist/client/assets/{svelte-BQBQ3ysY.js → svelte-IyvKNOcX.js} +2 -2
  68. package/dist/client/assets/{templ-cinsfbYE.js → templ-qRJlnfHP.js} +2 -2
  69. package/dist/client/assets/{tex-PiJ0CI8J.js → tex-CgYv5ALc.js} +2 -2
  70. package/dist/client/assets/{textarea-DV6gvhvo.js → textarea-B03Qe3NX.js} +2 -2
  71. package/dist/client/assets/{ts-tags-jRjqE2jk.js → ts-tags-YasuuPCT.js} +2 -2
  72. package/dist/client/assets/{tsx-DqzTbomV.js → tsx-BF7eypTR.js} +2 -2
  73. package/dist/client/assets/{twig-5U1Vd9zl.js → twig-BF-FIMTp.js} +2 -2
  74. package/dist/client/assets/{typescript-DmYNCX8k.js → typescript-CtOBCMI7.js} +2 -2
  75. package/dist/client/assets/{vue-BOE7yHne.js → vue-BTbCYZab.js} +2 -2
  76. package/dist/client/assets/{vue-html-roHe5KnN.js → vue-html-1KQNz6IV.js} +2 -2
  77. package/dist/client/assets/{vue-vine-YC-R0SEx.js → vue-vine-BVHOJ5oI.js} +2 -2
  78. package/dist/client/assets/{xml-B-QQaugn.js → xml-CftlzqvG.js} +2 -2
  79. package/dist/client/assets/{xsl-CyPKxPW7.js → xsl-DoQ9dHRM.js} +2 -2
  80. package/dist/client/assets/{yaml-Bq2pe1E4.js → yaml-DMUX1MAF.js} +2 -2
  81. package/dist/client/index.html +2 -2
  82. package/package.json +1 -1
  83. package/dist/client/assets/arrow-right-Dseaz2v4.js +0 -2
package/dist/bin.mjs CHANGED
@@ -233,7 +233,7 @@ const make$76 = () => {
233
233
  const layer$72 = Layer.sync(NetService, make$76);
234
234
  //#endregion
235
235
  //#region package.json
236
- var version = "0.1.21";
236
+ var version = "0.1.22";
237
237
  //#endregion
238
238
  //#region src/config.ts
239
239
  /**
@@ -7858,11 +7858,21 @@ var ProjectWriteFileError = class extends Schema$1.TaggedErrorClass()("ProjectWr
7858
7858
  * is a URL as often as an id, and which tracker a bare `MOBILE-12262` belongs
7859
7859
  * to is a question only the resolver can answer.
7860
7860
  */
7861
- const TicketResolveInput = Schema$1.Struct({ reference: TrimmedNonEmptyString });
7861
+ const TicketResolveInput = Schema$1.Struct({ reference: TrimmedNonEmptyString.pipe(Schema$1.annotateEncoded({ description: "The ticket as it was written: an identifier like MOBILE-12241, or a tracker URL. Pass it through verbatim rather than reformatting it." })) });
7862
7862
  const TicketResolveResult = Schema$1.Struct({
7863
7863
  externalRef: TaskExternalRef,
7864
7864
  /** The issue title as the tracker reports it, for the task that mirrors it. */
7865
- title: TrimmedNonEmptyString
7865
+ title: TrimmedNonEmptyString,
7866
+ /**
7867
+ * The issue body, when the tracker reports one.
7868
+ *
7869
+ * Optional because it is the one field here that has a legitimate empty
7870
+ * value - plenty of tickets are a title and nothing else - and because the
7871
+ * composer, which only ever renders a chip, does not read it. It is carried
7872
+ * for the caller that does: an agent handed a ticket id needs the
7873
+ * requirements, and the title alone sends it back to ask for them.
7874
+ */
7875
+ description: Schema$1.optional(TrimmedNonEmptyString)
7866
7876
  });
7867
7877
  /**
7868
7878
  * Why a reference could not be turned into a ticket.
@@ -34864,6 +34874,7 @@ const TASK_PLAN_TOOL_NAMES = /* @__PURE__ */ new Set([
34864
34874
  "task_get",
34865
34875
  "task_current",
34866
34876
  "task_propose",
34877
+ "ticket_resolve",
34867
34878
  "taskcreate",
34868
34879
  "taskupdate",
34869
34880
  "tasklist",
@@ -36571,13 +36582,16 @@ const make$36 = Effect.gen(function* () {
36571
36582
  reason: "not_found",
36572
36583
  detail: `Linear returned nothing usable for ${identifier}.`
36573
36584
  });
36585
+ const externalRef = {
36586
+ source: "linear",
36587
+ identifier: stringField$1(issue, "identifier") ?? identifier,
36588
+ url
36589
+ };
36590
+ const description = stringField$1(issue, "description");
36574
36591
  return {
36575
- externalRef: {
36576
- source: "linear",
36577
- identifier: stringField$1(issue, "identifier") ?? identifier,
36578
- url
36579
- },
36580
- title
36592
+ externalRef,
36593
+ title,
36594
+ ...description === void 0 ? {} : { description }
36581
36595
  };
36582
36596
  }) };
36583
36597
  });
@@ -47727,6 +47741,18 @@ const ProviderEventLoggersLive = Layer.effect(ProviderEventLoggers, Effect.gen(f
47727
47741
  var ProviderService = class extends Context.Service()("@p4code/cli/provider/Services/ProviderService") {};
47728
47742
  //#endregion
47729
47743
  //#region src/mcp/McpProviderSession.ts
47744
+ /**
47745
+ * The name p4code declares its own toolkit under, in every provider.
47746
+ *
47747
+ * One constant because it is one name in the agent's world: prompts, skills and
47748
+ * the tool categories all say `p4-code`, whichever runtime is reading them.
47749
+ * Every adapter also excludes it from the user's registered servers, so a
47750
+ * registration of the same name cannot displace the built-in one and take the
47751
+ * per-thread credential's tools (`task_current`, `thread_*`) with it.
47752
+ */
47753
+ const P4CODE_MCP_SERVER_NAME = "p4-code";
47754
+ /** The reserved names, as the set the mappers take. */
47755
+ const P4CODE_MCP_SERVER_NAMES = /* @__PURE__ */ new Set([P4CODE_MCP_SERVER_NAME]);
47730
47756
  const sessionsByThread = /* @__PURE__ */ new Map();
47731
47757
  function setMcpProviderSession(config) {
47732
47758
  sessionsByThread.set(config.threadId, config);
@@ -71563,6 +71589,81 @@ const SERVER_NOTIFICATION_PARAMS = {
71563
71589
  "account/login/completed": V2AccountLoginCompletedNotification
71564
71590
  };
71565
71591
  //#endregion
71592
+ //#region src/provider/Layers/codexMcpArgs.ts
71593
+ /** Codex's own name for the token variable of p4code's built-in server. */
71594
+ const CODEX_P4CODE_BEARER_TOKEN_ENV_VAR = "P4_MCP_BEARER_TOKEN";
71595
+ /** Prefix for the per-server variables the registered servers get. */
71596
+ const BEARER_TOKEN_ENV_VAR_PREFIX = "P4_MCP_BEARER_TOKEN_";
71597
+ /** TOML bare keys; anything else has to be quoted inside the dotted path. */
71598
+ const BARE_KEY = /^[A-Za-z0-9_-]+$/;
71599
+ const AUTHORIZATION_HEADER = "authorization";
71600
+ const BEARER_PREFIX = /^Bearer\s+/;
71601
+ const configKey = (name, field) => `mcp_servers.${BARE_KEY.test(name) ? name : JSON.stringify(name)}.${field}`;
71602
+ /**
71603
+ * A variable name derived from the server's, uniquely.
71604
+ *
71605
+ * Uppercased with every character a shell would not accept replaced, which can
71606
+ * collide (`a.b` and `a-b`), so the sanitized name is the prefix and the index
71607
+ * keeps it unique. The index is stable within one call, which is all that is
71608
+ * needed: the variable and the reference to it are emitted together.
71609
+ */
71610
+ const bearerTokenEnvVar = (name, index) => `${BEARER_TOKEN_ENV_VAR_PREFIX}${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_${index}`;
71611
+ /**
71612
+ * @param resolved - Servers keyed by name, as the registry resolved them.
71613
+ * @param exclude - Names p4code declares itself. A registration cannot displace
71614
+ * the built-in `p4-code` server, whose per-thread credential is the only
71615
+ * thing that makes `task_current` and the thread tools work.
71616
+ */
71617
+ const toCodexMcpConfig = (resolved, exclude = /* @__PURE__ */ new Set()) => {
71618
+ const args = [];
71619
+ const env = {};
71620
+ const skipped = [];
71621
+ const push = (name, field, value) => {
71622
+ args.push("-c", `${configKey(name, field)}=${value}`);
71623
+ };
71624
+ let index = 0;
71625
+ for (const [name, server] of Object.entries(resolved)) {
71626
+ if (exclude.has(name)) continue;
71627
+ if (server.type === "stdio") {
71628
+ push(name, "command", JSON.stringify(server.command));
71629
+ push(name, "args", JSON.stringify(server.args));
71630
+ if (Object.keys(server.env).length > 0) push(name, "env", `{ ${Object.entries(server.env).map(([key, value]) => `${JSON.stringify(key)} = ${JSON.stringify(value)}`).join(", ")} }`);
71631
+ index += 1;
71632
+ continue;
71633
+ }
71634
+ if (server.type === "sse") {
71635
+ skipped.push({
71636
+ name,
71637
+ reason: "Codex speaks streamable HTTP, not SSE."
71638
+ });
71639
+ continue;
71640
+ }
71641
+ const headerNames = Object.keys(server.headers);
71642
+ const authorization = headerNames.find((key) => key.toLowerCase() === AUTHORIZATION_HEADER);
71643
+ const otherHeaders = headerNames.filter((key) => key !== authorization);
71644
+ if (otherHeaders.length > 0) {
71645
+ skipped.push({
71646
+ name,
71647
+ reason: `Codex sends no custom headers, and this server needs ${otherHeaders.join(", ")}.`
71648
+ });
71649
+ continue;
71650
+ }
71651
+ push(name, "url", JSON.stringify(server.url));
71652
+ if (authorization !== void 0) {
71653
+ const token = server.headers[authorization]?.replace(BEARER_PREFIX, "") ?? "";
71654
+ const variable = bearerTokenEnvVar(name, index);
71655
+ env[variable] = token;
71656
+ push(name, "bearer_token_env_var", JSON.stringify(variable));
71657
+ }
71658
+ index += 1;
71659
+ }
71660
+ return {
71661
+ args,
71662
+ env,
71663
+ skipped
71664
+ };
71665
+ };
71666
+ //#endregion
71566
71667
  //#region ../../packages/effect-codex-app-server/src/_internal/shared.ts
71567
71668
  const JsonRpcId$1 = Schema$1.Union([Schema$1.Number, Schema$1.String]);
71568
71669
  const JsonRpcError = Schema$1.Struct({
@@ -73959,6 +74060,11 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
73959
74060
  if (existing && !existing.stopped) yield* Effect.suspend(() => stopSessionInternal(existing));
73960
74061
  const serviceTier = input.modelSelection?.instanceId === boundInstanceId ? getCodexServiceTierOptionValue(input.modelSelection) : void 0;
73961
74062
  const mcpSession = readMcpProviderSession(input.threadId);
74063
+ const externalMcp = toCodexMcpConfig(options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers, P4CODE_MCP_SERVER_NAMES);
74064
+ for (const dropped of externalMcp.skipped) yield* Effect.logWarning("codex cannot express an mcp registration", {
74065
+ server: dropped.name,
74066
+ reason: dropped.reason
74067
+ });
73962
74068
  const runtimeInput = {
73963
74069
  threadId: input.threadId,
73964
74070
  providerInstanceId: boundInstanceId,
@@ -73971,17 +74077,18 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
73971
74077
  runtimeMode: input.runtimeMode,
73972
74078
  ...input.modelSelection?.instanceId === boundInstanceId ? { model: input.modelSelection.model } : {},
73973
74079
  ...serviceTier ? { serviceTier } : {},
73974
- ...mcpSession ? {
74080
+ ...externalMcp.args.length > 0 || mcpSession ? {
73975
74081
  environment: {
73976
74082
  ...options?.environment ?? process.env,
73977
- P4_MCP_BEARER_TOKEN: mcpSession.authorizationHeader.replace(/^Bearer\s+/, "")
74083
+ ...externalMcp.env,
74084
+ ...mcpSession ? { [CODEX_P4CODE_BEARER_TOKEN_ENV_VAR]: mcpSession.authorizationHeader.replace(/^Bearer\s+/, "") } : {}
73978
74085
  },
73979
- appServerArgs: [
74086
+ appServerArgs: [...externalMcp.args, ...mcpSession ? [
73980
74087
  "-c",
73981
- `mcp_servers.p4-code.url=${mcpSession.endpoint}`,
74088
+ `mcp_servers.${P4CODE_MCP_SERVER_NAME}.url=${mcpSession.endpoint}`,
73982
74089
  "-c",
73983
- "mcp_servers.p4-code.bearer_token_env_var=\"P4_MCP_BEARER_TOKEN\""
73984
- ]
74090
+ `mcp_servers.${P4CODE_MCP_SERVER_NAME}.bearer_token_env_var="${CODEX_P4CODE_BEARER_TOKEN_ENV_VAR}"`
74091
+ ] : []]
73985
74092
  } : {}
73986
74093
  };
73987
74094
  const sessionScope = yield* Scope.make("sequential");
@@ -74484,6 +74591,7 @@ const CodexDriver = {
74484
74591
  const adapter = yield* makeCodexAdapter(effectiveConfig, {
74485
74592
  instanceId,
74486
74593
  environment: processEnv,
74594
+ resolveMcpServers: (yield* McpRegistry).resolveForSession,
74487
74595
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}
74488
74596
  });
74489
74597
  const textGeneration = yield* makeCodexTextGeneration(effectiveConfig, processEnv);
@@ -80076,6 +80184,31 @@ const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(function*
80076
80184
  };
80077
80185
  });
80078
80186
  //#endregion
80187
+ //#region src/provider/acp/acpMcpServers.ts
80188
+ const namedPairs = (values) => Object.entries(values).map(([name, value]) => ({
80189
+ name,
80190
+ value
80191
+ }));
80192
+ /**
80193
+ * @param resolved - Servers keyed by name, as the registry resolved them.
80194
+ * @param exclude - Names p4code declares itself, which win over a registration
80195
+ * of the same name. The built-in `p4-code` server carries a per-thread
80196
+ * credential no registration can reproduce, so a same-named registration must
80197
+ * not be able to displace it — it would take `task_current` with it, and the
80198
+ * failure would look like the agent forgetting which task it is on.
80199
+ */
80200
+ const toAcpMcpServers = (resolved, exclude = /* @__PURE__ */ new Set()) => Object.entries(resolved).filter(([name]) => !exclude.has(name)).map(([name, server]) => server.type === "stdio" ? {
80201
+ name,
80202
+ command: server.command,
80203
+ args: [...server.args],
80204
+ env: namedPairs(server.env)
80205
+ } : {
80206
+ type: server.type,
80207
+ name,
80208
+ url: server.url,
80209
+ headers: namedPairs(server.headers)
80210
+ });
80211
+ //#endregion
80079
80212
  //#region src/provider/acp/AcpAdapterSupport.ts
80080
80213
  const isAcpProcessExitedError = Schema$1.is(AcpProcessExitedError);
80081
80214
  const isAcpRequestError = Schema$1.is(AcpRequestError);
@@ -80560,6 +80693,15 @@ function makeCursorAdapter(cursorSettings, options) {
80560
80693
  });
80561
80694
  const effectiveCursorSettings = options?.resolveSettings ? yield* options.resolveSettings : cursorSettings;
80562
80695
  const mcpSession = readMcpProviderSession(input.threadId);
80696
+ const mcpServers = [...toAcpMcpServers(options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers, P4CODE_MCP_SERVER_NAMES), ...mcpSession ? [{
80697
+ type: "http",
80698
+ name: P4CODE_MCP_SERVER_NAME,
80699
+ url: mcpSession.endpoint,
80700
+ headers: [{
80701
+ name: "Authorization",
80702
+ value: mcpSession.authorizationHeader
80703
+ }]
80704
+ }] : []];
80563
80705
  const acp = yield* makeCursorAcpRuntime({
80564
80706
  cursorSettings: effectiveCursorSettings,
80565
80707
  ...options?.environment ? { environment: options.environment } : {},
@@ -80567,18 +80709,10 @@ function makeCursorAdapter(cursorSettings, options) {
80567
80709
  cwd,
80568
80710
  ...resumeSessionId ? { resumeSessionId } : {},
80569
80711
  clientInfo: {
80570
- name: "p4-code",
80712
+ name: P4CODE_MCP_SERVER_NAME,
80571
80713
  version: "0.0.0"
80572
80714
  },
80573
- ...mcpSession ? { mcpServers: [{
80574
- type: "http",
80575
- name: "p4-code",
80576
- url: mcpSession.endpoint,
80577
- headers: [{
80578
- name: "Authorization",
80579
- value: mcpSession.authorizationHeader
80580
- }]
80581
- }] } : {},
80715
+ ...mcpServers.length > 0 ? { mcpServers } : {},
80582
80716
  ...acpNativeLoggers
80583
80717
  }).pipe(Effect.provideService(Crypto.Crypto, crypto), Effect.provideService(Scope.Scope, sessionScope), Effect.mapError((cause) => new ProviderAdapterProcessError({
80584
80718
  provider: PROVIDER$3,
@@ -81059,6 +81193,7 @@ const CursorDriver = {
81059
81193
  });
81060
81194
  const adapter = yield* makeCursorAdapter(effectiveConfig, {
81061
81195
  environment: processEnv,
81196
+ resolveMcpServers: (yield* McpRegistry).resolveForSession,
81062
81197
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {},
81063
81198
  instanceId
81064
81199
  });
@@ -81781,6 +81916,15 @@ function makeGrokAdapter(grokSettings, options) {
81781
81916
  threadId: input.threadId
81782
81917
  });
81783
81918
  const mcpSession = readMcpProviderSession(input.threadId);
81919
+ const mcpServers = [...toAcpMcpServers(options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers, P4CODE_MCP_SERVER_NAMES), ...mcpSession ? [{
81920
+ type: "http",
81921
+ name: P4CODE_MCP_SERVER_NAME,
81922
+ url: mcpSession.endpoint,
81923
+ headers: [{
81924
+ name: "Authorization",
81925
+ value: mcpSession.authorizationHeader
81926
+ }]
81927
+ }] : []];
81784
81928
  const acp = yield* makeGrokAcpRuntime({
81785
81929
  grokSettings,
81786
81930
  ...options?.environment ? { environment: options.environment } : {},
@@ -81788,18 +81932,10 @@ function makeGrokAdapter(grokSettings, options) {
81788
81932
  cwd,
81789
81933
  ...resumeSessionId ? { resumeSessionId } : {},
81790
81934
  clientInfo: {
81791
- name: "p4-code",
81935
+ name: P4CODE_MCP_SERVER_NAME,
81792
81936
  version: "0.0.0"
81793
81937
  },
81794
- ...mcpSession ? { mcpServers: [{
81795
- type: "http",
81796
- name: "p4-code",
81797
- url: mcpSession.endpoint,
81798
- headers: [{
81799
- name: "Authorization",
81800
- value: mcpSession.authorizationHeader
81801
- }]
81802
- }] } : {},
81938
+ ...mcpServers.length > 0 ? { mcpServers } : {},
81803
81939
  ...acpNativeLoggers
81804
81940
  }).pipe(Effect.provideService(Crypto.Crypto, crypto), Effect.provideService(Scope.Scope, sessionScope), Effect.mapError((cause) => new ProviderAdapterProcessError({
81805
81941
  provider: PROVIDER$2,
@@ -82615,6 +82751,7 @@ const GrokDriver = {
82615
82751
  });
82616
82752
  const adapter = yield* makeGrokAdapter(effectiveConfig, {
82617
82753
  environment: processEnv,
82754
+ resolveMcpServers: (yield* McpRegistry).resolveForSession,
82618
82755
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {},
82619
82756
  instanceId
82620
82757
  });
@@ -84452,6 +84589,27 @@ const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(funct
84452
84589
  };
84453
84590
  });
84454
84591
  //#endregion
84592
+ //#region src/provider/Layers/openCodeMcpServers.ts
84593
+ /**
84594
+ * @param resolved - Servers keyed by name, as the registry resolved them.
84595
+ * @param exclude - Names p4code declares itself, which a registration must not
84596
+ * be able to displace: the built-in `p4-code` server carries the per-thread
84597
+ * credential behind `task_current` and the thread tools.
84598
+ */
84599
+ const toOpenCodeMcpServers = (resolved, exclude = /* @__PURE__ */ new Set()) => Object.entries(resolved).filter(([name]) => !exclude.has(name)).map(([name, server]) => ({
84600
+ name,
84601
+ config: server.type === "stdio" ? {
84602
+ type: "local",
84603
+ command: [server.command, ...server.args],
84604
+ ...Object.keys(server.env).length > 0 ? { environment: server.env } : {}
84605
+ } : {
84606
+ type: "remote",
84607
+ url: server.url,
84608
+ ...Object.keys(server.headers).length > 0 ? { headers: server.headers } : {},
84609
+ oauth: false
84610
+ }
84611
+ }));
84612
+ //#endregion
84455
84613
  //#region src/provider/Layers/OpenCodeAdapter.ts
84456
84614
  const PROVIDER = ProviderDriverKind.make("opencode");
84457
84615
  /**
@@ -85128,8 +85286,15 @@ function makeOpenCodeAdapter(openCodeSettings, options) {
85128
85286
  ...server.external && serverPassword ? { serverPassword } : {}
85129
85287
  });
85130
85288
  const mcpSession = readMcpProviderSession(input.threadId);
85289
+ if (!server.external) {
85290
+ const externalMcpServers = toOpenCodeMcpServers(options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers, P4CODE_MCP_SERVER_NAMES);
85291
+ for (const entry of externalMcpServers) yield* runOpenCodeSdk("mcp.add", () => client.mcp.add(entry)).pipe(Effect.catchCause((cause) => Effect.logWarning("opencode rejected an mcp registration", {
85292
+ server: entry.name,
85293
+ cause
85294
+ })));
85295
+ }
85131
85296
  if (mcpSession && !server.external) yield* runOpenCodeSdk("mcp.add", () => client.mcp.add({
85132
- name: "p4-code",
85297
+ name: P4CODE_MCP_SERVER_NAME,
85133
85298
  config: {
85134
85299
  type: "remote",
85135
85300
  url: mcpSession.endpoint,
@@ -85818,6 +85983,7 @@ const BUILT_IN_DRIVERS = [
85818
85983
  const adapter = yield* makeOpenCodeAdapter(effectiveConfig, {
85819
85984
  instanceId,
85820
85985
  environment: processEnv,
85986
+ resolveMcpServers: (yield* McpRegistry).resolveForSession,
85821
85987
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}
85822
85988
  });
85823
85989
  const textGeneration = yield* makeOpenCodeTextGeneration(effectiveConfig, processEnv);
@@ -86490,7 +86656,29 @@ const TaskProposeTool = Tool.make("task_propose", {
86490
86656
  failure: TaskToolError,
86491
86657
  dependencies
86492
86658
  }).annotate(Tool.Title, "Propose a task").annotate(Tool.Readonly, true).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, true);
86493
- const TaskToolkit = Toolkit.make(TaskListTool, TaskGetTool, TaskCurrentTool, TaskCreateTool, TaskUpdateTool, TaskProposeTool);
86659
+ /**
86660
+ * Reading a tracker ticket, for every provider rather than only the ones that
86661
+ * can talk to the tracker themselves.
86662
+ *
86663
+ * p4code resolves this server-side through the Linear server the user
86664
+ * registered once in Settings, so an agent gets the ticket whether or not its
86665
+ * own runtime was handed that registration. Without it, a thread started from
86666
+ * "MOBILE-12241" on a provider with no tracker of its own can only ask the user
86667
+ * to paste the description back in - which is the question they already
86668
+ * answered by quoting the id.
86669
+ *
86670
+ * On the task toolkit rather than a toolkit of its own because it is board
86671
+ * work: a resolved ticket's next step is `task_create` with the `externalRef`
86672
+ * this returns, and the two share the one capability a session is granted.
86673
+ */
86674
+ const TicketResolveTool = Tool.make("ticket_resolve", {
86675
+ description: "Read a tracker ticket by id or URL (e.g. MOBILE-12241, or a linear.app link), returning its identifier, canonical URL, title and description. Use this whenever the user names a ticket rather than asking them to paste it. Pass the returned externalRef straight to task_create to mirror the ticket onto the board. Fails when no tracker is registered on this machine, which is a thing only the user can fix.",
86676
+ parameters: TicketResolveInput,
86677
+ success: TicketResolveResult,
86678
+ failure: Schema$1.Union([TaskToolUnavailableError, TicketResolveError]),
86679
+ dependencies: [McpInvocationContext, TicketResolver]
86680
+ }).annotate(Tool.Title, "Resolve a ticket").annotate(Tool.Readonly, true).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, true);
86681
+ const TaskToolkit = Toolkit.make(TaskListTool, TaskGetTool, TaskCurrentTool, TaskCreateTool, TaskUpdateTool, TaskProposeTool, TicketResolveTool);
86494
86682
  //#endregion
86495
86683
  //#region src/mcp/toolkits/tasks/handlers.ts
86496
86684
  const nowIso$1 = Effect.map(DateTime.now, DateTime.formatIso);
@@ -86576,6 +86764,10 @@ const TaskToolkitHandlersLive = TaskToolkit.toLayer({
86576
86764
  if (Option.isNone(patched)) return yield* new TaskNotFoundError({ taskId: input.taskId });
86577
86765
  return patched.value;
86578
86766
  }),
86767
+ ticket_resolve: (input) => Effect.gen(function* () {
86768
+ yield* requireTaskCapability();
86769
+ return yield* (yield* TicketResolver).resolve(input.reference);
86770
+ }),
86579
86771
  task_propose: () => Effect.gen(function* () {
86580
86772
  yield* requireTaskCapability();
86581
86773
  return { awaitingConfirmation: true };