@p4code/cli 0.1.14 → 0.1.15

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 (86) hide show
  1. package/dist/bin.mjs +355 -46
  2. package/dist/client/assets/{DiffPanel-BdNsdwM5.js → DiffPanel-Btlwh6tZ.js} +2 -2
  3. package/dist/client/assets/{FilePreviewPanel-CWcDqLso.js → FilePreviewPanel-CJRGrUq9.js} +2 -2
  4. package/dist/client/assets/{PreviewPanel-2u47bK5v.js → PreviewPanel-CM8chpxZ.js} +2 -2
  5. package/dist/client/assets/{angular-html-BLv19dHn.js → angular-html-BjmAeE7T.js} +2 -2
  6. package/dist/client/assets/{angular-ts-D41w0Au3.js → angular-ts-BBpxlOlP.js} +2 -2
  7. package/dist/client/assets/{apl-BEl8UFu4.js → apl-BbgMrCuX.js} +2 -2
  8. package/dist/client/assets/arrow-right-DYd55OqT.js +2 -0
  9. package/dist/client/assets/{astro-U1Y_O85L.js → astro-mUvWYN-n.js} +2 -2
  10. package/dist/client/assets/{blade-CZ232EWr.js → blade-B5QWyKCP.js} +2 -2
  11. package/dist/client/assets/{c-DirgNKaz.js → c-BfHpmPOy.js} +2 -2
  12. package/dist/client/assets/{cobol-B7WyPi1F.js → cobol-DLZOS_vG.js} +2 -2
  13. package/dist/client/assets/{coffee-C_qHkMIP.js → coffee-9TkBNWbZ.js} +2 -2
  14. package/dist/client/assets/{cpp-SPUhkLTs.js → cpp-qjIc-2IN.js} +2 -2
  15. package/dist/client/assets/{crystal-vq6jdakY.js → crystal-DCOpXRVe.js} +2 -2
  16. package/dist/client/assets/{css-BAnKum7K.js → css-Xrxx3evf.js} +2 -2
  17. package/dist/client/assets/{edge-BuMKesaI.js → edge-BJXKMMao.js} +2 -2
  18. package/dist/client/assets/{elixir-BL-W6BH4.js → elixir-_uRFN4Aw.js} +2 -2
  19. package/dist/client/assets/{elm-DiUCNL3v.js → elm-fwfp6NdI.js} +2 -2
  20. package/dist/client/assets/{erb-skcSurJb.js → erb-DfSw8n3G.js} +2 -2
  21. package/dist/client/assets/{fileCommentAnnotations-BRTew3I1.js → fileCommentAnnotations-BCnpdEVp.js} +2 -2
  22. package/dist/client/assets/{git-rebase-dO-xI28x.js → git-rebase-CwGd8ZXk.js} +2 -2
  23. package/dist/client/assets/{glimmer-js-CECukRm7.js → glimmer-js-DIl7yS9j.js} +2 -2
  24. package/dist/client/assets/{glimmer-ts-CIaRC8zm.js → glimmer-ts-ClbRblrS.js} +2 -2
  25. package/dist/client/assets/{glsl-CKSbugKg.js → glsl-DPbTpA_H.js} +2 -2
  26. package/dist/client/assets/{graphql-BiZ7twV7.js → graphql-Ugw-cmPb.js} +2 -2
  27. package/dist/client/assets/{hack-BdAxCPD7.js → hack-BNaGlFKY.js} +2 -2
  28. package/dist/client/assets/{haml-SZR9Ndrp.js → haml-CADPiQL8.js} +2 -2
  29. package/dist/client/assets/{handlebars-BExVQKqz.js → handlebars-lMMkQPVI.js} +2 -2
  30. package/dist/client/assets/{html-CkYFYJn1.js → html-dV4yJf1E.js} +2 -2
  31. package/dist/client/assets/{html-derivative-Cop3EQeZ.js → html-derivative-DC417Zuq.js} +2 -2
  32. package/dist/client/assets/{http-DQ8c4u3s.js → http-DHNl1S4G.js} +2 -2
  33. package/dist/client/assets/{hurl-BKyyIuNR.js → hurl-MeTzE8YN.js} +2 -2
  34. package/dist/client/assets/{index-ClVe76A5.js → index-BmkbvCRH.js} +200 -200
  35. package/dist/client/assets/index-DvMVFBig.css +1 -0
  36. package/dist/client/assets/{java-CedFcWif.js → java-_z6VtRIC.js} +2 -2
  37. package/dist/client/assets/{javascript-BdXDoWFM.js → javascript-mzH0UoeT.js} +2 -2
  38. package/dist/client/assets/{jinja-CK8YWL7a.js → jinja-CcSfwgQN.js} +2 -2
  39. package/dist/client/assets/{jison-C-mnFz-X.js → jison-Dnr6DQYK.js} +2 -2
  40. package/dist/client/assets/{json-Dxix4Qbo.js → json-xiKHc2eN.js} +2 -2
  41. package/dist/client/assets/{jsx-6M0gL61I.js → jsx-B0uBKQ5P.js} +2 -2
  42. package/dist/client/assets/{julia-SXfQGJ8P.js → julia-Du1DH_tJ.js} +2 -2
  43. package/dist/client/assets/{just-O0TR05uE.js → just-DlyxJRKQ.js} +2 -2
  44. package/dist/client/assets/{latex-w7R_uAyc.js → latex-FzyaW41z.js} +2 -2
  45. package/dist/client/assets/{liquid-hPzEzmzZ.js → liquid-n6xLDAue.js} +2 -2
  46. package/dist/client/assets/{lua-D24pQ94w.js → lua-DL20UMyO.js} +2 -2
  47. package/dist/client/assets/{marko-DsaGFeHY.js → marko-OhxSvhVO.js} +2 -2
  48. package/dist/client/assets/{mdc-C4vifn2U.js → mdc-JFr_O-f6.js} +2 -2
  49. package/dist/client/assets/{nginx-KnKOgHWr.js → nginx-DO3MRFFZ.js} +2 -2
  50. package/dist/client/assets/{nim-CXVNWegc.js → nim-gxiT3Pjh.js} +2 -2
  51. package/dist/client/assets/{perl-_PU7gLJn.js → perl-uO1ltvnm.js} +2 -2
  52. package/dist/client/assets/{php-B--0cDl3.js → php-DkSF6XhT.js} +2 -2
  53. package/dist/client/assets/{pug-DELbYjHv.js → pug-D6ks186t.js} +2 -2
  54. package/dist/client/assets/{qml-CyGKPCuH.js → qml-CsabseTB.js} +2 -2
  55. package/dist/client/assets/{r-CSjDVJJY.js → r-UjYqKhF6.js} +2 -2
  56. package/dist/client/assets/{razor-ppZnQuQy.js → razor-Dr34iB-_.js} +2 -2
  57. package/dist/client/assets/{regexp-DAYlObpi.js → regexp-BG9MLSbj.js} +2 -2
  58. package/dist/client/assets/{rst-DV8sAt14.js → rst-I9GYrav4.js} +2 -2
  59. package/dist/client/assets/{ruby-DXISWktP.js → ruby-DQZcmBTL.js} +2 -2
  60. package/dist/client/assets/{sas-CJl6Tu3p.js → sas-To8Ja79N.js} +2 -2
  61. package/dist/client/assets/{scss-DmbKMDuD.js → scss-KhIYRETT.js} +2 -2
  62. package/dist/client/assets/{shellscript-BFH8QS9G.js → shellscript-B3M9HD4S.js} +2 -2
  63. package/dist/client/assets/{shellsession-CIHFsdwm.js → shellsession-DCI3i_rX.js} +2 -2
  64. package/dist/client/assets/{soy--q_a3wNH.js → soy-11gkdBZx.js} +2 -2
  65. package/dist/client/assets/{sql-DE3xygzU.js → sql-Dc2GulG4.js} +2 -2
  66. package/dist/client/assets/{stata-BZORI8K-.js → stata-Br5SUE30.js} +2 -2
  67. package/dist/client/assets/{surrealql-DQwYGqPv.js → surrealql-Rg04dQNn.js} +2 -2
  68. package/dist/client/assets/{svelte-C8rcZCbS.js → svelte-CtlB9-BL.js} +2 -2
  69. package/dist/client/assets/{templ-YxwRimHC.js → templ-Du0y714B.js} +2 -2
  70. package/dist/client/assets/{tex-CreWrrVU.js → tex-DujbYFg6.js} +2 -2
  71. package/dist/client/assets/textarea-C3IX8FEW.js +46 -0
  72. package/dist/client/assets/{ts-tags-BGYLwTar.js → ts-tags-D1giNT28.js} +2 -2
  73. package/dist/client/assets/{tsx-dvRLM93g.js → tsx-6OJBHQve.js} +2 -2
  74. package/dist/client/assets/{twig-BwKK1q-j.js → twig-CsGDI-1m.js} +2 -2
  75. package/dist/client/assets/{typescript-CIA9s0mZ.js → typescript-BK1jdq6h.js} +2 -2
  76. package/dist/client/assets/{vue-RR_2K8-s.js → vue-CcdGezrU.js} +2 -2
  77. package/dist/client/assets/{vue-html-SobvEO2e.js → vue-html-Cki3bF1b.js} +2 -2
  78. package/dist/client/assets/{vue-vine-BQgxB5Yf.js → vue-vine-CqNi4Hn_.js} +2 -2
  79. package/dist/client/assets/{xml-qR9OaTYe.js → xml-By8mAu2E.js} +2 -2
  80. package/dist/client/assets/{xsl-CNAIK0Wp.js → xsl-DWgCtTr-.js} +2 -2
  81. package/dist/client/assets/{yaml-CnmdSZli.js → yaml-DZTshk4U.js} +2 -2
  82. package/dist/client/index.html +3 -3
  83. package/package.json +1 -1
  84. package/dist/client/assets/arrow-right-Tef5pBUM.js +0 -2
  85. package/dist/client/assets/index-DGu8ejUP.css +0 -1
  86. package/dist/client/assets/textarea-DogWRke3.js +0 -46
