@p4code/cli 0.1.14 → 0.1.16

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 (89) hide show
  1. package/dist/bin.mjs +408 -58
  2. package/dist/client/assets/DiffPanel-rTTo7hcH.js +98 -0
  3. package/dist/client/assets/{FilePreviewPanel-CWcDqLso.js → FilePreviewPanel-CXPZlxI3.js} +5 -5
  4. package/dist/client/assets/PreviewPanel-BFuAVjo6.js +2 -0
  5. package/dist/client/assets/{angular-html-BLv19dHn.js → angular-html-B5E_J1fS.js} +2 -2
  6. package/dist/client/assets/{angular-ts-D41w0Au3.js → angular-ts-COv5JKxn.js} +2 -2
  7. package/dist/client/assets/{apl-BEl8UFu4.js → apl-BQsQyMXO.js} +2 -2
  8. package/dist/client/assets/arrow-right-SCFydakV.js +2 -0
  9. package/dist/client/assets/{astro-U1Y_O85L.js → astro-B8L9Cn_4.js} +2 -2
  10. package/dist/client/assets/{blade-CZ232EWr.js → blade-B_Che9pT.js} +2 -2
  11. package/dist/client/assets/{c-DirgNKaz.js → c-CPSBTKBx.js} +2 -2
  12. package/dist/client/assets/{cobol-B7WyPi1F.js → cobol-BriE1iNK.js} +2 -2
  13. package/dist/client/assets/{coffee-C_qHkMIP.js → coffee-ClgsI2Oz.js} +2 -2
  14. package/dist/client/assets/{cpp-SPUhkLTs.js → cpp-BoIGp4CN.js} +2 -2
  15. package/dist/client/assets/{crystal-vq6jdakY.js → crystal-B-s92Xor.js} +2 -2
  16. package/dist/client/assets/{css-BAnKum7K.js → css-lm7yIvqf.js} +2 -2
  17. package/dist/client/assets/{edge-BuMKesaI.js → edge-BdwKb_XJ.js} +2 -2
  18. package/dist/client/assets/{elixir-BL-W6BH4.js → elixir-Dd3gZy8B.js} +2 -2
  19. package/dist/client/assets/{elm-DiUCNL3v.js → elm-BUwJ0Z6D.js} +2 -2
  20. package/dist/client/assets/{erb-skcSurJb.js → erb-BmkGyaa3.js} +2 -2
  21. package/dist/client/assets/{fileCommentAnnotations-BRTew3I1.js → fileCommentAnnotations-aElZ1ls9.js} +2 -2
  22. package/dist/client/assets/{git-rebase-dO-xI28x.js → git-rebase-CgG-fpnH.js} +2 -2
  23. package/dist/client/assets/{glimmer-js-CECukRm7.js → glimmer-js-CgCxySf7.js} +2 -2
  24. package/dist/client/assets/{glimmer-ts-CIaRC8zm.js → glimmer-ts-D0qJCdA3.js} +2 -2
  25. package/dist/client/assets/{glsl-CKSbugKg.js → glsl-D-TJl_NC.js} +2 -2
  26. package/dist/client/assets/{graphql-BiZ7twV7.js → graphql-tJKOdjT8.js} +2 -2
  27. package/dist/client/assets/{hack-BdAxCPD7.js → hack-CNRyS4CV.js} +2 -2
  28. package/dist/client/assets/{haml-SZR9Ndrp.js → haml-DZHEkAiU.js} +2 -2
  29. package/dist/client/assets/{handlebars-BExVQKqz.js → handlebars-C2vebdS9.js} +2 -2
  30. package/dist/client/assets/{html-CkYFYJn1.js → html-DCuQyWj1.js} +2 -2
  31. package/dist/client/assets/{html-derivative-Cop3EQeZ.js → html-derivative-C5tQldZt.js} +2 -2
  32. package/dist/client/assets/{http-DQ8c4u3s.js → http-BAgKJQ4_.js} +2 -2
  33. package/dist/client/assets/{hurl-BKyyIuNR.js → hurl-CPO35wiX.js} +2 -2
  34. package/dist/client/assets/index-DXGA7g9I.js +655 -0
  35. package/dist/client/assets/index-MItVmi4T.css +1 -0
  36. package/dist/client/assets/{java-CedFcWif.js → java-DdKunJP-.js} +2 -2
  37. package/dist/client/assets/{javascript-BdXDoWFM.js → javascript-BzCImGGh.js} +2 -2
  38. package/dist/client/assets/{jinja-CK8YWL7a.js → jinja-KxDS67Zm.js} +2 -2
  39. package/dist/client/assets/{jison-C-mnFz-X.js → jison-CB_VQ7nH.js} +2 -2
  40. package/dist/client/assets/{json-Dxix4Qbo.js → json-DW5yQfU4.js} +2 -2
  41. package/dist/client/assets/{jsx-6M0gL61I.js → jsx-BCRm4K8K.js} +2 -2
  42. package/dist/client/assets/{julia-SXfQGJ8P.js → julia-B7zmtt-j.js} +2 -2
  43. package/dist/client/assets/{just-O0TR05uE.js → just-BPUjF3fe.js} +2 -2
  44. package/dist/client/assets/{latex-w7R_uAyc.js → latex-DlHsgJiO.js} +2 -2
  45. package/dist/client/assets/{liquid-hPzEzmzZ.js → liquid-DkAYrmIm.js} +2 -2
  46. package/dist/client/assets/{lua-D24pQ94w.js → lua-CkWXcEtU.js} +2 -2
  47. package/dist/client/assets/{marko-DsaGFeHY.js → marko-BreU7Tr4.js} +2 -2
  48. package/dist/client/assets/{mdc-C4vifn2U.js → mdc-BIy4U_CM.js} +2 -2
  49. package/dist/client/assets/{nginx-KnKOgHWr.js → nginx-CaBRBNvW.js} +2 -2
  50. package/dist/client/assets/{nim-CXVNWegc.js → nim-Dh_VcD-W.js} +2 -2
  51. package/dist/client/assets/{perl-_PU7gLJn.js → perl-DljrVQhk.js} +2 -2
  52. package/dist/client/assets/{php-B--0cDl3.js → php-DcpMefw4.js} +2 -2
  53. package/dist/client/assets/{pug-DELbYjHv.js → pug-BquSKFGg.js} +2 -2
  54. package/dist/client/assets/{qml-CyGKPCuH.js → qml-DEzduZ1z.js} +2 -2
  55. package/dist/client/assets/{r-CSjDVJJY.js → r-D0PJ1YHw.js} +2 -2
  56. package/dist/client/assets/{razor-ppZnQuQy.js → razor-C9NzXzG1.js} +2 -2
  57. package/dist/client/assets/{regexp-DAYlObpi.js → regexp-Bppxv8Nd.js} +2 -2
  58. package/dist/client/assets/{rst-DV8sAt14.js → rst-BHL4HPZF.js} +2 -2
  59. package/dist/client/assets/{ruby-DXISWktP.js → ruby-BgqgMbbJ.js} +2 -2
  60. package/dist/client/assets/{sas-CJl6Tu3p.js → sas-CWVKvcbG.js} +2 -2
  61. package/dist/client/assets/{scss-DmbKMDuD.js → scss-Cw6AvzKE.js} +2 -2
  62. package/dist/client/assets/{shellscript-BFH8QS9G.js → shellscript-BmSXT-3L.js} +2 -2
  63. package/dist/client/assets/{shellsession-CIHFsdwm.js → shellsession-CoR9jXze.js} +2 -2
  64. package/dist/client/assets/{soy--q_a3wNH.js → soy-C4LA8zVY.js} +2 -2
  65. package/dist/client/assets/{sql-DE3xygzU.js → sql-ByI0x14l.js} +2 -2
  66. package/dist/client/assets/{stata-BZORI8K-.js → stata-fHDl5JMD.js} +2 -2
  67. package/dist/client/assets/{surrealql-DQwYGqPv.js → surrealql-bNPgbvaA.js} +2 -2
  68. package/dist/client/assets/{svelte-C8rcZCbS.js → svelte-BvpeBLSH.js} +2 -2
  69. package/dist/client/assets/{templ-YxwRimHC.js → templ-uUxwDReQ.js} +2 -2
  70. package/dist/client/assets/{tex-CreWrrVU.js → tex-DvBkmY5z.js} +2 -2
  71. package/dist/client/assets/textarea-CbUaa52I.js +46 -0
  72. package/dist/client/assets/{ts-tags-BGYLwTar.js → ts-tags-CNdGGSEK.js} +2 -2
  73. package/dist/client/assets/{tsx-dvRLM93g.js → tsx-C-xKLmxT.js} +2 -2
  74. package/dist/client/assets/{twig-BwKK1q-j.js → twig-BwP3uniF.js} +2 -2
  75. package/dist/client/assets/{typescript-CIA9s0mZ.js → typescript-EVQqiZdz.js} +2 -2
  76. package/dist/client/assets/{vue-RR_2K8-s.js → vue-CcDCYMax.js} +2 -2
  77. package/dist/client/assets/{vue-html-SobvEO2e.js → vue-html-D78T-MxH.js} +2 -2
  78. package/dist/client/assets/{vue-vine-BQgxB5Yf.js → vue-vine-CZ6XjTDM.js} +2 -2
  79. package/dist/client/assets/{xml-qR9OaTYe.js → xml-Clr4M-ss.js} +2 -2
  80. package/dist/client/assets/{xsl-CNAIK0Wp.js → xsl-CboPzliu.js} +2 -2
  81. package/dist/client/assets/{yaml-CnmdSZli.js → yaml-DOfnzofq.js} +2 -2
  82. package/dist/client/index.html +3 -3
  83. package/package.json +1 -1
  84. package/dist/client/assets/DiffPanel-BdNsdwM5.js +0 -98
  85. package/dist/client/assets/PreviewPanel-2u47bK5v.js +0 -2
  86. package/dist/client/assets/arrow-right-Tef5pBUM.js +0 -2
  87. package/dist/client/assets/index-ClVe76A5.js +0 -660
  88. package/dist/client/assets/index-DGu8ejUP.css +0 -1
  89. 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.16";
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");
@@ -5024,14 +5024,18 @@ const UserInputResolvedPayload = Schema$1.Struct({ answers: UnknownRecordSchema
5024
5024
  const TaskStartedPayload = Schema$1.Struct({
5025
5025
  taskId: RuntimeTaskId,
5026
5026
  description: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5027
- taskType: Schema$1.optional(TrimmedNonEmptyStringSchema$1)
5027
+ taskType: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5028
+ toolUseId: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5029
+ subagentType: Schema$1.optional(TrimmedNonEmptyStringSchema$1)
5028
5030
  });
5029
5031
  const TaskProgressPayload = Schema$1.Struct({
5030
5032
  taskId: RuntimeTaskId,
5031
5033
  description: TrimmedNonEmptyStringSchema$1,
5032
5034
  summary: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5033
5035
  usage: Schema$1.optional(Schema$1.Unknown),
5034
- lastToolName: Schema$1.optional(TrimmedNonEmptyStringSchema$1)
5036
+ lastToolName: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5037
+ toolUseId: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5038
+ subagentType: Schema$1.optional(TrimmedNonEmptyStringSchema$1)
5035
5039
  });
5036
5040
  const TaskCompletedPayload = Schema$1.Struct({
5037
5041
  taskId: RuntimeTaskId,
@@ -5041,7 +5045,8 @@ const TaskCompletedPayload = Schema$1.Struct({
5041
5045
  "stopped"
5042
5046
  ]),
5043
5047
  summary: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5044
- usage: Schema$1.optional(Schema$1.Unknown)
5048
+ usage: Schema$1.optional(Schema$1.Unknown),
5049
+ toolUseId: Schema$1.optional(TrimmedNonEmptyStringSchema$1)
5045
5050
  });
5046
5051
  const HookStartedPayload = Schema$1.Struct({
5047
5052
  hookId: TrimmedNonEmptyStringSchema$1,
@@ -7054,14 +7059,28 @@ const TASK_ASSIGNEE_MAX_LENGTH = 128;
7054
7059
  * Board columns, in board order. `backlog` is the default for newly created
7055
7060
  * tasks — an agent filing a task mid-session is recording work that exists, not
7056
7061
  * committing to doing it next.
7062
+ *
7063
+ * `cancelled` is the other way a task closes: decided against, superseded or
7064
+ * merged into another task. Marking such a task `done` is the workaround it
7065
+ * replaces, and it lies - a board that says five things finished when two of
7066
+ * them were dropped is not worth reading.
7057
7067
  */
7058
7068
  const TaskStatus = Schema$1.Literals([
7059
7069
  "backlog",
7060
7070
  "todo",
7061
7071
  "in_progress",
7062
7072
  "in_review",
7063
- "done"
7073
+ "done",
7074
+ "cancelled"
7064
7075
  ]);
7076
+ /**
7077
+ * What a status this build has never heard of decodes to when read back.
7078
+ *
7079
+ * `backlog` is the least dishonest guess: it says "recorded, nothing claimed
7080
+ * about it", which is true of a status we cannot interpret. Guessing `done` or
7081
+ * `cancelled` would claim the task is closed.
7082
+ */
7083
+ const UNKNOWN_TASK_STATUS_FALLBACK = "backlog";
7065
7084
  const TaskPriority = Schema$1.Literals([
7066
7085
  "none",
7067
7086
  "low",
@@ -7093,7 +7112,19 @@ const ProjectIdField = ProjectId.pipe(Schema$1.annotateEncoded({ description: "I
7093
7112
  const ThreadIdField = ThreadId.pipe(Schema$1.annotateEncoded({ description: "Id of the agent thread working this task." }));
7094
7113
  const TitleField = TrimmedNonEmptyString.check(Schema$1.isMaxLength(TASK_TITLE_MAX_LENGTH)).pipe(Schema$1.annotateEncoded({ description: "One-line summary of the work. Required." }));
7095
7114
  const BodyField = Schema$1.String.pipe(Schema$1.annotateEncoded({ description: "Markdown detail: context, acceptance criteria, links." }));
7096
- const StatusField = TaskStatus.pipe(Schema$1.annotateEncoded({ description: "Board column: backlog (recorded, not queued), todo (queued next), in_progress, in_review, done." }));
7115
+ const StatusField = TaskStatus.pipe(Schema$1.annotateEncoded({ description: "Board column: backlog (recorded, not queued), todo (queued next), in_progress, in_review, done, cancelled (closed without doing the work)." }));
7116
+ /**
7117
+ * The status as read back from a store, tolerant of values this build predates.
7118
+ *
7119
+ * A board can be shared between machines running different versions, and a
7120
+ * newer peer may write a status added after this client shipped. A strict
7121
+ * literal would fail the decode of the whole page, so one unknown row would
7122
+ * blank the board behind a "hub is unavailable" error rather than degrade. An
7123
+ * unrecognized status therefore decodes to {@link UNKNOWN_TASK_STATUS_FALLBACK},
7124
+ * same spirit as the nullable `readableId` and `orderKey` below. Encoding stays
7125
+ * strict: this client can only ever write a status it knows.
7126
+ */
7127
+ const StoredStatusField = TaskStatus.pipe(Schema$1.catchDecoding(() => Effect.succeedSome(UNKNOWN_TASK_STATUS_FALLBACK)));
7097
7128
  const PriorityField = TaskPriority.pipe(Schema$1.annotateEncoded({ description: "Relative urgency: none, low, medium, high or urgent." }));
7098
7129
  const AssigneeField = TrimmedNonEmptyString.check(Schema$1.isMaxLength(TASK_ASSIGNEE_MAX_LENGTH)).pipe(Schema$1.annotateEncoded({ description: "Who owns the task — a person's handle or an agent name." }));
7099
7130
  /**
@@ -7161,7 +7192,7 @@ const Task = Schema$1.Struct({
7161
7192
  threadId: Schema$1.NullOr(ThreadId),
7162
7193
  title: TrimmedNonEmptyString.check(Schema$1.isMaxLength(TASK_TITLE_MAX_LENGTH)),
7163
7194
  body: Schema$1.String,
7164
- status: TaskStatus,
7195
+ status: StoredStatusField,
7165
7196
  priority: TaskPriority,
7166
7197
  assignee: Schema$1.NullOr(TrimmedNonEmptyString.check(Schema$1.isMaxLength(TASK_ASSIGNEE_MAX_LENGTH))),
7167
7198
  labels: Schema$1.Array(TaskLabel).check(Schema$1.isMaxLength(TASK_LABELS_MAX_COUNT)),
@@ -8217,17 +8248,62 @@ const McpServerOAuthStatus = Schema$1.Struct({
8217
8248
  * unusable *here*, and saying which slot is empty is the difference between a
8218
8249
  * fixable state and a mystery.
8219
8250
  */
8251
+ /**
8252
+ * Where a listed server lives, which is also where an edit goes.
8253
+ *
8254
+ * `claude` is the CLI's user scope (`~/.claude.json`) — the primary home,
8255
+ * because every Claude Code session reads it, inside p4code and out.
8256
+ * `project` is one workspace project's `.mcp.json`, committed with the repo.
8257
+ * `registry` is p4code's own store, the only one that syncs through the hub
8258
+ * and carries secret slots.
8259
+ */
8260
+ const McpServerSource = Schema$1.Literals([
8261
+ "registry",
8262
+ "claude",
8263
+ "project"
8264
+ ]);
8220
8265
  const McpServerStatus = Schema$1.Struct({
8221
8266
  registration: McpServerRegistration,
8222
8267
  missingSecrets: Schema$1.Array(McpSecretSlot),
8223
8268
  /** True when this machine holds everything needed to start it. */
8224
8269
  ready: Schema$1.Boolean,
8225
8270
  /** Absent for servers that never challenged and hold no token here. */
8226
- oauth: Schema$1.optional(McpServerOAuthStatus)
8271
+ oauth: Schema$1.optional(McpServerOAuthStatus),
8272
+ /** Absent means `registry`, which every row was before this field existed. */
8273
+ source: Schema$1.optional(McpServerSource),
8274
+ /** The workspace root whose `.mcp.json` holds this row. `project` rows only. */
8275
+ projectDir: Schema$1.optional(Schema$1.String)
8276
+ });
8277
+ /** A workspace project the panel can scope a server to. */
8278
+ const McpProjectRef = Schema$1.Struct({
8279
+ dir: Schema$1.String,
8280
+ title: Schema$1.String
8281
+ });
8282
+ const McpServerList = Schema$1.Struct({
8283
+ servers: Schema$1.Array(McpServerStatus),
8284
+ /**
8285
+ * The projects whose `.mcp.json` can be edited, for the add dialog's scope
8286
+ * picker. Carried with the list so the panel needs no second request.
8287
+ */
8288
+ projects: Schema$1.optional(Schema$1.Array(McpProjectRef))
8289
+ });
8290
+ /**
8291
+ * `source` routes the write: `claude` edits the `mcpServers` key of the
8292
+ * CLI's user-scope file, `registry` (or absent) writes p4code's own store.
8293
+ * The user-scope file is the primary home — it is what every Claude Code
8294
+ * session reads, in and out of p4code — so the panel defaults to it.
8295
+ */
8296
+ const McpServerSaveInput = Schema$1.Struct({
8297
+ registration: McpServerRegistration,
8298
+ source: Schema$1.optional(McpServerSource),
8299
+ /** Required when `source` is `project`: the workspace root to write into. */
8300
+ projectDir: Schema$1.optional(Schema$1.String)
8301
+ });
8302
+ const McpServerNameInput = Schema$1.Struct({
8303
+ name: McpServerName,
8304
+ source: Schema$1.optional(McpServerSource),
8305
+ projectDir: Schema$1.optional(Schema$1.String)
8227
8306
  });
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
8307
  /**
8232
8308
  * Setting one secret value, on this machine only.
8233
8309
  *
@@ -9405,7 +9481,7 @@ function deriveAuthClientMetadata(input) {
9405
9481
  //#endregion
9406
9482
  //#region src/auth/EnvironmentAuthPolicy.ts
9407
9483
  var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
9408
- const make$72 = Effect.gen(function* () {
9484
+ const make$73 = Effect.gen(function* () {
9409
9485
  const config = yield* ServerConfig$1;
9410
9486
  const isRemoteReachable = isRemoteReachableHost(config.host);
9411
9487
  const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
@@ -9423,7 +9499,7 @@ const make$72 = Effect.gen(function* () {
9423
9499
  };
9424
9500
  return EnvironmentAuthPolicy.of({ getDescriptor: () => Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")) });
9425
9501
  });
9426
- const layer$68 = Layer.effect(EnvironmentAuthPolicy, make$72);
9502
+ const layer$69 = Layer.effect(EnvironmentAuthPolicy, make$73);
9427
9503
  //#endregion
9428
9504
  //#region src/persistence/Errors.ts
9429
9505
  function summarizeSchemaIssue(issue) {
@@ -9604,7 +9680,7 @@ function toPersistenceSqlOrDecodeError$6(sqlOperation, decodeOperation, correlat
9604
9680
  cause
9605
9681
  });
9606
9682
  }
9607
- const make$71 = Effect.gen(function* () {
9683
+ const make$72 = Effect.gen(function* () {
9608
9684
  const sql = yield* SqlClient.SqlClient;
9609
9685
  const createSessionRow = SqlSchema.void({
9610
9686
  Request: CreateAuthSessionInput,
@@ -9738,7 +9814,7 @@ const make$71 = Effect.gen(function* () {
9738
9814
  setLastConnectedAt
9739
9815
  };
9740
9816
  });
9741
- const layer$67 = Layer.effect(AuthSessionRepository, make$71);
9817
+ const layer$68 = Layer.effect(AuthSessionRepository, make$72);
9742
9818
  //#endregion
9743
9819
  //#region src/auth/ServerSecretStore.ts
9744
9820
  const secretStoreErrorContext = {
@@ -9805,7 +9881,7 @@ const isSecretStoreError = Schema$1.is(SecretStoreError);
9805
9881
  const isPlatformError = (value) => Predicate.isTagged(value, "PlatformError");
9806
9882
  const isSecretAlreadyExistsError = (error) => "cause" in error && isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists";
9807
9883
  var ServerSecretStore = class extends Context.Service()("@p4code/cli/auth/ServerSecretStore") {};
9808
- const make$70 = Effect.gen(function* () {
9884
+ const make$71 = Effect.gen(function* () {
9809
9885
  const crypto = yield* Crypto.Crypto;
9810
9886
  const fileSystem = yield* FileSystem.FileSystem;
9811
9887
  const path = yield* Path.Path;
@@ -9875,7 +9951,7 @@ const make$70 = Effect.gen(function* () {
9875
9951
  remove
9876
9952
  });
9877
9953
  });
9878
- const layer$66 = Layer.effect(ServerSecretStore, make$70);
9954
+ const layer$67 = Layer.effect(ServerSecretStore, make$71);
9879
9955
  //#endregion
9880
9956
  //#region src/auth/SessionStore.ts
9881
9957
  var MalformedSessionTokenError = class extends Schema$1.TaggedErrorClass()("MalformedSessionTokenError", {}) {
@@ -10113,7 +10189,7 @@ function toAuthClientSession(input) {
10113
10189
  current: false
10114
10190
  };
10115
10191
  }
10116
- const make$69 = Effect.gen(function* () {
10192
+ const make$70 = Effect.gen(function* () {
10117
10193
  const crypto = yield* Crypto.Crypto;
10118
10194
  const serverConfig = yield* ServerConfig$1;
10119
10195
  const secretStore = yield* ServerSecretStore;
@@ -10427,7 +10503,7 @@ const make$69 = Effect.gen(function* () {
10427
10503
  markDisconnected
10428
10504
  });
10429
10505
  });
10430
- const layer$65 = Layer.effect(SessionStore, make$69).pipe(Layer.provideMerge(layer$67));
10506
+ const layer$66 = Layer.effect(SessionStore, make$70).pipe(Layer.provideMerge(layer$68));
10431
10507
  //#endregion
10432
10508
  //#region src/persistence/AuthPairingLinks.ts
10433
10509
  const AuthPairingLinkRecord = Schema$1.Struct({
@@ -10488,7 +10564,7 @@ function toPersistenceSqlOrDecodeError$5(sqlOperation, decodeOperation, correlat
10488
10564
  cause
10489
10565
  });
10490
10566
  }
10491
- const make$68 = Effect.gen(function* () {
10567
+ const make$69 = Effect.gen(function* () {
10492
10568
  const sql = yield* SqlClient.SqlClient;
10493
10569
  const createPairingLinkRow = SqlSchema.void({
10494
10570
  Request: CreateAuthPairingLinkInput,
@@ -10623,7 +10699,7 @@ const make$68 = Effect.gen(function* () {
10623
10699
  getByCredential
10624
10700
  };
10625
10701
  });
10626
- const layer$64 = Layer.effect(AuthPairingLinkRepository, make$68);
10702
+ const layer$65 = Layer.effect(AuthPairingLinkRepository, make$69);
10627
10703
  //#endregion
10628
10704
  //#region src/auth/PairingGrantStore.ts
10629
10705
  var UnknownBootstrapCredentialError = class extends Schema$1.TaggedErrorClass()("UnknownBootstrapCredentialError", {}) {
@@ -10718,7 +10794,7 @@ const DEV_STARTUP_TTL_HOURS = Duration.hours(24);
10718
10794
  const PAIRING_TOKEN_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
10719
10795
  const PAIRING_TOKEN_LENGTH = 12;
10720
10796
  const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
10721
- const make$67 = Effect.gen(function* () {
10797
+ const make$68 = Effect.gen(function* () {
10722
10798
  const crypto = yield* Crypto.Crypto;
10723
10799
  const config = yield* ServerConfig$1;
10724
10800
  const pairingLinks = yield* AuthPairingLinkRepository;
@@ -10916,7 +10992,7 @@ const make$67 = Effect.gen(function* () {
10916
10992
  consume
10917
10993
  });
10918
10994
  });
10919
- const layer$63 = Layer.effect(PairingGrantStore, make$67).pipe(Layer.provideMerge(layer$64));
10995
+ const layer$64 = Layer.effect(PairingGrantStore, make$68).pipe(Layer.provideMerge(layer$65));
10920
10996
  //#endregion
10921
10997
  //#region src/persistence/Migrations/001_OrchestrationEvents.ts
10922
10998
  var _001_OrchestrationEvents_default = Effect.gen(function* () {
@@ -12771,7 +12847,7 @@ function parseBearerToken(request) {
12771
12847
  const token = header.slice(7).trim();
12772
12848
  return token.length > 0 ? token : null;
12773
12849
  }
12774
- const make$66 = Effect.gen(function* () {
12850
+ const make$67 = Effect.gen(function* () {
12775
12851
  const policy = yield* EnvironmentAuthPolicy;
12776
12852
  const bootstrapCredentials = yield* PairingGrantStore;
12777
12853
  const sessions = yield* SessionStore;
@@ -12966,9 +13042,9 @@ const make$66 = Effect.gen(function* () {
12966
13042
  issueStartupPairingUrl
12967
13043
  });
12968
13044
  });
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));
13045
+ const layer$63 = Layer.effect(EnvironmentAuth, make$67).pipe(Layer.provideMerge(layer$64), Layer.provideMerge(layer$66), Layer.provideMerge(layer$69));
13046
+ const storageLayer = Layer.mergeAll(layer$67, layerConfig);
13047
+ const runtimeLayer = layer$63.pipe(Layer.provideMerge(storageLayer));
12972
13048
  //#endregion
12973
13049
  //#region src/cliAuthFormat.ts
12974
13050
  const newline = "\n";
@@ -13723,7 +13799,7 @@ const runWithEnvironmentAuth = (flags, run, options) => Effect.gen(function* ()
13723
13799
  }
13724
13800
  return yield* Effect.gen(function* () {
13725
13801
  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)))));
13802
+ }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$70(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
13727
13803
  });
13728
13804
  const ttlFlag = Flag.string("ttl").pipe(Flag.withSchema(DurationFromString), Flag.withDescription("TTL, for example `5m`, `1h`, `30d`, or `15 minutes`."), Flag.optional);
13729
13805
  const jsonFlag = Flag.boolean("json").pipe(Flag.withDescription("Emit JSON instead of human-readable output."), Flag.withDefault(false));
@@ -13863,7 +13939,7 @@ const DEFAULT_LIMITS = {
13863
13939
  windowMillis: FAILURE_WINDOW_MS,
13864
13940
  blockMillis: BLOCK_DURATION_MS
13865
13941
  };
13866
- const make$65 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
13942
+ const make$66 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
13867
13943
  const state = yield* Ref.make(initialThrottleState);
13868
13944
  return HubAuthThrottle.of({
13869
13945
  shouldRefuse: Effect.gen(function* () {
@@ -13877,7 +13953,7 @@ const make$65 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LI
13877
13953
  })
13878
13954
  });
13879
13955
  });
13880
- const layer$61 = Layer.effect(HubAuthThrottle, make$65());
13956
+ const layer$62 = Layer.effect(HubAuthThrottle, make$66());
13881
13957
  //#endregion
13882
13958
  //#region src/hub/HubAuth.ts
13883
13959
  /**
@@ -14676,7 +14752,7 @@ const deleteAssetRoute = HttpRouter.add("DELETE", "/assets/:kind/:name", respond
14676
14752
  const outcome = yield* (yield* AgentAssetRepository).deleteByName(requested);
14677
14753
  return outcome._tag === "conflict" ? assetConflict(Option.getOrNull(outcome.current)) : HttpServerResponse.empty({ status: 204 });
14678
14754
  })));
14679
- const layer$60 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
14755
+ const layer$61 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
14680
14756
  //#endregion
14681
14757
  //#region src/hub/Migrations/001_Tasks.ts
14682
14758
  /**
@@ -14955,7 +15031,7 @@ const announce = Layer.effectDiscard(Effect.gen(function* () {
14955
15031
  });
14956
15032
  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
15033
  }));
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));
15034
+ 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
15035
  const runHub = Layer.launch(makeHubLayer);
14960
15036
  //#endregion
14961
15037
  //#region src/atomicWrite.ts
@@ -15079,7 +15155,7 @@ function stripDefaultServerSettings(current, defaults) {
15079
15155
  }
15080
15156
  return Object.is(current, defaults) ? void 0 : current;
15081
15157
  }
15082
- const make$64 = Effect.gen(function* () {
15158
+ const make$65 = Effect.gen(function* () {
15083
15159
  const { settingsPath } = yield* ServerConfig$1;
15084
15160
  const fs = yield* FileSystem.FileSystem;
15085
15161
  const pathService = yield* Path.Path;
@@ -15300,7 +15376,7 @@ const make$64 = Effect.gen(function* () {
15300
15376
  }
15301
15377
  };
15302
15378
  });
15303
- const layer$59 = Layer.effect(ServerSettingsService, make$64);
15379
+ const layer$60 = Layer.effect(ServerSettingsService, make$65);
15304
15380
  //#endregion
15305
15381
  //#region src/pathExpansion.ts
15306
15382
  /**
@@ -15510,6 +15586,192 @@ const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config
15510
15586
  return [...skillsByName.values()].sort((left, right) => left.name.localeCompare(right.name));
15511
15587
  });
15512
15588
  //#endregion
15589
+ //#region src/mcp/ClaudeMcpFiles.ts
15590
+ /**
15591
+ * The MCP servers in Claude Code's own configuration files.
15592
+ *
15593
+ * Two homes, both the CLI's and both primary over p4code's registry:
15594
+ *
15595
+ * - **User scope**: the `mcpServers` key of `~/.claude.json`. Every Claude
15596
+ * Code session reads it, inside p4code and out.
15597
+ * - **Project scope**: `<project>/.mcp.json`, committed with the repository
15598
+ * and read by every session working in it.
15599
+ *
15600
+ * The settings panel manages both directly — list, add, edit, remove — so
15601
+ * this service writes them. **A user-scope write touches only the
15602
+ * `mcpServers` key**; `~/.claude.json` also holds `oauthAccount`, `machineID`
15603
+ * and a `projects` map, and everything outside the one key is carried
15604
+ * through a write as parsed. This is the same read-modify-write the
15605
+ * `claude mcp add` command performs, with the same last-writer-wins caveat
15606
+ * when a CLI session saves concurrently.
15607
+ *
15608
+ * A malformed entry, a name that would not survive as a registry filename, or
15609
+ * a missing file all cost only what they describe: that entry, or that one
15610
+ * file's list, never the panel.
15611
+ *
15612
+ * @module mcp/ClaudeMcpFiles
15613
+ */
15614
+ const isServerName = Schema$1.is(McpServerName);
15615
+ /** The file a project's scope lives in, beside its lockfiles and dotfiles. */
15616
+ const PROJECT_MCP_FILENAME = ".mcp.json";
15617
+ /**
15618
+ * One entry as the CLI writes it. `type` is absent for the CLI's original
15619
+ * stdio-only shape, so it defaults rather than discriminates.
15620
+ */
15621
+ const ClaudeMcpEntry = Schema$1.Struct({
15622
+ type: Schema$1.optional(Schema$1.Literals([
15623
+ "stdio",
15624
+ "http",
15625
+ "sse"
15626
+ ])),
15627
+ command: Schema$1.optional(Schema$1.String),
15628
+ args: Schema$1.optional(Schema$1.Array(Schema$1.String)),
15629
+ env: Schema$1.optional(Schema$1.Record(Schema$1.String, Schema$1.String)),
15630
+ url: Schema$1.optional(Schema$1.String),
15631
+ headers: Schema$1.optional(Schema$1.Record(Schema$1.String, Schema$1.String))
15632
+ });
15633
+ /**
15634
+ * A config file as this service needs to see it: the one key it owns, with
15635
+ * every other key carried as parsed. Both `~/.claude.json` and `.mcp.json`
15636
+ * decode through this — the former has many other keys, the latter none.
15637
+ */
15638
+ 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)]);
15639
+ const McpConfigFileFromJson = Schema$1.fromJsonString(McpConfigFile);
15640
+ const decodeConfigFile = Schema$1.decodeUnknownExit(McpConfigFileFromJson);
15641
+ const encodeConfigFile = Schema$1.encodeSync(McpConfigFileFromJson);
15642
+ const decodeEntry = Schema$1.decodeUnknownExit(ClaudeMcpEntry);
15643
+ /** Where the CLI keeps user scope: `$CLAUDE_CONFIG_DIR/.claude.json` when set, else `~/.claude.json`. */
15644
+ const claudeUserConfigPath = Effect.fn("claudeUserConfigPath")(function* () {
15645
+ const path = yield* Path.Path;
15646
+ const configDir = process.env["CLAUDE_CONFIG_DIR"]?.trim() ?? "";
15647
+ return configDir.length > 0 ? path.join(path.resolve(configDir), ".claude.json") : path.join(NodeOS.homedir(), ".claude.json");
15648
+ });
15649
+ /**
15650
+ * Map one CLI entry to a registration, or nothing when it cannot be one.
15651
+ *
15652
+ * `enabled: true` because presence in the CLI's file is what enabled means
15653
+ * there. Exported for tests.
15654
+ */
15655
+ function registrationFromClaudeEntry(name, entry) {
15656
+ if (!isServerName(name)) return void 0;
15657
+ const decoded = decodeEntry(entry);
15658
+ if (decoded._tag !== "Success") return void 0;
15659
+ const value = decoded.value;
15660
+ const type = value.type ?? "stdio";
15661
+ if (type === "stdio") {
15662
+ if (value.command === void 0 || value.command.trim().length === 0) return void 0;
15663
+ return {
15664
+ name,
15665
+ transport: "stdio",
15666
+ enabled: true,
15667
+ command: value.command,
15668
+ ...value.args !== void 0 && value.args.length > 0 ? { args: value.args } : {},
15669
+ ...value.env !== void 0 && Object.keys(value.env).length > 0 ? { env: value.env } : {}
15670
+ };
15671
+ }
15672
+ if (value.url === void 0 || value.url.trim().length === 0) return void 0;
15673
+ return {
15674
+ name,
15675
+ transport: type,
15676
+ enabled: true,
15677
+ url: value.url,
15678
+ ...value.headers !== void 0 && Object.keys(value.headers).length > 0 ? { headers: value.headers } : {}
15679
+ };
15680
+ }
15681
+ /**
15682
+ * The inverse mapping, for writes. `enabled` is dropped: the CLI has no such
15683
+ * flag, and presence in the file is what enabled means there. Exported for
15684
+ * tests, so the two mappings can be checked as a round trip.
15685
+ */
15686
+ function claudeEntryFromRegistration(registration) {
15687
+ if (registration.transport === "stdio") return {
15688
+ type: "stdio",
15689
+ command: registration.command,
15690
+ ...registration.args !== void 0 && registration.args.length > 0 ? { args: registration.args } : {},
15691
+ ...registration.env !== void 0 && Object.keys(registration.env).length > 0 ? { env: registration.env } : {}
15692
+ };
15693
+ return {
15694
+ type: registration.transport,
15695
+ url: registration.url,
15696
+ ...registration.headers !== void 0 && Object.keys(registration.headers).length > 0 ? { headers: registration.headers } : {}
15697
+ };
15698
+ }
15699
+ var ClaudeMcpFiles = class extends Context.Service()("@p4code/cli/mcp/ClaudeMcpFiles") {};
15700
+ const make$64 = Effect.gen(function* () {
15701
+ const fileSystem = yield* FileSystem.FileSystem;
15702
+ const path = yield* Path.Path;
15703
+ const services = yield* Effect.context();
15704
+ const readEntries = Effect.fn("ClaudeMcpFiles.readEntries")(function* (filePath) {
15705
+ const raw = yield* fileSystem.readFileString(filePath).pipe(Effect.orElseSucceed(() => void 0));
15706
+ if (raw === void 0) return [];
15707
+ const decoded = decodeConfigFile(raw);
15708
+ if (decoded._tag !== "Success") return [];
15709
+ const found = [];
15710
+ for (const [name, entry] of Object.entries(decoded.value.mcpServers ?? {})) {
15711
+ const registration = registrationFromClaudeEntry(name, entry);
15712
+ if (registration !== void 0) found.push(registration);
15713
+ }
15714
+ return found;
15715
+ });
15716
+ 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([]))));
15717
+ /**
15718
+ * Read, change the one key, write back atomically.
15719
+ *
15720
+ * A file that exists but will not parse fails the write loudly instead of
15721
+ * being replaced with `{ mcpServers }`: whatever is in it — including a
15722
+ * `~/.claude.json` full of the CLI's own state — is worth more than the
15723
+ * edit. A missing file starts from empty, which is how `.mcp.json` is born.
15724
+ */
15725
+ const changeFile = Effect.fn("ClaudeMcpFiles.changeFile")(function* (filePath, change) {
15726
+ const raw = yield* fileSystem.readFileString(filePath).pipe(Effect.orElseSucceed(() => void 0), Effect.provide(services));
15727
+ const decoded = raw === void 0 ? void 0 : decodeConfigFile(raw);
15728
+ if (decoded !== void 0 && decoded._tag !== "Success") return yield* new McpRegistryError({ detail: `${filePath} exists but could not be parsed, so it was left alone.` });
15729
+ const root = decoded === void 0 ? {} : decoded.value;
15730
+ const nextServers = change({ ...root.mcpServers });
15731
+ yield* fileSystem.makeDirectory(path.dirname(filePath), { recursive: true }).pipe(Effect.ignore, Effect.provide(services));
15732
+ yield* writeFileStringAtomically({
15733
+ filePath,
15734
+ contents: `${encodeConfigFile({
15735
+ ...root,
15736
+ mcpServers: nextServers
15737
+ })}\n`
15738
+ }).pipe(Effect.provide(services), Effect.mapError(() => new McpRegistryError({ detail: `Could not write ${filePath}.` })));
15739
+ });
15740
+ const projectFile = (projectDir) => path.join(path.resolve(projectDir), PROJECT_MCP_FILENAME);
15741
+ const upsertAt = (filePath) => Effect.fn("ClaudeMcpFiles.upsertAt")(function* (registration) {
15742
+ const resolved = yield* filePath.pipe(Effect.provide(services));
15743
+ yield* changeFile(resolved, (entries) => ({
15744
+ ...entries,
15745
+ [registration.name]: claudeEntryFromRegistration(registration)
15746
+ }));
15747
+ });
15748
+ const removeAt = (filePath) => Effect.fn("ClaudeMcpFiles.removeAt")(function* (name) {
15749
+ const resolved = yield* filePath.pipe(Effect.provide(services));
15750
+ yield* changeFile(resolved, (entries) => {
15751
+ const { [name]: _removed, ...rest } = entries;
15752
+ return rest;
15753
+ });
15754
+ });
15755
+ const userPath = claudeUserConfigPath();
15756
+ return {
15757
+ readUser: readAt(userPath),
15758
+ upsertUser: (registration) => upsertAt(userPath)(registration),
15759
+ removeUser: (name) => removeAt(userPath)(name),
15760
+ readProject: (projectDir) => readAt(Effect.succeed(projectFile(projectDir))),
15761
+ upsertProject: (projectDir, registration) => upsertAt(Effect.succeed(projectFile(projectDir)))(registration),
15762
+ removeProject: (projectDir, name) => removeAt(Effect.succeed(projectFile(projectDir)))(name)
15763
+ };
15764
+ });
15765
+ const layer$59 = Layer.effect(ClaudeMcpFiles, make$64);
15766
+ Layer.succeed(ClaudeMcpFiles, {
15767
+ readUser: Effect.succeed([]),
15768
+ upsertUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
15769
+ removeUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
15770
+ readProject: () => Effect.succeed([]),
15771
+ upsertProject: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
15772
+ removeProject: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." }))
15773
+ });
15774
+ //#endregion
15513
15775
  //#region src/mcp/McpOAuth.ts
15514
15776
  /**
15515
15777
  * OAuth sign-in for remote MCP servers, per the MCP authorization spec.
@@ -15978,6 +16240,7 @@ const make$62 = Effect.gen(function* () {
15978
16240
  const config = yield* ServerConfig$1;
15979
16241
  const secrets = yield* ServerSecretStore;
15980
16242
  const oauth = yield* McpOAuth;
16243
+ const claudeFiles = yield* ClaudeMcpFiles;
15981
16244
  const fileSystem = yield* FileSystem.FileSystem;
15982
16245
  const path = yield* Path.Path;
15983
16246
  const services = yield* Effect.context();
@@ -16026,7 +16289,21 @@ const make$62 = Effect.gen(function* () {
16026
16289
  registration,
16027
16290
  missingSecrets,
16028
16291
  ready: registration.enabled && missingSecrets.length === 0 && !needsSignIn,
16029
- ...Option.isSome(oauthStatus) ? { oauth: oauthStatus.value } : {}
16292
+ ...Option.isSome(oauthStatus) ? { oauth: oauthStatus.value } : {},
16293
+ source: "registry"
16294
+ });
16295
+ }
16296
+ const registryNames = new Set(statuses.map((status) => status.registration.name));
16297
+ for (const userScope of yield* claudeFiles.readUser) {
16298
+ if (registryNames.has(userScope.name)) continue;
16299
+ const oauthStatus = userScope.transport === "stdio" ? Option.none() : yield* oauth.statusFor(userScope);
16300
+ const needsSignIn = Option.isSome(oauthStatus) && !oauthStatus.value.connected;
16301
+ statuses.push({
16302
+ registration: userScope,
16303
+ missingSecrets: [],
16304
+ ready: !needsSignIn,
16305
+ ...Option.isSome(oauthStatus) ? { oauth: oauthStatus.value } : {},
16306
+ source: "claude"
16030
16307
  });
16031
16308
  }
16032
16309
  return statuses;
@@ -16092,6 +16369,20 @@ const make$62 = Effect.gen(function* () {
16092
16369
  headers
16093
16370
  };
16094
16371
  }
16372
+ for (const userScope of yield* claudeFiles.readUser) {
16373
+ if (userScope.transport === "stdio") continue;
16374
+ if (userScope.name in resolved) continue;
16375
+ const token = yield* oauth.accessTokenFor(userScope);
16376
+ if (Option.isNone(token)) continue;
16377
+ resolved[userScope.name] = {
16378
+ type: userScope.transport,
16379
+ url: userScope.url,
16380
+ headers: {
16381
+ ...userScope.headers,
16382
+ Authorization: `Bearer ${token.value}`
16383
+ }
16384
+ };
16385
+ }
16095
16386
  return resolved;
16096
16387
  }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry resolve failed", { cause }).pipe(Effect.as({}))))
16097
16388
  };
@@ -17813,7 +18104,7 @@ const make$59 = Effect.gen(function* () {
17813
18104
  const layer$54 = Layer.effect(AssetSync, make$59);
17814
18105
  //#endregion
17815
18106
  //#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));
18107
+ 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
18108
  const runWithSync = (flags, run) => Effect.gen(function* () {
17818
18109
  const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
17819
18110
  return yield* Effect.gen(function* () {
@@ -17821,7 +18112,7 @@ const runWithSync = (flags, run) => Effect.gen(function* () {
17821
18112
  sync: yield* AssetSync,
17822
18113
  link: yield* HubLink
17823
18114
  });
17824
- }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
18115
+ }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$70(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
17825
18116
  });
17826
18117
  const STATE_LABEL = {
17827
18118
  synced: "synced",
@@ -28407,7 +28698,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
28407
28698
  });
28408
28699
  yield* Console.log(output);
28409
28700
  }));
28410
- const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$69(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
28701
+ const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$70(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
28411
28702
  return yield* Effect.gen(function* () {
28412
28703
  const snapshot = yield* getOfflineSnapshot();
28413
28704
  const orchestrationEngine = yield* OrchestrationEngineService;
@@ -28418,7 +28709,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
28418
28709
  });
28419
28710
  yield* Console.log(output);
28420
28711
  }).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)))));
28712
+ }).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
28713
  });
28423
28714
  const projectAddCommand = Command.make("add", {
28424
28715
  ...projectLocationFlags,
@@ -44046,6 +44337,22 @@ function toAuthAccessStreamEvent(change, revision, currentSessionId) {
44046
44337
  };
44047
44338
  }
44048
44339
  }
44340
+ /**
44341
+ * Route one MCP write to the store its `source` names.
44342
+ *
44343
+ * `claude` and `project` write the CLI's own files; `registry` (or absent,
44344
+ * which every older client sends) writes p4code's store. A project write
44345
+ * without a directory is a caller bug worth a loud answer, not a fallback.
44346
+ */
44347
+ const routeMcpWrite = (input, handlers) => {
44348
+ if (input.source === "claude") return handlers.claude();
44349
+ if (input.source === "project") {
44350
+ const dir = input.projectDir?.trim() ?? "";
44351
+ if (dir.length === 0) return Effect.fail(new McpRegistryError({ detail: "A project-scope write needs its project directory." }));
44352
+ return handlers.project(dir);
44353
+ }
44354
+ return handlers.registry();
44355
+ };
44049
44356
  const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.toLayer(Effect.gen(function* () {
44050
44357
  const currentSessionId = currentSession.sessionId;
44051
44358
  const crypto = yield* Crypto.Crypto;
@@ -44074,7 +44381,26 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
44074
44381
  const assetSync = yield* AssetSync;
44075
44382
  const mcpRegistry = yield* McpRegistry;
44076
44383
  const mcpOAuth = yield* McpOAuth;
44384
+ const claudeMcpFiles = yield* ClaudeMcpFiles;
44077
44385
  const skillRegistry = yield* SkillRegistry;
44386
+ const listMcpServersEverywhere = Effect.gen(function* () {
44387
+ const servers = [...yield* mcpRegistry.list];
44388
+ const projectRows = yield* projectionProjects.listAll().pipe(Effect.map((rows) => rows.filter((row) => row.deletedAt === null)), Effect.orElseSucceed(() => []));
44389
+ for (const project of projectRows) for (const registration of yield* claudeMcpFiles.readProject(project.workspaceRoot)) servers.push({
44390
+ registration,
44391
+ missingSecrets: [],
44392
+ ready: true,
44393
+ source: "project",
44394
+ projectDir: project.workspaceRoot
44395
+ });
44396
+ return {
44397
+ servers,
44398
+ projects: projectRows.map((project) => ({
44399
+ dir: project.workspaceRoot,
44400
+ title: project.title
44401
+ }))
44402
+ };
44403
+ });
44078
44404
  const startup = yield* ServerRuntimeStartup;
44079
44405
  const workspaceEntries = yield* WorkspaceEntries;
44080
44406
  const workspaceFileSystem = yield* WorkspaceFileSystem;
@@ -44667,21 +44993,35 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
44667
44993
  }), { "rpc.aggregate": "skills" }),
44668
44994
  [WS_METHODS.skillRegistrySearch]: ({ query }) => observeRpcEffect$1(WS_METHODS.skillRegistrySearch, skillRegistry.search(query), { "rpc.aggregate": "skills" }),
44669
44995
  [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" }),
44996
+ [WS_METHODS.mcpList]: (_input) => observeRpcEffect$1(WS_METHODS.mcpList, listMcpServersEverywhere, { "rpc.aggregate": "mcp" }),
44997
+ [WS_METHODS.mcpSave]: ({ registration, source, projectDir }) => observeRpcEffect$1(WS_METHODS.mcpSave, routeMcpWrite({
44998
+ source,
44999
+ projectDir
45000
+ }, {
45001
+ claude: () => claudeMcpFiles.upsertUser(registration),
45002
+ project: (dir) => claudeMcpFiles.upsertProject(dir, registration),
45003
+ registry: () => mcpRegistry.save(registration)
45004
+ }).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
45005
+ [WS_METHODS.mcpRemove]: ({ name, source, projectDir }) => observeRpcEffect$1(WS_METHODS.mcpRemove, routeMcpWrite({
45006
+ source,
45007
+ projectDir
45008
+ }, {
45009
+ claude: () => claudeMcpFiles.removeUser(name),
45010
+ project: (dir) => claudeMcpFiles.removeProject(dir, name),
45011
+ registry: () => mcpRegistry.remove(name)
45012
+ }).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
44673
45013
  [WS_METHODS.mcpSetSecret]: ({ name, slot, value }) => observeRpcEffect$1(WS_METHODS.mcpSetSecret, mcpRegistry.setSecret({
44674
45014
  name,
44675
45015
  slot,
44676
45016
  value
44677
- }).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
45017
+ }).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
44678
45018
  [WS_METHODS.mcpOAuthBegin]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpOAuthBegin, Effect.gen(function* () {
44679
45019
  const found = (yield* mcpRegistry.list).find((status) => status.registration.name === name);
44680
45020
  if (found === void 0) return yield* new McpRegistryError({ detail: `No server is named ${name}.` });
44681
45021
  if (found.registration.transport === "stdio") return yield* new McpRegistryError({ detail: "A stdio server is launched locally and has no sign-in." });
44682
45022
  return yield* mcpOAuth.begin(found.registration);
44683
45023
  }), { "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" }),
45024
+ [WS_METHODS.mcpOAuthDisconnect]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpOAuthDisconnect, mcpOAuth.disconnect(name).pipe(Effect.andThen(listMcpServersEverywhere)), { "rpc.aggregate": "mcp" }),
44685
45025
  [WS_METHODS.serverGetSettings]: (_input) => observeRpcEffect$1(WS_METHODS.serverGetSettings, serverSettings.getSettings.pipe(Effect.map(redactServerSettingsForClient)), { "rpc.aggregate": "server" }),
44686
45026
  [WS_METHODS.serverUpdateSettings]: ({ patch }) => observeRpcEffect$1(WS_METHODS.serverUpdateSettings, serverSettings.updateSettings(patch).pipe(Effect.map(redactServerSettingsForClient)), { "rpc.aggregate": "server" }),
44687
45027
  [WS_METHODS.serverDiscoverSourceControl]: (_input) => observeRpcEffect$1(WS_METHODS.serverDiscoverSourceControl, sourceControlDiscovery.discover, { "rpc.aggregate": "server" }),
@@ -47179,7 +47519,7 @@ const makeOpenCodeRuntime = Effect.gen(function* () {
47179
47519
  };
47180
47520
  });
47181
47521
  var OpenCodeRuntime = class extends Context.Service()("@p4code/cli/provider/opencodeRuntime") {};
47182
- const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$70));
47522
+ const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$71));
47183
47523
  //#endregion