package/dist/bin.mjs CHANGED
@@ -121,7 +121,7 @@ const closeServer = (server) => {
121
121
  * NetService - Service tag for startup networking helpers.
122
122
  */
123
123
  var NetService = class extends Context.Service()("@p4code/shared/Net/NetService") {};
124
- const make$74 = () => {
124
+ const make$75 = () => {
125
125
  /**
126
126
  * Returns true when a TCP server can bind to {host, port}.
127
127
  * `EADDRNOTAVAIL` is treated as available so IPv6-absent hosts don't fail
@@ -230,10 +230,10 @@ const make$74 = () => {
230
230
  })
231
231
  };
232
232
  };
233
- const layer$70 = Layer.sync(NetService, make$74);
233
+ const layer$71 = Layer.sync(NetService, make$75);
234
234
  //#endregion
235
235
  //#region package.json
236
- var version = "0.1.14";
236
+ var version = "0.1.15";
237
237
  //#endregion
238
238
  //#region src/config.ts
239
239
  /**
@@ -254,8 +254,8 @@ var ServerConfig$1 = class extends Context.Service()("@p4code/cli/config/ServerC
254
254
  /** @deprecated Import and use `layerTest` from this module. */
255
255
  static layerTest = (cwd, baseDirOrPrefix) => layerTest$2(cwd, baseDirOrPrefix);
256
256
  };
257
- const make$73 = (config) => ServerConfig$1.of(config);
258
- const layer$69 = (config) => Layer.succeed(ServerConfig$1, make$73(config));
257
+ const make$74 = (config) => ServerConfig$1.of(config);
258
+ const layer$70 = (config) => Layer.succeed(ServerConfig$1, make$74(config));
259
259
  const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
260
260
  const { join } = yield* Path.Path;
261
261
  const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
@@ -8217,17 +8217,62 @@ const McpServerOAuthStatus = Schema$1.Struct({
8217
8217
  * unusable *here*, and saying which slot is empty is the difference between a
8218
8218
  * fixable state and a mystery.
8219
8219
  */
8220
+ /**
8221
+ * Where a listed server lives, which is also where an edit goes.
8222
+ *
8223
+ * `claude` is the CLI's user scope (`~/.claude.json`) — the primary home,
8224
+ * because every Claude Code session reads it, inside p4code and out.
8225
+ * `project` is one workspace project's `.mcp.json`, committed with the repo.
8226
+ * `registry` is p4code's own store, the only one that syncs through the hub
8227
+ * and carries secret slots.
8228
+ */
8229
+ const McpServerSource = Schema$1.Literals([
8230
+ "registry",
8231
+ "claude",
8232
+ "project"
8233
+ ]);
8220
8234
  const McpServerStatus = Schema$1.Struct({
8221
8235
  registration: McpServerRegistration,
8222
8236
  missingSecrets: Schema$1.Array(McpSecretSlot),
8223
8237
  /** True when this machine holds everything needed to start it. */
8224
8238
  ready: Schema$1.Boolean,
8225
8239
  /** Absent for servers that never challenged and hold no token here. */
8226
- oauth: Schema$1.optional(McpServerOAuthStatus)
8240
+ oauth: Schema$1.optional(McpServerOAuthStatus),
8241
+ /** Absent means `registry`, which every row was before this field existed. */
8242
+ source: Schema$1.optional(McpServerSource),
8243
+ /** The workspace root whose `.mcp.json` holds this row. `project` rows only. */
8244
+ projectDir: Schema$1.optional(Schema$1.String)
8245
+ });
8246
+ /** A workspace project the panel can scope a server to. */
8247
+ const McpProjectRef = Schema$1.Struct({
8248
+ dir: Schema$1.String,
8249
+ title: Schema$1.String
8250
+ });
8251
+ const McpServerList = Schema$1.Struct({
8252
+ servers: Schema$1.Array(McpServerStatus),
8253
+ /**
8254
+ * The projects whose `.mcp.json` can be edited, for the add dialog's scope
8255
+ * picker. Carried with the list so the panel needs no second request.
8256
+ */
8257
+ projects: Schema$1.optional(Schema$1.Array(McpProjectRef))
8258
+ });
8259
+ /**
8260
+ * `source` routes the write: `claude` edits the `mcpServers` key of the
8261
+ * CLI's user-scope file, `registry` (or absent) writes p4code's own store.
8262
+ * The user-scope file is the primary home — it is what every Claude Code
8263
+ * session reads, in and out of p4code — so the panel defaults to it.
8264
+ */
8265
+ const McpServerSaveInput = Schema$1.Struct({
8266
+ registration: McpServerRegistration,
8267
+ source: Schema$1.optional(McpServerSource),
8268
+ /** Required when `source` is `project`: the workspace root to write into. */
8269
+ projectDir: Schema$1.optional(Schema$1.String)
8270
+ });
8271
+ const McpServerNameInput = Schema$1.Struct({
8272
+ name: McpServerName,
8273
+ source: Schema$1.optional(McpServerSource),
8274
+ projectDir: Schema$1.optional(Schema$1.String)
8227
8275
  });
8228
- const McpServerList = Schema$1.Struct({ servers: Schema$1.Array(McpServerStatus) });
8229
- const McpServerSaveInput = Schema$1.Struct({ registration: McpServerRegistration });
8230
- const McpServerNameInput = Schema$1.Struct({ name: McpServerName });
8231
8276
  /**
8232
8277
  * Setting one secret value, on this machine only.
8233
8278
  *
@@ -9405,7 +9450,7 @@ function deriveAuthClientMetadata(input) {
9405
9450
  //#endregion
9406
9451
  //#region src/auth/EnvironmentAuthPolicy.ts
9407
9452
  var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
9408
- const make$72 = Effect.gen(function* () {
9453
+ const make$73 = Effect.gen(function* () {
9409
9454
  const config = yield* ServerConfig$1;
9410
9455
  const isRemoteReachable = isRemoteReachableHost(config.host);
9411
9456
  const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
@@ -9423,7 +9468,7 @@ const make$72 = Effect.gen(function* () {
9423
9468
  };
9424
9469
  return EnvironmentAuthPolicy.of({ getDescriptor: () => Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")) });
9425
9470
  });
9426
- const layer$68 = Layer.effect(EnvironmentAuthPolicy, make$72);
9471
+ const layer$69 = Layer.effect(EnvironmentAuthPolicy, make$73);
9427
9472
  //#endregion
9428
9473
  //#region src/persistence/Errors.ts
9429
9474
  function summarizeSchemaIssue(issue) {
@@ -9604,7 +9649,7 @@ function toPersistenceSqlOrDecodeError$6(sqlOperation, decodeOperation, correlat
9604
9649
  cause
9605
9650
  });
9606
9651
  }
9607
- const make$71 = Effect.gen(function* () {
9652
+ const make$72 = Effect.gen(function* () {
9608
9653
  const sql = yield* SqlClient.SqlClient;
9609
9654
  const createSessionRow = SqlSchema.void({
9610
9655
  Request: CreateAuthSessionInput,
@@ -9738,7 +9783,7 @@ const make$71 = Effect.gen(function* () {
9738
9783
  setLastConnectedAt
9739
9784
  };
9740
9785
  });
9741
- const layer$67 = Layer.effect(AuthSessionRepository, make$71);
9786
+ const layer$68 = Layer.effect(AuthSessionRepository, make$72);
9742
9787
  //#endregion
9743
9788
  //#region src/auth/ServerSecretStore.ts
9744
9789
  const secretStoreErrorContext = {
@@ -9805,7 +9850,7 @@ const isSecretStoreError = Schema$1.is(SecretStoreError);
9805
9850
  const isPlatformError = (value) => Predicate.isTagged(value, "PlatformError");
9806
9851
  const isSecretAlreadyExistsError = (error) => "cause" in error && isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists";
9807
9852
  var ServerSecretStore = class extends Context.Service()("@p4code/cli/auth/ServerSecretStore") {};
9808
- const make$70 = Effect.gen(function* () {
9853
+ const make$71 = Effect.gen(function* () {
9809
9854
  const crypto = yield* Crypto.Crypto;
9810
9855
  const fileSystem = yield* FileSystem.FileSystem;
9811
9856
  const path = yield* Path.Path;
@@ -9875,7 +9920,7 @@ const make$70 = Effect.gen(function* () {
9875
9920
  remove
9876
9921
  });
9877
9922
  });
9878
- const layer$66 = Layer.effect(ServerSecretStore, make$70);
9923
+ const layer$67 = Layer.effect(ServerSecretStore, make$71);
9879
9924
  //#endregion
9880
9925
  //#region src/auth/SessionStore.ts
9881
9926
  var MalformedSessionTokenError = class extends Schema$1.TaggedErrorClass()("MalformedSessionTokenError", {}) {
@@ -10113,7 +10158,7 @@ function toAuthClientSession(input) {
10113
10158
  current: false
10114
10159
  };
10115
10160
  }
10116
- const make$69 = Effect.gen(function* () {
10161
+ const make$70 = Effect.gen(function* () {
10117
10162
  const crypto = yield* Crypto.Crypto;
10118
10163
  const serverConfig = yield* ServerConfig$1;
10119
10164
  const secretStore = yield* ServerSecretStore;
@@ -10427,7 +10472,7 @@ const make$69 = Effect.gen(function* () {
10427
10472
  markDisconnected
10428
10473
  });
10429
10474
  });
10430
- const layer$65 = Layer.effect(SessionStore, make$69).pipe(Layer.provideMerge(layer$67));
10475
+ const layer$66 = Layer.effect(SessionStore, make$70).pipe(Layer.provideMerge(layer$68));
10431
10476
  //#endregion
10432
10477
  //#region src/persistence/AuthPairingLinks.ts
10433
10478
  const AuthPairingLinkRecord = Schema$1.Struct({
@@ -10488,7 +10533,7 @@ function toPersistenceSqlOrDecodeError$5(sqlOperation, decodeOperation, correlat
10488
10533
  cause
10489
10534
  });
10490
10535
  }
10491
- const make$68 = Effect.gen(function* () {
10536
+ const make$69 = Effect.gen(function* () {
10492
10537
  const sql = yield* SqlClient.SqlClient;
10493
10538
  const createPairingLinkRow = SqlSchema.void({
10494
10539
  Request: CreateAuthPairingLinkInput,
@@ -10623,7 +10668,7 @@ const make$68 = Effect.gen(function* () {
10623
10668
  getByCredential
10624
10669
  };
10625
10670
  });
10626
- const layer$64 = Layer.effect(AuthPairingLinkRepository, make$68);
10671
+ const layer$65 = Layer.effect(AuthPairingLinkRepository, make$69);
10627
10672
  //#endregion
10628
10673
  //#region src/auth/PairingGrantStore.ts
10629
10674
  var UnknownBootstrapCredentialError = class extends Schema$1.TaggedErrorClass()("UnknownBootstrapCredentialError", {}) {
@@ -10718,7 +10763,7 @@ const DEV_STARTUP_TTL_HOURS = Duration.hours(24);
10718
10763
  const PAIRING_TOKEN_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
10719
10764
  const PAIRING_TOKEN_LENGTH = 12;
10720
10765
  const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
10721
- const make$67 = Effect.gen(function* () {
10766
+ const make$68 = Effect.gen(function* () {
10722
10767
  const crypto = yield* Crypto.Crypto;
10723
10768
  const config = yield* ServerConfig$1;
10724
10769
  const pairingLinks = yield* AuthPairingLinkRepository;
@@ -10916,7 +10961,7 @@ const make$67 = Effect.gen(function* () {
10916
10961
  consume
10917
10962
  });
10918
10963
  });
10919
- const layer$63 = Layer.effect(PairingGrantStore, make$67).pipe(Layer.provideMerge(layer$64));
10964
+ const layer$64 = Layer.effect(PairingGrantStore, make$68).pipe(Layer.provideMerge(layer$65));
10920
10965
  //#endregion
10921
10966
  //#region src/persistence/Migrations/001_OrchestrationEvents.ts
10922
10967
  var _001_OrchestrationEvents_default = Effect.gen(function* () {
@@ -12771,7 +12816,7 @@ function parseBearerToken(request) {
12771
12816
  const token = header.slice(7).trim();
12772
12817
  return token.length > 0 ? token : null;
12773
12818
  }
12774
- const make$66 = Effect.gen(function* () {
12819
+ const make$67 = Effect.gen(function* () {
12775
12820
  const policy = yield* EnvironmentAuthPolicy;
12776
12821
  const bootstrapCredentials = yield* PairingGrantStore;
12777
12822
  const sessions = yield* SessionStore;
@@ -12966,9 +13011,9 @@ const make$66 = Effect.gen(function* () {
12966
13011
  issueStartupPairingUrl
12967
13012
  });
12968
13013
  });
12969
- const layer$62 = Layer.effect(EnvironmentAuth, make$66).pipe(Layer.provideMerge(layer$63), Layer.provideMerge(layer$65), Layer.provideMerge(layer$68));
12970
- const storageLayer = Layer.mergeAll(layer$66, layerConfig);
12971
- const runtimeLayer = layer$62.pipe(Layer.provideMerge(storageLayer));
13014
+ const layer$63 = Layer.effect(EnvironmentAuth, make$67).pipe(Layer.provideMerge(layer$64), Layer.provideMerge(layer$66), Layer.provideMerge(layer$69));
13015
+ const storageLayer = Layer.mergeAll(layer$67, layerConfig);
13016
+ const runtimeLayer = layer$63.pipe(Layer.provideMerge(storageLayer));
12972
13017
  //#endregion
12973
13018
  //#region src/cliAuthFormat.ts
12974
13019
  const newline = "\n";
@@ -13723,7 +13768,7 @@ const runWithEnvironmentAuth = (flags, run, options) => Effect.gen(function* ()
13723
13768
  }
13724
13769
  return yield* Effect.gen(function* () {
13725
13770
  return yield* run(yield* EnvironmentAuth);
13726
- }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
13771
+ }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$70(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
13727
13772
  });
13728
13773
  const ttlFlag = Flag.string("ttl").pipe(Flag.withSchema(DurationFromString), Flag.withDescription("TTL, for example `5m`, `1h`, `30d`, or `15 minutes`."), Flag.optional);
13729
13774
  const jsonFlag = Flag.boolean("json").pipe(Flag.withDescription("Emit JSON instead of human-readable output."), Flag.withDefault(false));
@@ -13863,7 +13908,7 @@ const DEFAULT_LIMITS = {
13863
13908
  windowMillis: FAILURE_WINDOW_MS,
13864
13909
  blockMillis: BLOCK_DURATION_MS
13865
13910
  };
13866
- const make$65 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
13911
+ const make$66 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
13867
13912
  const state = yield* Ref.make(initialThrottleState);
13868
13913
  return HubAuthThrottle.of({
13869
13914
  shouldRefuse: Effect.gen(function* () {
@@ -13877,7 +13922,7 @@ const make$65 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LI
13877
13922
  })
13878
13923
  });
13879
13924
  });
13880
- const layer$61 = Layer.effect(HubAuthThrottle, make$65());
13925
+ const layer$62 = Layer.effect(HubAuthThrottle, make$66());
13881
13926
  //#endregion
13882
13927
  //#region src/hub/HubAuth.ts
13883
13928
  /**
@@ -14676,7 +14721,7 @@ const deleteAssetRoute = HttpRouter.add("DELETE", "/assets/:kind/:name", respond
14676
14721
  const outcome = yield* (yield* AgentAssetRepository).deleteByName(requested);
14677
14722
  return outcome._tag === "conflict" ? assetConflict(Option.getOrNull(outcome.current)) : HttpServerResponse.empty({ status: 204 });
14678
14723
  })));
14679
- const layer$60 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
14724
+ const layer$61 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
14680
14725
  //#endregion
14681
14726
  //#region src/hub/Migrations/001_Tasks.ts
14682
14727
  /**
@@ -14955,7 +15000,7 @@ const announce = Layer.effectDiscard(Effect.gen(function* () {
14955
15000
  });
14956
15001
  if (isRemoteReachableHost(config.host)) yield* Effect.logWarning("Hub is reachable beyond loopback. The bearer token is the only control — repeated auth failures are not rate limited.", { host: config.host });
14957
15002
  }));
14958
- const makeHubLayer = HttpRouter.serve(layer$60).pipe(Layer.provideMerge(announce), Layer.provideMerge(HubHttpServerLive), Layer.provideMerge(layer$61), Layer.provideMerge(TaskRepositoryLive), Layer.provideMerge(AgentAssetRepositoryLive), Layer.provideMerge(HubPersistenceLive));
15003
+ const makeHubLayer = HttpRouter.serve(layer$61).pipe(Layer.provideMerge(announce), Layer.provideMerge(HubHttpServerLive), Layer.provideMerge(layer$62), Layer.provideMerge(TaskRepositoryLive), Layer.provideMerge(AgentAssetRepositoryLive), Layer.provideMerge(HubPersistenceLive));
14959
15004
  const runHub = Layer.launch(makeHubLayer);
14960
15005
  //#endregion
14961
15006
  //#region src/atomicWrite.ts
@@ -15079,7 +15124,7 @@ function stripDefaultServerSettings(current, defaults) {
15079
15124
  }
15080
15125
  return Object.is(current, defaults) ? void 0 : current;
15081
15126
  }
15082
- const make$64 = Effect.gen(function* () {
15127
+ const make$65 = Effect.gen(function* () {
15083
15128
  const { settingsPath } = yield* ServerConfig$1;
15084
15129
  const fs = yield* FileSystem.FileSystem;
15085
15130
  const pathService = yield* Path.Path;
@@ -15300,7 +15345,7 @@ const make$64 = Effect.gen(function* () {
15300
15345
  }
15301
15346
  };
15302
15347
  });
15303
- const layer$59 = Layer.effect(ServerSettingsService, make$64);
15348
+ const layer$60 = Layer.effect(ServerSettingsService, make$65);
15304
15349
  //#endregion
15305
15350
  //#region src/pathExpansion.ts
15306
15351
  /**
@@ -15510,6 +15555,192 @@ const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config
15510
15555
  return [...skillsByName.values()].sort((left, right) => left.name.localeCompare(right.name));
15511
15556
  });
15512
15557
  //#endregion
15558
+ //#region src/mcp/ClaudeMcpFiles.ts
15559
+ /**
15560
+ * The MCP servers in Claude Code's own configuration files.
15561
+ *
15562
+ * Two homes, both the CLI's and both primary over p4code's registry:
15563
+ *
15564
+ * - **User scope**: the `mcpServers` key of `~/.claude.json`. Every Claude
15565
+ * Code session reads it, inside p4code and out.
15566
+ * - **Project scope**: `<project>/.mcp.json`, committed with the repository
15567
+ * and read by every session working in it.
15568
+ *
15569
+ * The settings panel manages both directly — list, add, edit, remove — so
15570
+ * this service writes them. **A user-scope write touches only the
15571
+ * `mcpServers` key**; `~/.claude.json` also holds `oauthAccount`, `machineID`
15572
+ * and a `projects` map, and everything outside the one key is carried
15573
+ * through a write as parsed. This is the same read-modify-write the
15574
+ * `claude mcp add` command performs, with the same last-writer-wins caveat
15575
+ * when a CLI session saves concurrently.
15576
+ *
15577
+ * A malformed entry, a name that would not survive as a registry filename, or
15578
+ * a missing file all cost only what they describe: that entry, or that one
15579
+ * file's list, never the panel.
15580
+ *
15581
+ * @module mcp/ClaudeMcpFiles
15582
+ */
15583
+ const isServerName = Schema$1.is(McpServerName);
15584
+ /** The file a project's scope lives in, beside its lockfiles and dotfiles. */
15585
+ const PROJECT_MCP_FILENAME = ".mcp.json";
15586
+ /**
15587
+ * One entry as the CLI writes it. `type` is absent for the CLI's original
15588
+ * stdio-only shape, so it defaults rather than discriminates.
15589
+ */
15590
+ const ClaudeMcpEntry = Schema$1.Struct({
15591
+ type: Schema$1.optional(Schema$1.Literals([
15592
+ "stdio",
15593
+ "http",
15594
+ "sse"
15595
+ ])),
15596
+ command: Schema$1.optional(Schema$1.String),
15597
+ args: Schema$1.optional(Schema$1.Array(Schema$1.String)),
15598
+ env: Schema$1.optional(Schema$1.Record(Schema$1.String, Schema$1.String)),
15599
+ url: Schema$1.optional(Schema$1.String),
15600
+ headers: Schema$1.optional(Schema$1.Record(Schema$1.String, Schema$1.String))
15601
+ });
15602
+ /**
15603
+ * A config file as this service needs to see it: the one key it owns, with
15604
+ * every other key carried as parsed. Both `~/.claude.json` and `.mcp.json`
15605
+ * decode through this — the former has many other keys, the latter none.
15606
+ */
15607
+ const McpConfigFile = Schema$1.StructWithRest(Schema$1.Struct({ mcpServers: Schema$1.optional(Schema$1.Record(Schema$1.String, Schema$1.Unknown)) }), [Schema$1.Record(Schema$1.String, Schema$1.Unknown)]);
15608
+ const McpConfigFileFromJson = Schema$1.fromJsonString(McpConfigFile);
15609
+ const decodeConfigFile = Schema$1.decodeUnknownExit(McpConfigFileFromJson);
15610
+ const encodeConfigFile = Schema$1.encodeSync(McpConfigFileFromJson);
15611
+ const decodeEntry = Schema$1.decodeUnknownExit(ClaudeMcpEntry);
15612
+ /** Where the CLI keeps user scope: `$CLAUDE_CONFIG_DIR/.claude.json` when set, else `~/.claude.json`. */
15613
+ const claudeUserConfigPath = Effect.fn("claudeUserConfigPath")(function* () {
15614
+ const path = yield* Path.Path;
15615
+ const configDir = process.env["CLAUDE_CONFIG_DIR"]?.trim() ?? "";
15616
+ return configDir.length > 0 ? path.join(path.resolve(configDir), ".claude.json") : path.join(NodeOS.homedir(), ".claude.json");
15617
+ });
15618
+ /**
15619
+ * Map one CLI entry to a registration, or nothing when it cannot be one.
15620
+ *
15621
+ * `enabled: true` because presence in the CLI's file is what enabled means
15622
+ * there. Exported for tests.
15623
+ */
15624
+ function registrationFromClaudeEntry(name, entry) {
15625
+ if (!isServerName(name)) return void 0;
15626
+ const decoded = decodeEntry(entry);
15627
+ if (decoded._tag !== "Success") return void 0;
15628
+ const value = decoded.value;
15629
+ const type = value.type ?? "stdio";
15630
+ if (type === "stdio") {
15631
+ if (value.command === void 0 || value.command.trim().length === 0) return void 0;
15632
+ return {
15633
+ name,
15634
+ transport: "stdio",
15635
+ enabled: true,
15636
+ command: value.command,
15637
+ ...value.args !== void 0 && value.args.length > 0 ? { args: value.args } : {},
15638
+ ...value.env !== void 0 && Object.keys(value.env).length > 0 ? { env: value.env } : {}
15639
+ };
15640
+ }
15641
+ if (value.url === void 0 || value.url.trim().length === 0) return void 0;
15642
+ return {
15643
+ name,
15644
+ transport: type,
15645
+ enabled: true,
15646
+ url: value.url,
15647
+ ...value.headers !== void 0 && Object.keys(value.headers).length > 0 ? { headers: value.headers } : {}
15648
+ };
15649
+ }
15650
+ /**
15651
+ * The inverse mapping, for writes. `enabled` is dropped: the CLI has no such
15652
+ * flag, and presence in the file is what enabled means there. Exported for
15653
+ * tests, so the two mappings can be checked as a round trip.
15654
+ */
15655
+ function claudeEntryFromRegistration(registration) {
15656
+ if (registration.transport === "stdio") return {
15657
+ type: "stdio",
15658
+ command: registration.command,
15659
+ ...registration.args !== void 0 && registration.args.length > 0 ? { args: registration.args } : {},
15660
+ ...registration.env !== void 0 && Object.keys(registration.env).length > 0 ? { env: registration.env } : {}
15661
+ };
15662
+ return {
15663
+ type: registration.transport,
15664
+ url: registration.url,
15665
+ ...registration.headers !== void 0 && Object.keys(registration.headers).length > 0 ? { headers: registration.headers } : {}
15666
+ };
15667
+ }
15668
+ var ClaudeMcpFiles = class extends Context.Service()("@p4code/cli/mcp/ClaudeMcpFiles") {};
15669
+ const make$64 = Effect.gen(function* () {
15670
+ const fileSystem = yield* FileSystem.FileSystem;
15671
+ const path = yield* Path.Path;
15672
+ const services = yield* Effect.context();
15673
+ const readEntries = Effect.fn("ClaudeMcpFiles.readEntries")(function* (filePath) {
15674
+ const raw = yield* fileSystem.readFileString(filePath).pipe(Effect.orElseSucceed(() => void 0));
15675
+ if (raw === void 0) return [];
15676
+ const decoded = decodeConfigFile(raw);
15677
+ if (decoded._tag !== "Success") return [];
15678
+ const found = [];
15679
+ for (const [name, entry] of Object.entries(decoded.value.mcpServers ?? {})) {
15680
+ const registration = registrationFromClaudeEntry(name, entry);
15681
+ if (registration !== void 0) found.push(registration);
15682
+ }
15683
+ return found;
15684
+ });
15685
+ const readAt = (filePath) => filePath.pipe(Effect.flatMap((resolved) => readEntries(resolved)), Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("claude mcp config read failed", { cause }).pipe(Effect.as([]))));
15686
+ /**
15687
+ * Read, change the one key, write back atomically.
15688
+ *
15689
+ * A file that exists but will not parse fails the write loudly instead of
15690
+ * being replaced with `{ mcpServers }`: whatever is in it — including a
15691
+ * `~/.claude.json` full of the CLI's own state — is worth more than the
15692
+ * edit. A missing file starts from empty, which is how `.mcp.json` is born.
15693
+ */
15694
+ const changeFile = Effect.fn("ClaudeMcpFiles.changeFile")(function* (filePath, change) {
15695
+ const raw = yield* fileSystem.readFileString(filePath).pipe(Effect.orElseSucceed(() => void 0), Effect.provide(services));
15696
+ const decoded = raw === void 0 ? void 0 : decodeConfigFile(raw);
15697
+ if (decoded !== void 0 && decoded._tag !== "Success") return yield* new McpRegistryError({ detail: `${filePath} exists but could not be parsed, so it was left alone.` });
15698
+ const root = decoded === void 0 ? {} : decoded.value;
15699
+ const nextServers = change({ ...root.mcpServers });
15700
+ yield* fileSystem.makeDirectory(path.dirname(filePath), { recursive: true }).pipe(Effect.ignore, Effect.provide(services));
15701
+ yield* writeFileStringAtomically({
15702
+ filePath,
15703
+ contents: `${encodeConfigFile({
15704
+ ...root,
15705
+ mcpServers: nextServers
15706
+ })}\n`
15707
+ }).pipe(Effect.provide(services), Effect.mapError(() => new McpRegistryError({ detail: `Could not write ${filePath}.` })));
15708
+ });
15709
+ const projectFile = (projectDir) => path.join(path.resolve(projectDir), PROJECT_MCP_FILENAME);
15710
+ const upsertAt = (filePath) => Effect.fn("ClaudeMcpFiles.upsertAt")(function* (registration) {
15711
+ const resolved = yield* filePath.pipe(Effect.provide(services));
15712
+ yield* changeFile(resolved, (entries) => ({
15713
+ ...entries,
15714
+ [registration.name]: claudeEntryFromRegistration(registration)
15715
+ }));
15716
+ });
15717
+ const removeAt = (filePath) => Effect.fn("ClaudeMcpFiles.removeAt")(function* (name) {
15718
+ const resolved = yield* filePath.pipe(Effect.provide(services));
15719
+ yield* changeFile(resolved, (entries) => {
15720
+ const { [name]: _removed, ...rest } = entries;
15721
+ return rest;
15722
+ });
15723
+ });
15724
+ const userPath = claudeUserConfigPath();
15725
+ return {
15726
+ readUser: readAt(userPath),
15727
+ upsertUser: (registration) => upsertAt(userPath)(registration),
15728
+ removeUser: (name) => removeAt(userPath)(name),
15729
+ readProject: (projectDir) => readAt(Effect.succeed(projectFile(projectDir))),
15730
+ upsertProject: (projectDir, registration) => upsertAt(Effect.succeed(projectFile(projectDir)))(registration),
15731
+ removeProject: (projectDir, name) => removeAt(Effect.succeed(projectFile(projectDir)))(name)
15732
+ };
15733
+ });
15734
+ const layer$59 = Layer.effect(ClaudeMcpFiles, make$64);
15735
+ Layer.succeed(ClaudeMcpFiles, {
15736
+ readUser: Effect.succeed([]),
15737
+ upsertUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
15738
+ removeUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
15739
+ readProject: () => Effect.succeed([]),
15740
+ upsertProject: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
15741
+ removeProject: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." }))
15742
+ });
15743
+ //#endregion
15513
15744
  //#region src/mcp/McpOAuth.ts
15514
15745
  /**
15515
15746
  * OAuth sign-in for remote MCP servers, per the MCP authorization spec.
@@ -15978,6 +16209,7 @@ const make$62 = Effect.gen(function* () {
15978
16209
  const config = yield* ServerConfig$1;
15979
16210
  const secrets = yield* ServerSecretStore;
15980
16211
  const oauth = yield* McpOAuth;
16212
+ const claudeFiles = yield* ClaudeMcpFiles;
15981
16213
  const fileSystem = yield* FileSystem.FileSystem;
15982
16214
  const path = yield* Path.Path;
15983
16215
  const services = yield* Effect.context();
@@ -16026,7 +16258,21 @@ const make$62 = Effect.gen(function* () {
16026
16258
  registration,
16027
16259
  missingSecrets,
16028
16260
  ready: registration.enabled && missingSecrets.length === 0 && !needsSignIn,
16029
- ...Option.isSome(oauthStatus) ? { oauth: oauthStatus.value } : {}
16261
+ ...Option.isSome(oauthStatus) ? { oauth: oauthStatus.value } : {},
16262
+ source: "registry"
16263
+ });
16264
+ }
16265
+ const registryNames = new Set(statuses.map((status) => status.registration.name));
16266
+ for (const userScope of yield* claudeFiles.readUser) {
16267
+ if (registryNames.has(userScope.name)) continue;
16268
+ const oauthStatus = userScope.transport === "stdio" ? Option.none() : yield* oauth.statusFor(userScope);
16269
+ const needsSignIn = Option.isSome(oauthStatus) && !oauthStatus.value.connected;
16270
+ statuses.push({
16271
+ registration: userScope,
16272
+ missingSecrets: [],
16273
+ ready: !needsSignIn,
16274
+ ...Option.isSome(oauthStatus) ? { oauth: oauthStatus.value } : {},
16275
+ source: "claude"
16030
16276
  });
16031
16277
  }
16032
16278
  return statuses;
@@ -16092,6 +16338,20 @@ const make$62 = Effect.gen(function* () {
16092
16338
  headers
16093
16339
  };
16094
16340
  }
16341
+ for (const userScope of yield* claudeFiles.readUser) {
16342
+ if (userScope.transport === "stdio") continue;
16343
+ if (userScope.name in resolved) continue;
16344
+ const token = yield* oauth.accessTokenFor(userScope);
16345
+ if (Option.isNone(token)) continue;
16346
+ resolved[userScope.name] = {
16347
+ type: userScope.transport,
16348
+ url: userScope.url,
16349
+ headers: {
16350
+ ...userScope.headers,
16351
+ Authorization: `Bearer ${token.value}`
16352
+ }
16353
+ };
16354
+ }
16095
16355
  return resolved;
16096
16356
  }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry resolve failed", { cause }).pipe(Effect.as({}))))
16097
16357
  };
@@ -17813,7 +18073,7 @@ const make$59 = Effect.gen(function* () {
17813
18073
  const layer$54 = Layer.effect(AssetSync, make$59);
17814
18074
  //#endregion
17815
18075
  //#region src/cli/assets.ts
17816
- const SyncServicesLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56), Layer.provideMerge(layer$59.pipe(Layer.provide(layer$66))), Layer.provideMerge(layer$66), Layer.provideMerge(FetchHttpClient.layer));
18076
+ const SyncServicesLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56), Layer.provideMerge(layer$60.pipe(Layer.provide(layer$67))), Layer.provideMerge(layer$67), Layer.provideMerge(FetchHttpClient.layer));
17817
18077
  const runWithSync = (flags, run) => Effect.gen(function* () {
17818
18078
  const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
17819
18079
  return yield* Effect.gen(function* () {
@@ -17821,7 +18081,7 @@ const runWithSync = (flags, run) => Effect.gen(function* () {
17821
18081
  sync: yield* AssetSync,
17822
18082
  link: yield* HubLink
17823
18083
  });
17824
- }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
18084
+ }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$70(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
17825
18085
  });
17826
18086
  const STATE_LABEL = {
17827
18087
  synced: "synced",
@@ -28407,7 +28667,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
28407
28667
  });
28408
28668
  yield* Console.log(output);
28409
28669
  }));
28410
- const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
28670
+ const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$70(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
28411
28671
  return yield* Effect.gen(function* () {
28412
28672
  const snapshot = yield* getOfflineSnapshot();
28413
28673
  const orchestrationEngine = yield* OrchestrationEngineService;
@@ -28418,7 +28678,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
28418
28678
  });
28419
28679
  yield* Console.log(output);
28420
28680
  }).pipe(Effect.provide(offlineRuntimeLayer));
28421
- }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$43).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
28681
+ }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$43).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$70(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
28422
28682
  });
28423
28683
  const projectAddCommand = Command.make("add", {
28424
28684
  ...projectLocationFlags,
@@ -44046,6 +44306,22 @@ function toAuthAccessStreamEvent(change, revision, currentSessionId) {
44046
44306
  };
44047
44307
  }
44048
44308
  }
44309
+ /**
44310
+ * Route one MCP write to the store its `source` names.
44311
+ *
44312
+ * `claude` and `project` write the CLI's own files; `registry` (or absent,
44313
+ * which every older client sends) writes p4code's store. A project write
44314
+ * without a directory is a caller bug worth a loud answer, not a fallback.
44315
+ */
44316
+ const routeMcpWrite = (input, handlers) => {
44317
+ if (input.source === "claude") return handlers.claude();
44318
+ if (input.source === "project") {
44319
+ const dir = input.projectDir?.trim() ?? "";
44320
+ if (dir.length === 0) return Effect.fail(new McpRegistryError({ detail: "A project-scope write needs its project directory." }));
44321
+ return handlers.project(dir);
44322
+ }
44323
+ return handlers.registry();
44324
+ };
44049
44325
  const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.toLayer(Effect.gen(function* () {
44050
44326
  const currentSessionId = currentSession.sessionId;
44051
44327
  const crypto = yield* Crypto.Crypto;
@@ -44074,7 +44350,26 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
44074
44350
  const assetSync = yield* AssetSync;
44075
44351
  const mcpRegistry = yield* McpRegistry;
44076
44352
  const mcpOAuth = yield* McpOAuth;
44353
+ const claudeMcpFiles = yield* ClaudeMcpFiles;
44077
44354
  const skillRegistry = yield* SkillRegistry;
44355
+ const listMcpServersEverywhere = Effect.gen(function* () {
44356
+ const servers = [...yield* mcpRegistry.list];
44357
+ const projectRows = yield* projectionProjects.listAll().pipe(Effect.map((rows) => rows.filter((row) => row.deletedAt === null)), Effect.orElseSucceed(() => []));
44358
+ for (const project of projectRows) for (const registration of yield* claudeMcpFiles.readProject(project.workspaceRoot)) servers.push({
44359
+ registration,
44360
+ missingSecrets: [],
44361
+ ready: true,
44362
+ source: "project",
44363
+ projectDir: project.workspaceRoot
44364
+ });
44365
+ return {
44366
+ servers,
44367
+ projects: projectRows.map((project) => ({
44368
+ dir: project.workspaceRoot,
44369
+ title: project.title
44370
+ }))
44371
+ };
44372
+ });
44078
44373
  const startup = yield* ServerRuntimeStartup;
44079
44374
  const workspaceEntries = yield* WorkspaceEntries;
44080
44375
  const workspaceFileSystem = yield* WorkspaceFileSystem;
@@ -44667,21 +44962,35 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
44667
44962
  }), { "rpc.aggregate": "skills" }),
44668
44963
  [WS_METHODS.skillRegistrySearch]: ({ query }) => observeRpcEffect$1(WS_METHODS.skillRegistrySearch, skillRegistry.search(query), { "rpc.aggregate": "skills" }),
44669
44964
  [WS_METHODS.skillRegistryFetch]: ({ id }) => observeRpcEffect$1(WS_METHODS.skillRegistryFetch, skillRegistry.fetch(id), { "rpc.aggregate": "skills" }),
44670
- [WS_METHODS.mcpList]: (_input) => observeRpcEffect$1(WS_METHODS.mcpList, mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))), { "rpc.aggregate": "mcp" }),
44671
- [WS_METHODS.mcpSave]: ({ registration }) => observeRpcEffect$1(WS_METHODS.mcpSave, mcpRegistry.save(registration).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
44672
- [WS_METHODS.mcpRemove]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpRemove, mcpRegistry.remove(name).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
44965
+ [WS_METHODS.mcpList]: (_input) => observeRpcEffect$1(WS_METHODS.mcpList, listMcpServersEverywhere, { "rpc.aggregate": "mcp" }),
44966
+ [WS_METHODS.mcpSave]: ({ registration, source, projectDir }) => observeRpcEffect$1(WS_METHODS.mcpSave, routeMcpWrite({
44967
+ source,
44968
+ projectDir
44969
+ }, {
44970
+ claude: () => claudeMcpFiles.upsertUser(registration),
44971
+ project: (dir) => claudeMcpFiles.upsertProject(dir, registration),
44972
+ registry: () => mcpRegistry.save(registration)
44973
+ }).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
44974
+ [WS_METHODS.mcpRemove]: ({ name, source, projectDir }) => observeRpcEffect$1(WS_METHODS.mcpRemove, routeMcpWrite({
44975
+ source,
44976
+ projectDir
44977
+ }, {
44978
+ claude: () => claudeMcpFiles.removeUser(name),
44979
+ project: (dir) => claudeMcpFiles.removeProject(dir, name),
44980
+ registry: () => mcpRegistry.remove(name)
44981
+ }).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
44673
44982
  [WS_METHODS.mcpSetSecret]: ({ name, slot, value }) => observeRpcEffect$1(WS_METHODS.mcpSetSecret, mcpRegistry.setSecret({
44674
44983
  name,
44675
44984
  slot,
44676
44985
  value
44677
- }).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
44986
+ }).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
44678
44987
  [WS_METHODS.mcpOAuthBegin]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpOAuthBegin, Effect.gen(function* () {
44679
44988
  const found = (yield* mcpRegistry.list).find((status) => status.registration.name === name);
44680
44989
  if (found === void 0) return yield* new McpRegistryError({ detail: `No server is named ${name}.` });
44681
44990
  if (found.registration.transport === "stdio") return yield* new McpRegistryError({ detail: "A stdio server is launched locally and has no sign-in." });
44682
44991
  return yield* mcpOAuth.begin(found.registration);
44683
44992
  }), { "rpc.aggregate": "mcp" }),
44684
- [WS_METHODS.mcpOAuthDisconnect]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpOAuthDisconnect, mcpOAuth.disconnect(name).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
44993
+ [WS_METHODS.mcpOAuthDisconnect]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpOAuthDisconnect, mcpOAuth.disconnect(name).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
44685
44994
  [WS_METHODS.serverGetSettings]: (_input) => observeRpcEffect$1(WS_METHODS.serverGetSettings, serverSettings.getSettings.pipe(Effect.map(redactServerSettingsForClient)), { "rpc.aggregate": "server" }),
44686
44995
  [WS_METHODS.serverUpdateSettings]: ({ patch }) => observeRpcEffect$1(WS_METHODS.serverUpdateSettings, serverSettings.updateSettings(patch).pipe(Effect.map(redactServerSettingsForClient)), { "rpc.aggregate": "server" }),
44687
44996
  [WS_METHODS.serverDiscoverSourceControl]: (_input) => observeRpcEffect$1(WS_METHODS.serverDiscoverSourceControl, sourceControlDiscovery.discover, { "rpc.aggregate": "server" }),
@@ -47179,7 +47488,7 @@ const makeOpenCodeRuntime = Effect.gen(function* () {
47179
47488
  };
47180
47489
  });
47181
47490
  var OpenCodeRuntime = class extends Context.Service()("@p4code/cli/provider/opencodeRuntime") {};
47182
- const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$70));
47491
+ const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$71));
47183
47492
  //#endregion
47184
47493
  //#region src/textGeneration/TextGenerationUtils.ts
47185
47494
  const isTextGenerationError$2 = Schema$1.is(TextGenerationError);
@@ -86464,9 +86773,9 @@ const WorkspaceEntriesLayerLive = layer$25.pipe(Layer.provide(layer$43));
86464
86773
  const WorkspaceFileSystemLayerLive = layer$24.pipe(Layer.provide(layer$43), Layer.provide(WorkspaceEntriesLayerLive));
86465
86774
  const WorkspaceLayerLive = Layer.mergeAll(layer$43, WorkspaceEntriesLayerLive, WorkspaceFileSystemLayerLive);
86466
86775
  const ProjectFaviconResolverLayerLive = layer$41.pipe(Layer.provide(layer$43), Layer.provide(layer$42));
86467
- const AuthLayerLive = layer$62.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$66));
86776
+ const AuthLayerLive = layer$63.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$67));
86468
86777
  const ProviderRuntimeLayerLive = ProviderSessionReaperLive.pipe(Layer.provideMerge(ProviderLayerLive), Layer.provideMerge(OrchestrationLayerLive));