47184
47524
  //#region src/textGeneration/TextGenerationUtils.ts
47185
47525
  const isTextGenerationError$2 = Schema$1.is(TextGenerationError);
@@ -50582,7 +50922,9 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50582
50922
  payload: {
50583
50923
  taskId: RuntimeTaskId.make(message.task_id),
50584
50924
  description: message.description,
50585
- ...message.task_type ? { taskType: message.task_type } : {}
50925
+ ...message.task_type ? { taskType: message.task_type } : {},
50926
+ ...message.tool_use_id ? { toolUseId: message.tool_use_id } : {},
50927
+ ...message.subagent_type ? { subagentType: message.subagent_type } : {}
50586
50928
  }
50587
50929
  });
50588
50930
  return;
@@ -50599,7 +50941,9 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50599
50941
  description: message.description,
50600
50942
  ...message.summary ? { summary: message.summary } : {},
50601
50943
  ...message.usage ? { usage: message.usage } : {},
50602
- ...message.last_tool_name ? { lastToolName: message.last_tool_name } : {}
50944
+ ...message.last_tool_name ? { lastToolName: message.last_tool_name } : {},
50945
+ ...message.tool_use_id ? { toolUseId: message.tool_use_id } : {},
50946
+ ...message.subagent_type ? { subagentType: message.subagent_type } : {}
50603
50947
  }