86469
- const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(CheckpointingLayerLive), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(GitLayerLive), Layer.provideMerge(VcsLayerLive), Layer.provideMerge(ProviderRuntimeLayerLive), Layer.provideMerge(Layer.mergeAll(TerminalLayerLive, PreviewLayerLive)), Layer.provideMerge(PersistenceLayerLive), Layer.provideMerge(layer$51), Layer.provideMerge(ProviderRegistryLive), Layer.provideMerge(ProviderInstanceRegistryHydrationLive), Layer.provideMerge(ProviderEventLoggersLive), Layer.provideMerge(OpenCodeRuntimeLive), Layer.provideMerge(layer$59.pipe(Layer.provide(layer$66))), Layer.provideMerge(WorkspaceLayerLive), Layer.provideMerge(ProjectFaviconResolverLayerLive), Layer.provideMerge(layer$52), Layer.provideMerge(layer$45), Layer.provideMerge(AuthLayerLive), Layer.provideMerge(Layer.mergeAll(layer$57, layer$31).pipe(Layer.provideMerge(layer$58))), Layer.provideMerge(layer$66)).pipe(Layer.provideMerge(layer$8), Layer.provideMerge(layer$7), Layer.provideMerge(layer$6), Layer.provideMerge(layer$48), Layer.provideMerge(layer$50), Layer.provideMerge(layer$49), Layer.provide(layer$70));
86778
+ const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(CheckpointingLayerLive), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(GitLayerLive), Layer.provideMerge(VcsLayerLive), Layer.provideMerge(ProviderRuntimeLayerLive), Layer.provideMerge(Layer.mergeAll(TerminalLayerLive, PreviewLayerLive)), Layer.provideMerge(PersistenceLayerLive), Layer.provideMerge(layer$51), Layer.provideMerge(ProviderRegistryLive), Layer.provideMerge(ProviderInstanceRegistryHydrationLive), Layer.provideMerge(ProviderEventLoggersLive), Layer.provideMerge(OpenCodeRuntimeLive), Layer.provideMerge(layer$60.pipe(Layer.provide(layer$67))), Layer.provideMerge(WorkspaceLayerLive), Layer.provideMerge(ProjectFaviconResolverLayerLive), Layer.provideMerge(layer$52), Layer.provideMerge(layer$45), Layer.provideMerge(AuthLayerLive), Layer.provideMerge(Layer.mergeAll(layer$57, layer$31).pipe(Layer.provideMerge(layer$58), Layer.provideMerge(layer$59))), Layer.provideMerge(layer$67)).pipe(Layer.provideMerge(layer$8), Layer.provideMerge(layer$7), Layer.provideMerge(layer$6), Layer.provideMerge(layer$48), Layer.provideMerge(layer$50), Layer.provideMerge(layer$49), Layer.provide(layer$71));
86470
86779
  /**
86471
86780
  * Hub asset sync.
86472
86781
  *
@@ -86886,7 +87195,7 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
86886
87195
  ]));
86887
87196
  //#endregion
86888
87197
  //#region src/bin.ts
86889
- const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$70, FetchHttpClient.layer);
87198
+ const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$71, FetchHttpClient.layer);
86890
87199
  /**
86891
87200
  * Prints an update reminder before dispatching, at most once a day.
86892
87201
  *