50604
50948
  });
50605
50949
  return;
@@ -50616,7 +50960,8 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50616
50960
  taskId: RuntimeTaskId.make(message.task_id),
50617
50961
  status: message.status,
50618
50962
  ...message.summary ? { summary: message.summary } : {},
50619
- ...message.usage ? { usage: message.usage } : {}
50963
+ ...message.usage ? { usage: message.usage } : {},
50964
+ ...message.tool_use_id ? { toolUseId: message.tool_use_id } : {}
50620
50965
  }
50621
50966
  });
50622
50967
  return;
@@ -83838,7 +84183,9 @@ function runtimeEventToActivities(event, taskTitle) {
83838
84183
  payload: {
83839
84184
  taskId: event.payload.taskId,
83840
84185
  ...event.payload.taskType ? { taskType: event.payload.taskType } : {},
83841
- ...event.payload.description ? { detail: truncateDetail(event.payload.description) } : {}
84186
+ ...event.payload.description ? { detail: truncateDetail(event.payload.description) } : {},
84187
+ ...event.payload.toolUseId ? { toolUseId: event.payload.toolUseId } : {},
84188
+ ...event.payload.subagentType ? { subagentType: event.payload.subagentType } : {}
83842
84189
  },
83843
84190
  turnId: toTurnId$1(event.turnId) ?? null,
83844
84191
  ...maybeSequence
@@ -83855,7 +84202,9 @@ function runtimeEventToActivities(event, taskTitle) {
83855
84202
  detail: truncateDetail(event.payload.summary ?? event.payload.description),
83856
84203
  ...event.payload.summary ? { summary: truncateDetail(event.payload.summary) } : {},
83857
84204
  ...event.payload.lastToolName ? { lastToolName: event.payload.lastToolName } : {},
83858
- ...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {}
84205
+ ...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {},
84206
+ ...event.payload.toolUseId ? { toolUseId: event.payload.toolUseId } : {},
84207
+ ...event.payload.subagentType ? { subagentType: event.payload.subagentType } : {}
83859
84208
  },
83860
84209
  turnId: toTurnId$1(event.turnId) ?? null,
83861
84210
  ...maybeSequence
@@ -83874,7 +84223,8 @@ function runtimeEventToActivities(event, taskTitle) {
83874
84223
  summary: truncateDetail(event.payload.summary),
83875
84224
  detail: truncateDetail(event.payload.summary)
83876
84225
  } : {},
83877
- ...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {}
84226
+ ...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {},
84227
+ ...event.payload.toolUseId ? { toolUseId: event.payload.toolUseId } : {}
83878
84228
  },
83879
84229
  turnId: toTurnId$1(event.turnId) ?? null,
83880
84230
  ...maybeSequence
@@ -86464,9 +86814,9 @@ const WorkspaceEntriesLayerLive = layer$25.pipe(Layer.provide(layer$43));
86464
86814
  const WorkspaceFileSystemLayerLive = layer$24.pipe(Layer.provide(layer$43), Layer.provide(WorkspaceEntriesLayerLive));
86465
86815
  const WorkspaceLayerLive = Layer.mergeAll(layer$43, WorkspaceEntriesLayerLive, WorkspaceFileSystemLayerLive);
86466
86816
  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));
86817
+ const AuthLayerLive = layer$63.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$67));
86468
86818
  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));
86819
+ 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
86820
  /**
86471
86821
  * Hub asset sync.
86472
86822
  *
@@ -86886,7 +87236,7 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
86886
87236
  ]));
86887
87237
  //#endregion
86888
87238
  //#region src/bin.ts
86889
- const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$70, FetchHttpClient.layer);
87239
+ const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$71, FetchHttpClient.layer);
86890
87240
  /**
86891
87241
  * Prints an update reminder before dispatching, at most once a day.
86892
87242
  *