@p4code/cli 0.1.3 → 0.1.5

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 +1022 -147
  2. package/dist/client/assets/{DiffPanel-DyAcFDt3.js → DiffPanel-ML_kqHo4.js} +2 -2
  3. package/dist/client/assets/{FilePreviewPanel-BYBlt2Jx.js → FilePreviewPanel-DqEQ4wir.js} +2 -2
  4. package/dist/client/assets/{PreviewPanel-2wO230Hl.js → PreviewPanel-BwHQqsFC.js} +2 -2
  5. package/dist/client/assets/{angular-html-C9jMC3ZQ.js → angular-html-B70hXg9o.js} +2 -2
  6. package/dist/client/assets/{angular-ts-CYoSZaKw.js → angular-ts-B2MRnnc1.js} +2 -2
  7. package/dist/client/assets/{apl-CgWZs6Gn.js → apl-DY9W2lgD.js} +2 -2
  8. package/dist/client/assets/arrow-right-Bdq-W9Bm.js +2 -0
  9. package/dist/client/assets/{astro-CUIqu6Jz.js → astro-CKmYmuzu.js} +2 -2
  10. package/dist/client/assets/{blade-iplcV4Ix.js → blade-mlm-ZlOd.js} +2 -2
  11. package/dist/client/assets/{c-Dd6jN1w_.js → c-9y7zDOj9.js} +2 -2
  12. package/dist/client/assets/{cobol-0ScsIx-z.js → cobol-CD87wiGp.js} +2 -2
  13. package/dist/client/assets/{coffee-KS_79spe.js → coffee-kgGv4P2i.js} +2 -2
  14. package/dist/client/assets/{cpp-BllSLkvw.js → cpp-DpZlUxYu.js} +2 -2
  15. package/dist/client/assets/{crystal-DF2_oukQ.js → crystal-B0OLLlY8.js} +2 -2
  16. package/dist/client/assets/{css-DBr167Oo.js → css--MUQJ4o7.js} +2 -2
  17. package/dist/client/assets/{edge-CRJ0aLAq.js → edge-B9eY7KZn.js} +2 -2
  18. package/dist/client/assets/{elixir-DXl1oanW.js → elixir-BZ2mTmkv.js} +2 -2
  19. package/dist/client/assets/{elm-CqKx609q.js → elm-Bu95APK0.js} +2 -2
  20. package/dist/client/assets/{erb-MLJdAbE4.js → erb-CpKKo-fS.js} +2 -2
  21. package/dist/client/assets/{fileCommentAnnotations-BaJ5XhsU.js → fileCommentAnnotations-DeY-XSzV.js} +2 -2
  22. package/dist/client/assets/{git-rebase-M0aVykt3.js → git-rebase-BN70gFDl.js} +2 -2
  23. package/dist/client/assets/{glimmer-js-CXPK1DP8.js → glimmer-js-DM-4mIJW.js} +2 -2
  24. package/dist/client/assets/{glimmer-ts-wptUL2fp.js → glimmer-ts-DFHG1P9q.js} +2 -2
  25. package/dist/client/assets/{glsl-BRKhgqUF.js → glsl-B4TfqZ4_.js} +2 -2
  26. package/dist/client/assets/{graphql-1BUUHzT4.js → graphql-DLTs8DHV.js} +2 -2
  27. package/dist/client/assets/{hack-BR9NLXvX.js → hack-DRRemOcq.js} +2 -2
  28. package/dist/client/assets/{haml-BgBKuGz0.js → haml-4MHJURGQ.js} +2 -2
  29. package/dist/client/assets/{handlebars-BUs0Hgpn.js → handlebars-D7k0HQlo.js} +2 -2
  30. package/dist/client/assets/{html-BWwNwdti.js → html-DovLLqdO.js} +2 -2
  31. package/dist/client/assets/{html-derivative-B2dGSGlK.js → html-derivative-Dz9-s5om.js} +2 -2
  32. package/dist/client/assets/{http-NIyxdCuV.js → http-cxnvN4kV.js} +2 -2
  33. package/dist/client/assets/{hurl-CH8mm6dw.js → hurl-CSBBQOts.js} +2 -2
  34. package/dist/client/assets/{index-HEbzvM18.js → index-BXFHdiV7.js} +202 -202
  35. package/dist/client/assets/index-oFUAtVw2.css +1 -0
  36. package/dist/client/assets/{java-CQPmtuJ5.js → java-DIz7GrNg.js} +2 -2
  37. package/dist/client/assets/{javascript-DzjJJM-s.js → javascript-MSaRoKWU.js} +2 -2
  38. package/dist/client/assets/{jinja-4Qs6tVyC.js → jinja-DI8yd0V9.js} +2 -2
  39. package/dist/client/assets/{jison-CPG2kEI3.js → jison-sGqXSFug.js} +2 -2
  40. package/dist/client/assets/{json-DlY_RU7e.js → json-C_w_LNS4.js} +2 -2
  41. package/dist/client/assets/{jsx-Cd_ApdjY.js → jsx-V5NNKrjP.js} +2 -2
  42. package/dist/client/assets/{julia-SX8cqtZg.js → julia-BGVYDOsa.js} +2 -2
  43. package/dist/client/assets/{just-Ao5BO2B0.js → just-D-04ksOT.js} +2 -2
  44. package/dist/client/assets/{latex-C46nB2Dk.js → latex-BEsliWgq.js} +2 -2
  45. package/dist/client/assets/{liquid-BMcKK3Z1.js → liquid-DNUeMt2o.js} +2 -2
  46. package/dist/client/assets/{lua-DjG6qAWa.js → lua--TgilFGl.js} +2 -2
  47. package/dist/client/assets/{marko-3JoFYw3q.js → marko-DxDDGF4_.js} +2 -2
  48. package/dist/client/assets/{mdc-BpGP1uha.js → mdc-DzjvIH05.js} +2 -2
  49. package/dist/client/assets/{nginx-HOkzmdTd.js → nginx-BqVTMZgm.js} +2 -2
  50. package/dist/client/assets/{nim-CeKNmMcr.js → nim-Co2BGNef.js} +2 -2
  51. package/dist/client/assets/{perl-BWQkxnsH.js → perl-Ba8Q7XkF.js} +2 -2
  52. package/dist/client/assets/{php-Df4cK7Vr.js → php-Bfbmd1-m.js} +2 -2
  53. package/dist/client/assets/{pug-CoCjyAiE.js → pug-be-1Xvfl.js} +2 -2
  54. package/dist/client/assets/{qml-DYi25PQ3.js → qml-D7icULiU.js} +2 -2
  55. package/dist/client/assets/{r-BzJkuBsW.js → r-Cph7TJQ-.js} +2 -2
  56. package/dist/client/assets/{razor-BhG_PBuW.js → razor-CjLyUAnD.js} +2 -2
  57. package/dist/client/assets/{regexp-BAM54YZk.js → regexp-BdlWyepz.js} +2 -2
  58. package/dist/client/assets/{rst-DHl4hyZ2.js → rst-DEpJb2t7.js} +2 -2
  59. package/dist/client/assets/{ruby-gNx0WumM.js → ruby-C_x4mzoE.js} +2 -2
  60. package/dist/client/assets/{sas-CW83v0Dn.js → sas-Bz4iLdau.js} +2 -2
  61. package/dist/client/assets/{scss-WgrcQHVQ.js → scss-CwgGUhGr.js} +2 -2
  62. package/dist/client/assets/{shellscript-CKEnN-lX.js → shellscript-CHr9xiaE.js} +2 -2
  63. package/dist/client/assets/{shellsession-BbcmvnCz.js → shellsession-11TeKCPG.js} +2 -2
  64. package/dist/client/assets/{soy-D1MIxKdU.js → soy-BLILGuwU.js} +2 -2
  65. package/dist/client/assets/{sql-Bhxl_Mi7.js → sql-KbVEV8JC.js} +2 -2
  66. package/dist/client/assets/{stata-C-LT_UBU.js → stata-XDGn9IyV.js} +2 -2
  67. package/dist/client/assets/{surrealql-Ch_ceRvJ.js → surrealql-BkijSB1h.js} +2 -2
  68. package/dist/client/assets/{svelte-DlhsOd0r.js → svelte-S0qXpcmK.js} +2 -2
  69. package/dist/client/assets/{templ-CIHR3tEf.js → templ-Bpai32u4.js} +2 -2
  70. package/dist/client/assets/{tex-DRWioNbs.js → tex-BqM5PBWs.js} +2 -2
  71. package/dist/client/assets/textarea-CUI7U2B2.js +46 -0
  72. package/dist/client/assets/{ts-tags-BvRYwyAy.js → ts-tags-ChsaUtvn.js} +2 -2
  73. package/dist/client/assets/{tsx-BRkrE5rM.js → tsx-Bw54IsTH.js} +2 -2
  74. package/dist/client/assets/{twig-BlZvFnQN.js → twig-BOAKWhe6.js} +2 -2
  75. package/dist/client/assets/{typescript-Djd2wnjW.js → typescript-vJRDqHfC.js} +2 -2
  76. package/dist/client/assets/{vue-DActsgCM.js → vue-CtHSR0DM.js} +2 -2
  77. package/dist/client/assets/{vue-html-Cqt121Xa.js → vue-html-KPDmQoqc.js} +2 -2
  78. package/dist/client/assets/{vue-vine-CzSkk7Q4.js → vue-vine-BSN6OPd2.js} +2 -2
  79. package/dist/client/assets/{xml-DPi6y6-m.js → xml-8bohM9Or.js} +2 -2
  80. package/dist/client/assets/{xsl-BAvs_EI4.js → xsl-D-jqs0Dv.js} +2 -2
  81. package/dist/client/assets/{yaml-DFFGim1C.js → yaml-CzI494Jo.js} +2 -2
  82. package/dist/client/index.html +3 -3
  83. package/package.json +1 -1
  84. package/dist/client/assets/arrow-right-BpqEKABW.js +0 -2
  85. package/dist/client/assets/index-C7UXI10J.css +0 -1
  86. package/dist/client/assets/textarea-CHMvJ0-S.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$72 = () => {
124
+ const make$73 = () => {
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$72 = () => {
230
230
  })
231
231
  };
232
232
  };
233
- const layer$68 = Layer.sync(NetService, make$72);
233
+ const layer$69 = Layer.sync(NetService, make$73);
234
234
  //#endregion
235
235
  //#region package.json
236
- var version = "0.1.3";
236
+ var version = "0.1.5";
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$71 = (config) => ServerConfig$1.of(config);
258
- const layer$67 = (config) => Layer.succeed(ServerConfig$1, make$71(config));
257
+ const make$72 = (config) => ServerConfig$1.of(config);
258
+ const layer$68 = (config) => Layer.succeed(ServerConfig$1, make$72(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");
@@ -5720,6 +5720,7 @@ const SourceControlWritingStyleSettings = Schema$1.Struct({
5720
5720
  followChangeRequestTemplates: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true)))
5721
5721
  });
5722
5722
  const DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL = Duration.seconds(30);
5723
+ const TaskBoardSource = Schema$1.Literals(["local", "hub"]);
5723
5724
  const ServerSettings = Schema$1.Struct({
5724
5725
  enableAssistantStreaming: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(false))),
5725
5726
  enableProviderUpdateChecks: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true))),
@@ -5733,6 +5734,42 @@ const ServerSettings = Schema$1.Struct({
5733
5734
  }))),
5734
5735
  sourceControlWritingStyle: SourceControlWritingStyleSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
5735
5736
  sourceControlWriterModelSelection: Schema$1.NullOr(ModelSelection).pipe(Schema$1.withDecodingDefault(Effect.succeed(null))),
5737
+ /**
5738
+ * Where this server's task board lives.
5739
+ *
5740
+ * `local` is this machine's own SQLite database, which is where every board
5741
+ * has been until now. `hub` puts the board on the linked hub, so two servers
5742
+ * read and write one board instead of two that silently diverge.
5743
+ *
5744
+ * A setting rather than "hub if one is linked", because a hub can be linked
5745
+ * for skills alone, and flipping a board's home is not something to have
5746
+ * happen as a side effect of connecting. It is also the way back: the local
5747
+ * rows are still there, untouched, when it is set to `local` again.
5748
+ *
5749
+ * **On `hub`, an unreachable hub means no board.** There is no local
5750
+ * fallback by decision: answering from a stale local copy would recreate the
5751
+ * per-machine divergence the hub exists to remove, and it would do it
5752
+ * invisibly.
5753
+ */
5754
+ taskBoardSource: TaskBoardSource.pipe(Schema$1.withDecodingDefault(Effect.succeed("local"))),
5755
+ /**
5756
+ * Skills the agents on this server must not see, by name.
5757
+ *
5758
+ * Server-scoped rather than per provider instance, because a skill is a
5759
+ * property of the machine's filesystem and every instance on it reads the
5760
+ * same directories.
5761
+ *
5762
+ * Deliberately **not** synced through the hub. A shared skill that is muted
5763
+ * on one machine is the useful combination — the laptop does not want the
5764
+ * skill that shells out to the Studio's build tooling — and syncing the mute
5765
+ * would make that inexpressible.
5766
+ *
5767
+ * What "disabled" means is bounded by what the provider can enforce: the
5768
+ * skill is hidden from the model's listing and from `/name`, and its files
5769
+ * stay on disk and remain readable by Read and Bash. It is a context filter,
5770
+ * not a sandbox, and nothing here should be described to a user as one.
5771
+ */
5772
+ disabledSkills: Schema$1.Array(TrimmedNonEmptyString).pipe(Schema$1.withDecodingDefault(Effect.succeed([]))),
5736
5773
  providers: Schema$1.Struct({
5737
5774
  codex: CodexSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
5738
5775
  claudeAgent: ClaudeSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
@@ -5824,6 +5861,8 @@ const ServerSettingsPatch = Schema$1.Struct({
5824
5861
  followChangeRequestTemplates: Schema$1.optionalKey(Schema$1.Boolean)
5825
5862
  })),
5826
5863
  sourceControlWriterModelSelection: Schema$1.optionalKey(Schema$1.NullOr(ModelSelection)),
5864
+ disabledSkills: Schema$1.optionalKey(Schema$1.Array(TrimmedNonEmptyString)),
5865
+ taskBoardSource: Schema$1.optionalKey(TaskBoardSource),
5827
5866
  observability: Schema$1.optionalKey(Schema$1.Struct({
5828
5867
  otlpTracesUrl: Schema$1.optionalKey(TrimmedString),
5829
5868
  otlpMetricsUrl: Schema$1.optionalKey(TrimmedString)
@@ -7317,6 +7356,22 @@ const TaskStreamEvent = Schema$1.Union([
7317
7356
  taskId: TaskId
7318
7357
  })
7319
7358
  ]);
7359
+ Schema$1.Struct({
7360
+ patch: TaskUpdateInput,
7361
+ /** The status the caller believes the task is in. */
7362
+ expectedStatus: TaskStatus
7363
+ });
7364
+ Schema$1.Union([
7365
+ Schema$1.Struct({
7366
+ outcome: Schema$1.Literal("updated"),
7367
+ task: Task
7368
+ }),
7369
+ Schema$1.Struct({ outcome: Schema$1.Literal("missing") }),
7370
+ Schema$1.Struct({
7371
+ outcome: Schema$1.Literal("conflict"),
7372
+ current: Task
7373
+ })
7374
+ ]);
7320
7375
  /**
7321
7376
  * Start an agent on a task.
7322
7377
  *
@@ -7935,6 +7990,81 @@ var McpRegistryError = class extends Schema$1.TaggedErrorClass()("McpRegistryErr
7935
7990
  }
7936
7991
  };
7937
7992
  //#endregion
7993
+ //#region ../../packages/contracts/src/skillRegistry.ts
7994
+ /**
7995
+ * Finding skills that are not on this machine yet.
7996
+ *
7997
+ * Managing the skills you already have is CRUD, and that is `agentAsset.ts`.
7998
+ * This is the other half: a catalogue to search and a repository to read a
7999
+ * skill out of, with the install itself going through the ordinary local-create
8000
+ * path so there is exactly one way a skill lands on disk.
8001
+ *
8002
+ * **Nothing here installs anything.** Search returns names; fetch returns the
8003
+ * files it *would* write, with the source they came from. The confirmation step
8004
+ * is a person looking at that list, which is the only reason it is two calls
8005
+ * rather than one — a `SKILL.md` is instructions handed to an agent that
8006
+ * already has a shell, so what it contains is worth seeing before it arrives.
8007
+ *
8008
+ * @module skillRegistry
8009
+ */
8010
+ /**
8011
+ * One catalogue hit.
8012
+ *
8013
+ * `source` is the repository, and it is not decoration: it is what a person
8014
+ * judges the install on, so it travels with every result rather than being
8015
+ * fetched later.
8016
+ */
8017
+ const RegistrySkill = Schema$1.Struct({
8018
+ /** `owner/repo/skill-name`, the catalogue's own identifier. */
8019
+ id: TrimmedNonEmptyString,
8020
+ name: TrimmedNonEmptyString,
8021
+ /** `owner/repo`. */
8022
+ source: TrimmedNonEmptyString,
8023
+ /** How many installs the catalogue has counted. Popularity, not endorsement. */
8024
+ installs: Schema$1.Int
8025
+ });
8026
+ const RegistrySkillSearchInput = Schema$1.Struct({ query: TrimmedNonEmptyString });
8027
+ /**
8028
+ * `unavailable` rather than a failure, matching the hub calls: a catalogue on
8029
+ * someone else's infrastructure being down is an ordinary condition, and a
8030
+ * panel has to say which of "nothing matched" and "could not ask" happened.
8031
+ */
8032
+ const RegistrySkillSearchResult = Schema$1.Struct({
8033
+ results: Schema$1.Array(RegistrySkill),
8034
+ unavailable: Schema$1.NullOr(Schema$1.String)
8035
+ });
8036
+ const RegistrySkillFetchInput = Schema$1.Struct({
8037
+ /** `owner/repo/skill-name`, from a search result or typed by hand. */
8038
+ id: TrimmedNonEmptyString });
8039
+ /** Why a file in the skill's directory is not in the fetched set. */
8040
+ const RegistrySkillSkippedFile = Schema$1.Struct({
8041
+ path: Schema$1.String,
8042
+ reason: Schema$1.Literals([
8043
+ "too-large",
8044
+ "too-many-files",
8045
+ "over-total-size"
8046
+ ])
8047
+ });
8048
+ /**
8049
+ * What installing this skill would write, and where it came from.
8050
+ *
8051
+ * `skipped` is part of the answer rather than a log line. A bound that silently
8052
+ * drops a script leaves a skill that is present, looks installed, and fails at
8053
+ * the moment it is used.
8054
+ */
8055
+ const RegistrySkillFetchResult = Schema$1.Struct({
8056
+ found: Schema$1.Boolean,
8057
+ id: TrimmedNonEmptyString,
8058
+ /** The directory name the skill would take on disk. */
8059
+ name: Schema$1.String,
8060
+ source: Schema$1.String,
8061
+ /** Where these files can be read in full, before trusting them. */
8062
+ sourceUrl: Schema$1.String,
8063
+ files: Schema$1.Array(AgentAssetFile),
8064
+ skipped: Schema$1.Array(RegistrySkillSkippedFile),
8065
+ unavailable: Schema$1.NullOr(Schema$1.String)
8066
+ });
8067
+ //#endregion
7938
8068
  //#region ../../packages/contracts/src/filesystem.ts
7939
8069
  const FILESYSTEM_PATH_MAX_LENGTH = 512;
7940
8070
  const FilesystemBrowseInput = Schema$1.Struct({
@@ -8197,6 +8327,8 @@ const WS_METHODS = {
8197
8327
  assetsDelete: "assets.delete",
8198
8328
  assetsCreateLocal: "assets.createLocal",
8199
8329
  assetsRemoveLocal: "assets.removeLocal",
8330
+ skillRegistrySearch: "skillRegistry.search",
8331
+ skillRegistryFetch: "skillRegistry.fetch",
8200
8332
  mcpList: "mcp.list",
8201
8333
  mcpSave: "mcp.save",
8202
8334
  mcpRemove: "mcp.remove",
@@ -8420,6 +8552,24 @@ const WsAssetsRemoveLocalRpc = Rpc.make(WS_METHODS.assetsRemoveLocal, {
8420
8552
  error: Schema$1.Union([EnvironmentAuthorizationError])
8421
8553
  });
8422
8554
  /**
8555
+ * Finding and reading skills that are not on this machine yet.
8556
+ *
8557
+ * Read-only, both of them. Installing is `assets.createLocal` with the files
8558
+ * `skillRegistry.fetch` returned, so a skill arriving from a catalogue goes
8559
+ * through exactly the same refusals as one typed into the New skill dialog, and
8560
+ * the step in between is a person looking at what would be written.
8561
+ */
8562
+ const WsSkillRegistrySearchRpc = Rpc.make(WS_METHODS.skillRegistrySearch, {
8563
+ payload: RegistrySkillSearchInput,
8564
+ success: RegistrySkillSearchResult,
8565
+ error: Schema$1.Union([EnvironmentAuthorizationError])
8566
+ });
8567
+ const WsSkillRegistryFetchRpc = Rpc.make(WS_METHODS.skillRegistryFetch, {
8568
+ payload: RegistrySkillFetchInput,
8569
+ success: RegistrySkillFetchResult,
8570
+ error: Schema$1.Union([EnvironmentAuthorizationError])
8571
+ });
8572
+ /**
8423
8573
  * Registering the user's own MCP servers.
8424
8574
  *
8425
8575
  * Every one of these answers with the whole list, for the same reason the sync
@@ -8829,7 +8979,7 @@ const WsSubscribeAuthAccessRpc = Rpc.make(WS_METHODS.subscribeAuthAccess, {
8829
8979
  error: Schema$1.Union([AuthAccessStreamError, EnvironmentAuthorizationError]),
8830
8980
  stream: true
8831
8981
  });
8832
- const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetProviderUsageRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsAssetsCreateLocalRpc, WsAssetsRemoveLocalRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
8982
+ const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetProviderUsageRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsAssetsCreateLocalRpc, WsAssetsRemoveLocalRpc, WsSkillRegistrySearchRpc, WsSkillRegistryFetchRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
8833
8983
  //#endregion
8834
8984
  //#region ../../packages/shared/src/oauthScope.ts
8835
8985
  const OAUTH_SCOPE_TOKEN = /^[\u0021\u0023-\u005b\u005d-\u007e]+$/u;
@@ -8975,7 +9125,7 @@ function deriveAuthClientMetadata(input) {
8975
9125
  //#endregion
8976
9126
  //#region src/auth/EnvironmentAuthPolicy.ts
8977
9127
  var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
8978
- const make$70 = Effect.gen(function* () {
9128
+ const make$71 = Effect.gen(function* () {
8979
9129
  const config = yield* ServerConfig$1;
8980
9130
  const isRemoteReachable = isRemoteReachableHost(config.host);
8981
9131
  const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
@@ -8993,7 +9143,7 @@ const make$70 = Effect.gen(function* () {
8993
9143
  };
8994
9144
  return EnvironmentAuthPolicy.of({ getDescriptor: () => Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")) });
8995
9145
  });
8996
- const layer$66 = Layer.effect(EnvironmentAuthPolicy, make$70);
9146
+ const layer$67 = Layer.effect(EnvironmentAuthPolicy, make$71);
8997
9147
  //#endregion
8998
9148
  //#region src/persistence/Errors.ts
8999
9149
  function summarizeSchemaIssue(issue) {
@@ -9174,7 +9324,7 @@ function toPersistenceSqlOrDecodeError$6(sqlOperation, decodeOperation, correlat
9174
9324
  cause
9175
9325
  });
9176
9326
  }
9177
- const make$69 = Effect.gen(function* () {
9327
+ const make$70 = Effect.gen(function* () {
9178
9328
  const sql = yield* SqlClient.SqlClient;
9179
9329
  const createSessionRow = SqlSchema.void({
9180
9330
  Request: CreateAuthSessionInput,
@@ -9308,7 +9458,7 @@ const make$69 = Effect.gen(function* () {
9308
9458
  setLastConnectedAt
9309
9459
  };
9310
9460
  });
9311
- const layer$65 = Layer.effect(AuthSessionRepository, make$69);
9461
+ const layer$66 = Layer.effect(AuthSessionRepository, make$70);
9312
9462
  //#endregion
9313
9463
  //#region src/auth/ServerSecretStore.ts
9314
9464
  const secretStoreErrorContext = {
@@ -9375,7 +9525,7 @@ const isSecretStoreError = Schema$1.is(SecretStoreError);
9375
9525
  const isPlatformError = (value) => Predicate.isTagged(value, "PlatformError");
9376
9526
  const isSecretAlreadyExistsError = (error) => "cause" in error && isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists";
9377
9527
  var ServerSecretStore = class extends Context.Service()("@p4code/cli/auth/ServerSecretStore") {};
9378
- const make$68 = Effect.gen(function* () {
9528
+ const make$69 = Effect.gen(function* () {
9379
9529
  const crypto = yield* Crypto.Crypto;
9380
9530
  const fileSystem = yield* FileSystem.FileSystem;
9381
9531
  const path = yield* Path.Path;
@@ -9445,7 +9595,7 @@ const make$68 = Effect.gen(function* () {
9445
9595
  remove
9446
9596
  });
9447
9597
  });
9448
- const layer$64 = Layer.effect(ServerSecretStore, make$68);
9598
+ const layer$65 = Layer.effect(ServerSecretStore, make$69);
9449
9599
  //#endregion
9450
9600
  //#region src/auth/SessionStore.ts
9451
9601
  var MalformedSessionTokenError = class extends Schema$1.TaggedErrorClass()("MalformedSessionTokenError", {}) {
@@ -9683,7 +9833,7 @@ function toAuthClientSession(input) {
9683
9833
  current: false
9684
9834
  };
9685
9835
  }
9686
- const make$67 = Effect.gen(function* () {
9836
+ const make$68 = Effect.gen(function* () {
9687
9837
  const crypto = yield* Crypto.Crypto;
9688
9838
  const serverConfig = yield* ServerConfig$1;
9689
9839
  const secretStore = yield* ServerSecretStore;
@@ -9997,7 +10147,7 @@ const make$67 = Effect.gen(function* () {
9997
10147
  markDisconnected
9998
10148
  });
9999
10149
  });
10000
- const layer$63 = Layer.effect(SessionStore, make$67).pipe(Layer.provideMerge(layer$65));
10150
+ const layer$64 = Layer.effect(SessionStore, make$68).pipe(Layer.provideMerge(layer$66));
10001
10151
  //#endregion
10002
10152
  //#region src/persistence/AuthPairingLinks.ts
10003
10153
  const AuthPairingLinkRecord = Schema$1.Struct({
@@ -10058,7 +10208,7 @@ function toPersistenceSqlOrDecodeError$5(sqlOperation, decodeOperation, correlat
10058
10208
  cause
10059
10209
  });
10060
10210
  }
10061
- const make$66 = Effect.gen(function* () {
10211
+ const make$67 = Effect.gen(function* () {
10062
10212
  const sql = yield* SqlClient.SqlClient;
10063
10213
  const createPairingLinkRow = SqlSchema.void({
10064
10214
  Request: CreateAuthPairingLinkInput,
@@ -10193,7 +10343,7 @@ const make$66 = Effect.gen(function* () {
10193
10343
  getByCredential
10194
10344
  };
10195
10345
  });
10196
- const layer$62 = Layer.effect(AuthPairingLinkRepository, make$66);
10346
+ const layer$63 = Layer.effect(AuthPairingLinkRepository, make$67);
10197
10347
  //#endregion
10198
10348
  //#region src/auth/PairingGrantStore.ts
10199
10349
  var UnknownBootstrapCredentialError = class extends Schema$1.TaggedErrorClass()("UnknownBootstrapCredentialError", {}) {
@@ -10288,7 +10438,7 @@ const DEV_STARTUP_TTL_HOURS = Duration.hours(24);
10288
10438
  const PAIRING_TOKEN_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
10289
10439
  const PAIRING_TOKEN_LENGTH = 12;
10290
10440
  const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
10291
- const make$65 = Effect.gen(function* () {
10441
+ const make$66 = Effect.gen(function* () {
10292
10442
  const crypto = yield* Crypto.Crypto;
10293
10443
  const config = yield* ServerConfig$1;
10294
10444
  const pairingLinks = yield* AuthPairingLinkRepository;
@@ -10486,7 +10636,7 @@ const make$65 = Effect.gen(function* () {
10486
10636
  consume
10487
10637
  });
10488
10638
  });
10489
- const layer$61 = Layer.effect(PairingGrantStore, make$65).pipe(Layer.provideMerge(layer$62));
10639
+ const layer$62 = Layer.effect(PairingGrantStore, make$66).pipe(Layer.provideMerge(layer$63));
10490
10640
  //#endregion
10491
10641
  //#region src/persistence/Migrations/001_OrchestrationEvents.ts
10492
10642
  var _001_OrchestrationEvents_default = Effect.gen(function* () {
@@ -12259,7 +12409,7 @@ function parseBearerToken(request) {
12259
12409
  const token = header.slice(7).trim();
12260
12410
  return token.length > 0 ? token : null;
12261
12411
  }
12262
- const make$64 = Effect.gen(function* () {
12412
+ const make$65 = Effect.gen(function* () {
12263
12413
  const policy = yield* EnvironmentAuthPolicy;
12264
12414
  const bootstrapCredentials = yield* PairingGrantStore;
12265
12415
  const sessions = yield* SessionStore;
@@ -12454,9 +12604,9 @@ const make$64 = Effect.gen(function* () {
12454
12604
  issueStartupPairingUrl
12455
12605
  });
12456
12606
  });
12457
- const layer$60 = Layer.effect(EnvironmentAuth, make$64).pipe(Layer.provideMerge(layer$61), Layer.provideMerge(layer$63), Layer.provideMerge(layer$66));
12458
- const storageLayer = Layer.mergeAll(layer$64, layerConfig);
12459
- const runtimeLayer = layer$60.pipe(Layer.provideMerge(storageLayer));
12607
+ const layer$61 = Layer.effect(EnvironmentAuth, make$65).pipe(Layer.provideMerge(layer$62), Layer.provideMerge(layer$64), Layer.provideMerge(layer$67));
12608
+ const storageLayer = Layer.mergeAll(layer$65, layerConfig);
12609
+ const runtimeLayer = layer$61.pipe(Layer.provideMerge(storageLayer));
12460
12610
  //#endregion
12461
12611
  //#region src/cliAuthFormat.ts
12462
12612
  const newline = "\n";
@@ -13211,7 +13361,7 @@ const runWithEnvironmentAuth = (flags, run, options) => Effect.gen(function* ()
13211
13361
  }
13212
13362
  return yield* Effect.gen(function* () {
13213
13363
  return yield* run(yield* EnvironmentAuth);
13214
- }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$67(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
13364
+ }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$68(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
13215
13365
  });
13216
13366
  const ttlFlag = Flag.string("ttl").pipe(Flag.withSchema(DurationFromString), Flag.withDescription("TTL, for example `5m`, `1h`, `30d`, or `15 minutes`."), Flag.optional);
13217
13367
  const jsonFlag = Flag.boolean("json").pipe(Flag.withDescription("Emit JSON instead of human-readable output."), Flag.withDefault(false));
@@ -13351,7 +13501,7 @@ const DEFAULT_LIMITS = {
13351
13501
  windowMillis: FAILURE_WINDOW_MS,
13352
13502
  blockMillis: BLOCK_DURATION_MS
13353
13503
  };
13354
- const make$63 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
13504
+ const make$64 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
13355
13505
  const state = yield* Ref.make(initialThrottleState);
13356
13506
  return HubAuthThrottle.of({
13357
13507
  shouldRefuse: Effect.gen(function* () {
@@ -13365,7 +13515,7 @@ const make$63 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LI
13365
13515
  })
13366
13516
  });
13367
13517
  });
13368
- const layer$59 = Layer.effect(HubAuthThrottle, make$63());
13518
+ const layer$60 = Layer.effect(HubAuthThrottle, make$64());
13369
13519
  //#endregion
13370
13520
  //#region src/hub/HubAuth.ts
13371
13521
  /**
@@ -13817,6 +13967,43 @@ const makeTaskRepository = Effect.gen(function* () {
13817
13967
  task
13818
13968
  })
13819
13969
  })));
13970
+ /**
13971
+ * The claim, and the reason it is a separate method rather than an option on
13972
+ * `patch`: only this one has an outcome a caller must branch on.
13973
+ *
13974
+ * The comparison happens *inside* the transaction alongside the write, which
13975
+ * is the only arrangement that makes it a compare-and-set. Reading first and
13976
+ * writing after would leave exactly the window it exists to close.
13977
+ */
13978
+ const patchIfStatus = (input, updatedAt) => sql.withTransaction(Effect.gen(function* () {
13979
+ const existing = yield* getTaskRow({ taskId: input.patch.taskId });
13980
+ if (Option.isNone(existing)) return { outcome: "missing" };
13981
+ if (existing.value.status !== input.expectedStatus) return {
13982
+ outcome: "conflict",
13983
+ current: existing.value
13984
+ };
13985
+ const updated = {
13986
+ ...existing.value,
13987
+ ...input.patch.projectId !== void 0 ? { projectId: input.patch.projectId } : {},
13988
+ ...input.patch.repositoryKey !== void 0 ? { repositoryKey: input.patch.repositoryKey } : {},
13989
+ ...input.patch.threadId !== void 0 ? { threadId: input.patch.threadId } : {},
13990
+ ...input.patch.title !== void 0 ? { title: input.patch.title } : {},
13991
+ ...input.patch.body !== void 0 ? { body: input.patch.body } : {},
13992
+ ...input.patch.status !== void 0 ? { status: input.patch.status } : {},
13993
+ ...input.patch.priority !== void 0 ? { priority: input.patch.priority } : {},
13994
+ ...input.patch.assignee !== void 0 ? { assignee: input.patch.assignee } : {},
13995
+ ...input.patch.labels !== void 0 ? { labels: input.patch.labels } : {},
13996
+ updatedAt
13997
+ };
13998
+ yield* upsertTaskRow(updated);
13999
+ return {
14000
+ outcome: "updated",
14001
+ task: updated
14002
+ };
14003
+ })).pipe(Effect.mapError(toPersistenceSqlError("TaskRepository.patchIfStatus:query")), Effect.tap((result) => result.outcome === "updated" ? publish({
14004
+ type: "upserted",
14005
+ task: result.task
14006
+ }) : Effect.void));
13820
14007
  const deleteById = (input) => deleteTaskRow(input).pipe(Effect.mapError(toPersistenceSqlError("TaskRepository.deleteById:query")), Effect.tap(() => publish({
13821
14008
  type: "deleted",
13822
14009
  taskId: input.taskId
@@ -13824,6 +14011,7 @@ const makeTaskRepository = Effect.gen(function* () {
13824
14011
  return {
13825
14012
  upsert,
13826
14013
  patch,
14014
+ patchIfStatus,
13827
14015
  getById,
13828
14016
  list,
13829
14017
  deleteById,
@@ -13944,13 +14132,25 @@ const updateTaskRoute = HttpRouter.add("PATCH", "/tasks/:taskId", respondToHubFa
13944
14132
  yield* authenticateHubRequest();
13945
14133
  const params = yield* HttpRouter.params;
13946
14134
  const taskId = TaskId.make(params.taskId ?? "");
13947
- const body = yield* readJsonBody();
14135
+ const { expectedStatus, ...patchBody } = (yield* readJsonBody()) ?? {};
13948
14136
  const input = yield* decodeOrInvalid(TaskUpdateInput, "Request body does not match TaskUpdateInput.")({
13949
- ...body,
14137
+ ...patchBody,
13950
14138
  taskId
13951
14139
  });
13952
14140
  const tasks = yield* TaskRepository;
13953
14141
  const timestamp = DateTime.formatIso(yield* DateTime.now);
14142
+ if (expectedStatus !== void 0) {
14143
+ const condition = yield* decodeOrInvalid(TaskStatus, "expectedStatus is not a task status.")(expectedStatus);
14144
+ const result = yield* tasks.patchIfStatus({
14145
+ patch: input,
14146
+ expectedStatus: condition
14147
+ }, timestamp);
14148
+ if (result.outcome === "missing") return notFound(taskId);
14149
+ return result.outcome === "conflict" ? HttpServerResponse.jsonUnsafe({
14150
+ error: "conflict",
14151
+ current: result.current
14152
+ }, { status: 409 }) : HttpServerResponse.jsonUnsafe(result.task);
14153
+ }
13954
14154
  const patched = yield* tasks.patch(input, timestamp);
13955
14155
  return Option.isNone(patched) ? notFound(taskId) : HttpServerResponse.jsonUnsafe(patched.value);
13956
14156
  })));
@@ -14056,7 +14256,7 @@ const deleteAssetRoute = HttpRouter.add("DELETE", "/assets/:kind/:name", respond
14056
14256
  const outcome = yield* (yield* AgentAssetRepository).deleteByName(requested);
14057
14257
  return outcome._tag === "conflict" ? assetConflict(Option.getOrNull(outcome.current)) : HttpServerResponse.empty({ status: 204 });
14058
14258
  })));
14059
- const layer$58 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
14259
+ const layer$59 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
14060
14260
  //#endregion
14061
14261
  //#region src/hub/Migrations/001_Tasks.ts
14062
14262
  /**
@@ -14271,7 +14471,7 @@ const announce = Layer.effectDiscard(Effect.gen(function* () {
14271
14471
  });
14272
14472
  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 });
14273
14473
  }));
14274
- const makeHubLayer = HttpRouter.serve(layer$58).pipe(Layer.provideMerge(announce), Layer.provideMerge(HubHttpServerLive), Layer.provideMerge(layer$59), Layer.provideMerge(TaskRepositoryLive), Layer.provideMerge(AgentAssetRepositoryLive), Layer.provideMerge(HubPersistenceLive));
14474
+ const makeHubLayer = HttpRouter.serve(layer$59).pipe(Layer.provideMerge(announce), Layer.provideMerge(HubHttpServerLive), Layer.provideMerge(layer$60), Layer.provideMerge(TaskRepositoryLive), Layer.provideMerge(AgentAssetRepositoryLive), Layer.provideMerge(HubPersistenceLive));
14275
14475
  const runHub = Layer.launch(makeHubLayer);
14276
14476
  //#endregion
14277
14477
  //#region src/atomicWrite.ts
@@ -14395,7 +14595,7 @@ function stripDefaultServerSettings(current, defaults) {
14395
14595
  }
14396
14596
  return Object.is(current, defaults) ? void 0 : current;
14397
14597
  }
14398
- const make$62 = Effect.gen(function* () {
14598
+ const make$63 = Effect.gen(function* () {
14399
14599
  const { settingsPath } = yield* ServerConfig$1;
14400
14600
  const fs = yield* FileSystem.FileSystem;
14401
14601
  const pathService = yield* Path.Path;
@@ -14616,7 +14816,7 @@ const make$62 = Effect.gen(function* () {
14616
14816
  }
14617
14817
  };
14618
14818
  });
14619
- const layer$57 = Layer.effect(ServerSettingsService, make$62);
14819
+ const layer$58 = Layer.effect(ServerSettingsService, make$63);
14620
14820
  //#endregion
14621
14821
  //#region src/pathExpansion.ts
14622
14822
  /**
@@ -14638,6 +14838,86 @@ function expandHomePath$3(value) {
14638
14838
  return value;
14639
14839
  }
14640
14840
  //#endregion
14841
+ //#region src/provider/skillOverrides.ts
14842
+ /**
14843
+ * Turning "this skill is disabled" into something a provider enforces.
14844
+ *
14845
+ * **A skill has two names and either can reach it.** Discovery reports the
14846
+ * `SKILL.md` frontmatter `name` when there is one and the directory name
14847
+ * otherwise, while the sync panel lists directories — so the disabled set can
14848
+ * hold either form depending on which surface the toggle was pressed on, and
14849
+ * the CLI keys its own listing on the name it resolved. Matching on one form
14850
+ * only produces a toggle that works for most skills and silently does nothing
14851
+ * for the ones whose frontmatter disagrees with their directory, which is the
14852
+ * worst of the available failures: it looks like the feature works.
14853
+ *
14854
+ * So both forms are matched on the way in and both are emitted on the way out.
14855
+ *
14856
+ * **The lever is `Settings.skillOverrides`, not the SDK's `skills` option.**
14857
+ * `skills: string[]` is an allowlist: passing it enables *only* the listed
14858
+ * skills, so a single disabled skill would silently take every plugin-provided
14859
+ * skill with it, since those are not in our discovery at all. `skillOverrides`
14860
+ * is per skill and additive — an absent key means "on" — so nothing is affected
14861
+ * except what was named.
14862
+ *
14863
+ * @module provider/skillOverrides
14864
+ */
14865
+ /**
14866
+ * Hidden from the model's listing *and* from `/name`.
14867
+ *
14868
+ * The other values the setting accepts are partial hides (`name-only`,
14869
+ * `user-invocable-only`); a p4code toggle labelled "disabled" has to be the
14870
+ * complete one, or the label is a lie.
14871
+ */
14872
+ const SKILL_OVERRIDE_OFF = "off";
14873
+ /**
14874
+ * The directory a skill lives in, from its `SKILL.md` path.
14875
+ *
14876
+ * Path handling by hand rather than through `Path.Path`, because this stays a
14877
+ * pure function: it is called from discovery, from the adapter and from tests,
14878
+ * and the segment separator is the only platform fact it needs.
14879
+ */
14880
+ function skillDirectoryName(skillPath) {
14881
+ const segments = skillPath.split(/[/\\]/).filter((segment) => segment.length > 0);
14882
+ return segments.length >= 2 ? segments[segments.length - 2] ?? "" : "";
14883
+ }
14884
+ /** Every name a skill answers to, ignoring empties. */
14885
+ function namesOf(skill) {
14886
+ const directoryName = skillDirectoryName(skill.path);
14887
+ return [skill.name, directoryName].filter((name) => name.length > 0);
14888
+ }
14889
+ /**
14890
+ * Whether a discovered skill is in the disabled set, under either of its names.
14891
+ */
14892
+ function isSkillDisabled(skill, disabled) {
14893
+ const disabledSet = new Set(disabled);
14894
+ return namesOf(skill).some((name) => disabledSet.has(name));
14895
+ }
14896
+ /**
14897
+ * The `skillOverrides` map to hand a session, or `undefined` when nothing is
14898
+ * disabled.
14899
+ *
14900
+ * `undefined` rather than `{}` on purpose: an empty map is a setting the
14901
+ * session did not have before, and the point of this feature is that a server
14902
+ * with nothing disabled starts sessions byte-identical to the ones it started
14903
+ * yesterday.
14904
+ *
14905
+ * Names that match no discovered skill are still emitted. A skill can be
14906
+ * disabled and then removed from disk, or disabled in a project the current
14907
+ * session is not in, and dropping the entry would quietly re-enable it the
14908
+ * moment discovery misses it.
14909
+ */
14910
+ function buildSkillOverrides(disabled, discovered) {
14911
+ if (disabled.length === 0) return;
14912
+ const overrides = {};
14913
+ for (const name of disabled) if (name.length > 0) overrides[name] = SKILL_OVERRIDE_OFF;
14914
+ for (const skill of discovered) {
14915
+ if (!isSkillDisabled(skill, disabled)) continue;
14916
+ for (const name of namesOf(skill)) overrides[name] = SKILL_OVERRIDE_OFF;
14917
+ }
14918
+ return Object.keys(overrides).length === 0 ? void 0 : overrides;
14919
+ }
14920
+ //#endregion
14641
14921
  //#region src/provider/Drivers/ClaudeSkills.ts
14642
14922
  /**
14643
14923
  * ClaudeSkills — filesystem discovery of Claude Code skills for the `$` picker.
@@ -14709,7 +14989,7 @@ const resolveClaudeUserSkillsDir = Effect.fn("resolveClaudeUserSkillsDir")(funct
14709
14989
  * collisions the project-scoped skill wins, matching Claude Code's
14710
14990
  * most-specific-wins resolution.
14711
14991
  */
14712
- const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config, cwd, environment) {
14992
+ const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config, cwd, environment, disabledSkills) {
14713
14993
  const fileSystem = yield* FileSystem.FileSystem;
14714
14994
  const path = yield* Path.Path;
14715
14995
  const configDirPath = yield* resolveClaudeConfigDirPath(config, environment ?? process.env, cwd);
@@ -14734,7 +15014,10 @@ const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config
14734
15014
  skillsByName.set(name, {
14735
15015
  name,
14736
15016
  path: skillPath,
14737
- enabled: true,
15017
+ enabled: !isSkillDisabled({
15018
+ name,
15019
+ path: skillPath
15020
+ }, disabledSkills ?? []),
14738
15021
  scope: root.scope,
14739
15022
  ...frontmatter.kind === "parsed" && frontmatter.description ? { description: frontmatter.description } : {}
14740
15023
  });
@@ -14749,7 +15032,7 @@ const decodeRegistration$1 = Schema$1.decodeUnknownExit(RegistrationFromJson$1);
14749
15032
  const encodeRegistration = Schema$1.encodeSync(RegistrationFromJson$1);
14750
15033
  var McpRegistry = class extends Context.Service()("@p4code/cli/mcp/McpRegistry") {};
14751
15034
  const slotsOf = (registration) => registration.secrets ?? [];
14752
- const make$61 = Effect.gen(function* () {
15035
+ const make$62 = Effect.gen(function* () {
14753
15036
  const config = yield* ServerConfig$1;
14754
15037
  const secrets = yield* ServerSecretStore;
14755
15038
  const fileSystem = yield* FileSystem.FileSystem;
@@ -14861,7 +15144,7 @@ const make$61 = Effect.gen(function* () {
14861
15144
  }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry resolve failed", { cause }).pipe(Effect.as({}))))
14862
15145
  };
14863
15146
  });
14864
- const layer$56 = Layer.effect(McpRegistry, make$61);
15147
+ const layer$57 = Layer.effect(McpRegistry, make$62);
14865
15148
  //#endregion
14866
15149
  //#region src/sync/HubLink.ts
14867
15150
  /**
@@ -14958,7 +15241,7 @@ const formatHubLink = (input) => encodeStoredHubLink({
14958
15241
  shareMode: input.shareMode
14959
15242
  });
14960
15243
  const fromEnvironment = (environment) => validateHubLink(environment.P4CODE_HUB_URL ?? "", environment.P4CODE_HUB_TOKEN ?? "");
14961
- const make$60 = Effect.fn("HubLink.make")(function* (environment) {
15244
+ const make$61 = Effect.fn("HubLink.make")(function* (environment) {
14962
15245
  const secrets = yield* ServerSecretStore;
14963
15246
  const env = environment ?? process.env;
14964
15247
  const fromEnv = fromEnvironment(env);
@@ -15024,7 +15307,7 @@ const make$60 = Effect.fn("HubLink.make")(function* (environment) {
15024
15307
  })
15025
15308
  };
15026
15309
  });
15027
- const layer$55 = Layer.effect(HubLink, make$60());
15310
+ const layer$56 = Layer.effect(HubLink, make$61());
15028
15311
  //#endregion
15029
15312
  //#region src/sync/HubAssetClient.ts
15030
15313
  /**
@@ -15039,7 +15322,7 @@ const layer$55 = Layer.effect(HubLink, make$60());
15039
15322
  *
15040
15323
  * @module sync/HubAssetClient
15041
15324
  */
15042
- const HUB_REQUEST_TIMEOUT_MS = 15e3;
15325
+ const HUB_REQUEST_TIMEOUT_MS$1 = 15e3;
15043
15326
  /**
15044
15327
  * The hub could not be reached, or answered something unusable.
15045
15328
  *
@@ -15052,12 +15335,12 @@ var HubAssetConflict = class extends Data.TaggedError("HubAssetConflict") {};
15052
15335
  /** No hub is configured on this server, so there is nothing to talk to. */
15053
15336
  var HubNotConfigured = class extends Data.TaggedError("HubNotConfigured") {};
15054
15337
  const AssetListPage = Schema$1.Struct({ assets: Schema$1.Array(AgentAsset) });
15055
- const ConflictBody = Schema$1.Struct({ current: Schema$1.NullOr(AgentAsset) });
15338
+ const ConflictBody$1 = Schema$1.Struct({ current: Schema$1.NullOr(AgentAsset) });
15056
15339
  const decodeAssetListPage = Schema$1.decodeUnknownEffect(AssetListPage);
15057
- const decodeConflictBody = Schema$1.decodeUnknownEffect(ConflictBody);
15340
+ const decodeConflictBody$1 = Schema$1.decodeUnknownEffect(ConflictBody$1);
15058
15341
  const decodeAsset = Schema$1.decodeUnknownEffect(AgentAsset);
15059
15342
  var HubAssetClient = class extends Context.Service()("@p4code/cli/sync/HubAssetClient") {};
15060
- const make$59 = Effect.gen(function* () {
15343
+ const make$60 = Effect.gen(function* () {
15061
15344
  const http = yield* HttpClient.HttpClient;
15062
15345
  const link = yield* HubLink;
15063
15346
  const requireSettings = Effect.gen(function* () {
@@ -15066,7 +15349,7 @@ const make$59 = Effect.gen(function* () {
15066
15349
  return state.settings.value;
15067
15350
  });
15068
15351
  const send = Effect.fn("HubAssetClient.send")(function* (operation, settings, request) {
15069
- return yield* http.execute(request.pipe(HttpClientRequest.setHeader("authorization", `Bearer ${settings.token}`), HttpClientRequest.setHeader("accept", "application/json"))).pipe(Effect.timeout(HUB_REQUEST_TIMEOUT_MS), Effect.mapError((cause) => new HubUnavailable({
15352
+ return yield* http.execute(request.pipe(HttpClientRequest.setHeader("authorization", `Bearer ${settings.token}`), HttpClientRequest.setHeader("accept", "application/json"))).pipe(Effect.timeout(HUB_REQUEST_TIMEOUT_MS$1), Effect.mapError((cause) => new HubUnavailable({
15070
15353
  operation,
15071
15354
  detail: `${cause._tag ?? "error"}`
15072
15355
  })));
@@ -15086,7 +15369,7 @@ const make$59 = Effect.gen(function* () {
15086
15369
  * which is what lets a caller show both sides instead of only saying no.
15087
15370
  */
15088
15371
  const conflictFrom = Effect.fn("HubAssetClient.conflictFrom")(function* (name, response) {
15089
- const body = yield* decodeBody("conflict", decodeConflictBody, response).pipe(Effect.orElseSucceed(() => ({ current: null })));
15372
+ const body = yield* decodeBody("conflict", decodeConflictBody$1, response).pipe(Effect.orElseSucceed(() => ({ current: null })));
15090
15373
  return new HubAssetConflict({
15091
15374
  name,
15092
15375
  current: body.current === null ? Option.none() : Option.some(body.current)
@@ -15139,7 +15422,7 @@ const make$59 = Effect.gen(function* () {
15139
15422
  remove
15140
15423
  };
15141
15424
  });
15142
- const layer$54 = Layer.effect(HubAssetClient, make$59);
15425
+ const layer$55 = Layer.effect(HubAssetClient, make$60);
15143
15426
  //#endregion
15144
15427
  //#region src/sync/mcpRegistrationFiles.ts
15145
15428
  /**
@@ -15878,7 +16161,7 @@ const EMPTY_REPORT = {
15878
16161
  unavailable: null
15879
16162
  };
15880
16163
  var AssetSync = class extends Context.Service()("@p4code/cli/sync/AssetSync") {};
15881
- const make$58 = Effect.gen(function* () {
16164
+ const make$59 = Effect.gen(function* () {
15882
16165
  const client = yield* HubAssetClient;
15883
16166
  const link = yield* HubLink;
15884
16167
  const settingsStore = yield* ServerSettingsService;
@@ -16575,10 +16858,10 @@ const make$58 = Effect.gen(function* () {
16575
16858
  removeLocal
16576
16859
  };
16577
16860
  });
16578
- const layer$53 = Layer.effect(AssetSync, make$58);
16861
+ const layer$54 = Layer.effect(AssetSync, make$59);
16579
16862
  //#endregion
16580
16863
  //#region src/cli/assets.ts
16581
- const SyncServicesLive = layer$53.pipe(Layer.provideMerge(layer$54), Layer.provideMerge(layer$55), Layer.provideMerge(layer$57.pipe(Layer.provide(layer$64))), Layer.provideMerge(layer$64), Layer.provideMerge(FetchHttpClient.layer));
16864
+ const SyncServicesLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56), Layer.provideMerge(layer$58.pipe(Layer.provide(layer$65))), Layer.provideMerge(layer$65), Layer.provideMerge(FetchHttpClient.layer));
16582
16865
  const runWithSync = (flags, run) => Effect.gen(function* () {
16583
16866
  const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
16584
16867
  return yield* Effect.gen(function* () {
@@ -16586,7 +16869,7 @@ const runWithSync = (flags, run) => Effect.gen(function* () {
16586
16869
  sync: yield* AssetSync,
16587
16870
  link: yield* HubLink
16588
16871
  });
16589
- }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$67(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
16872
+ }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$68(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
16590
16873
  });
16591
16874
  const STATE_LABEL = {
16592
16875
  synced: "synced",
@@ -21801,12 +22084,12 @@ const runProcessCore = Effect.fn("processRunner.runProcessCore")(function* (spaw
21801
22084
  stderrTruncated: stderr.truncated
21802
22085
  };
21803
22086
  });
21804
- const make$57 = Effect.fn("ProcessRunner.make")(function* () {
22087
+ const make$58 = Effect.fn("ProcessRunner.make")(function* () {
21805
22088
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
21806
22089
  const run = (input) => finalizeRunProcess(runProcessCore(spawner, input), input);
21807
22090
  return ProcessRunner.of({ run });
21808
22091
  });
21809
- const layer$52 = Layer.effect(ProcessRunner, make$57());
22092
+ const layer$53 = Layer.effect(ProcessRunner, make$58());
21810
22093
  //#endregion
21811
22094
  //#region src/project/RepositoryIdentityResolver.ts
21812
22095
  const DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY = 512;
@@ -21897,7 +22180,7 @@ const resolveRepositoryIdentityFromCacheKey = Effect.fn("RepositoryIdentityResol
21897
22180
  rootPath: cacheKey
21898
22181
  }) : null;
21899
22182
  });
21900
- const make$56 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
22183
+ const make$57 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
21901
22184
  const processRunner = yield* ProcessRunner;
21902
22185
  const repositoryIdentityCache = yield* Cache.makeWith((cacheKey) => resolveRepositoryIdentityFromCacheKey(cacheKey).pipe(Effect.provideService(ProcessRunner, processRunner)), {
21903
22186
  capacity: options.cacheCapacity ?? DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY,
@@ -21912,7 +22195,7 @@ const make$56 = Effect.fn("RepositoryIdentityResolver.make")(function* (options
21912
22195
  });
21913
22196
  return RepositoryIdentityResolver.of({ resolve });
21914
22197
  });
21915
- const layer$51 = Layer.effect(RepositoryIdentityResolver, make$56()).pipe(Layer.provide(layer$52));
22198
+ const layer$52 = Layer.effect(RepositoryIdentityResolver, make$57()).pipe(Layer.provide(layer$53));
21916
22199
  //#endregion
21917
22200
  //#region src/orchestration/Layers/ProjectionSnapshotQuery.ts
21918
22201
  const decodeReadModel = Schema$1.decodeUnknownEffect(OrchestrationReadModel);
@@ -23667,7 +23950,7 @@ function mergeWithDefaultKeybindings(custom) {
23667
23950
  * Keybindings - Service tag for keybinding configuration operations.
23668
23951
  */
23669
23952
  var Keybindings = class extends Context.Service()("@p4code/cli/keybindings") {};
23670
- const make$55 = Effect.gen(function* () {
23953
+ const make$56 = Effect.gen(function* () {
23671
23954
  const { keybindingsConfigPath } = yield* ServerConfig$1;
23672
23955
  const fs = yield* FileSystem.FileSystem;
23673
23956
  const path = yield* Path.Path;
@@ -23928,7 +24211,7 @@ const make$55 = Effect.gen(function* () {
23928
24211
  }))
23929
24212
  };
23930
24213
  });
23931
- const layer$50 = Layer.effect(Keybindings, make$55);
24214
+ const layer$51 = Layer.effect(Keybindings, make$56);
23932
24215
  //#endregion
23933
24216
  //#region src/process/externalLauncher.ts
23934
24217
  /**
@@ -24155,7 +24438,7 @@ const launchEditorProcess = Effect.fn("externalLauncher.launchEditorProcess")(fu
24155
24438
  cause
24156
24439
  }));
24157
24440
  });
24158
- const make$54 = Effect.gen(function* () {
24441
+ const make$55 = Effect.gen(function* () {
24159
24442
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
24160
24443
  const fileSystem = yield* FileSystem.FileSystem;
24161
24444
  const path = yield* Path.Path;
@@ -24166,7 +24449,7 @@ const make$54 = Effect.gen(function* () {
24166
24449
  launchEditor: (input) => provideCommandResolutionServices(Effect.flatMap(resolveEditorLaunch(input), (launch) => launchEditorProcess(launch).pipe(Effect.provideService(ChildProcessSpawner$1.ChildProcessSpawner, spawner))))
24167
24450
  });
24168
24451
  });
24169
- const layer$49 = Layer.effect(ExternalLauncher, make$54);
24452
+ const layer$50 = Layer.effect(ExternalLauncher, make$55);
24170
24453
  //#endregion
24171
24454
  //#region src/orchestration/Services/OrchestrationReactor.ts
24172
24455
  /**
@@ -24184,7 +24467,7 @@ var OrchestrationReactor = class extends Context.Service()("@p4code/cli/orchestr
24184
24467
  //#endregion
24185
24468
  //#region src/serverLifecycleEvents.ts
24186
24469
  var ServerLifecycleEvents = class extends Context.Service()("@p4code/cli/serverLifecycleEvents") {};
24187
- const make$53 = Effect.gen(function* () {
24470
+ const make$54 = Effect.gen(function* () {
24188
24471
  const pubsub = yield* PubSub.unbounded();
24189
24472
  const state = yield* Ref.make({
24190
24473
  sequence: 0,
@@ -24208,7 +24491,7 @@ const make$53 = Effect.gen(function* () {
24208
24491
  }
24209
24492
  };
24210
24493
  });
24211
- const layer$48 = Layer.effect(ServerLifecycleEvents, make$53);
24494
+ const layer$49 = Layer.effect(ServerLifecycleEvents, make$54);
24212
24495
  //#endregion
24213
24496
  //#region src/telemetry/Identify.ts
24214
24497
  const CodexAuthJsonSchema = Schema$1.Struct({ tokens: Schema$1.Struct({ account_id: Schema$1.String }) });
@@ -24381,7 +24664,7 @@ var AnalyticsService = class AnalyticsService extends Context.Service()("@p4code
24381
24664
  /** No-op layer for callers that intentionally disable telemetry. */
24382
24665
  static layerTest = Layer.succeed(AnalyticsService, inert);
24383
24666
  };
24384
- const make$52 = Effect.gen(function* () {
24667
+ const make$53 = Effect.gen(function* () {
24385
24668
  const telemetryConfig = yield* TelemetryEnvConfig;
24386
24669
  const posthogKey = telemetryConfig.posthogKey.trim();
24387
24670
  if (!telemetryConfig.enabled || posthogKey === "") return inert;
@@ -24451,7 +24734,7 @@ const make$52 = Effect.gen(function* () {
24451
24734
  flush
24452
24735
  });
24453
24736
  });
24454
- const layer$47 = Layer.effect(AnalyticsService, make$52);
24737
+ const layer$48 = Layer.effect(AnalyticsService, make$53);
24455
24738
  AnalyticsService.layerTest;
24456
24739
  //#endregion
24457
24740
  //#region src/service/pinnedRuntime.ts
@@ -24798,7 +25081,7 @@ var BootServiceInstallError = class extends Schema$1.TaggedErrorClass()("BootSer
24798
25081
  }
24799
25082
  };
24800
25083
  var BootService = class extends Context.Service()("@p4code/cli/service/bootService") {};
24801
- const make$51 = Effect.fn("cloud.boot_service.make")(function* (input) {
25084
+ const make$52 = Effect.fn("cloud.boot_service.make")(function* (input) {
24802
25085
  const hostExecPath = yield* HostProcessExecutablePath;
24803
25086
  const hostArguments = yield* HostProcessArguments;
24804
25087
  const host = input.host ?? {
@@ -25017,7 +25300,7 @@ const make$51 = Effect.fn("cloud.boot_service.make")(function* (input) {
25017
25300
  logPath
25018
25301
  });
25019
25302
  });
25020
- const layer$46 = (input) => Layer.effect(BootService, make$51(input));
25303
+ const layer$47 = (input) => Layer.effect(BootService, make$52(input));
25021
25304
  //#endregion
25022
25305
  //#region src/service/selfUpdate.ts
25023
25306
  /**
@@ -25092,7 +25375,7 @@ const resolveServerSelfUpdateCapability = Effect.fn("cloud.server_self_update.re
25092
25375
  return null;
25093
25376
  });
25094
25377
  var ServerSelfUpdate = class extends Context.Service()("@p4code/cli/service/selfUpdate/ServerSelfUpdate") {};
25095
- const make$50 = Effect.fn("cloud.server_self_update.make")(function* (options) {
25378
+ const make$51 = Effect.fn("cloud.server_self_update.make")(function* (options) {
25096
25379
  const serverConfig = yield* ServerConfig$1;
25097
25380
  const fs = yield* FileSystem.FileSystem;
25098
25381
  const path = yield* Path.Path;
@@ -25242,7 +25525,7 @@ const make$50 = Effect.fn("cloud.server_self_update.make")(function* (options) {
25242
25525
  });
25243
25526
  return ServerSelfUpdate.of({ update });
25244
25527
  });
25245
- const layer$45 = Layer.effect(ServerSelfUpdate, make$50()).pipe(Layer.provide(layer$52));
25528
+ const layer$46 = Layer.effect(ServerSelfUpdate, make$51()).pipe(Layer.provide(layer$53));
25246
25529
  //#endregion
25247
25530
  //#region src/environment/ServerEnvironmentLabel.ts
25248
25531
  const ServerEnvironmentLabelCommandProbe = Schema$1.Literals(["macos-computer-name", "linux-pretty-hostname"]);
@@ -25374,7 +25657,7 @@ function platformArch(architecture) {
25374
25657
  default: return "other";
25375
25658
  }
25376
25659
  }
25377
- const make$49 = Effect.gen(function* () {
25660
+ const make$50 = Effect.gen(function* () {
25378
25661
  const fileSystem = yield* FileSystem.FileSystem;
25379
25662
  const path = yield* Path.Path;
25380
25663
  const serverConfig = yield* ServerConfig$1;
@@ -25437,7 +25720,7 @@ const make$49 = Effect.gen(function* () {
25437
25720
  * state. It intentionally has no fallback Layer.succeed value: callers must
25438
25721
  * provide the external platform services and a ServerConfig.
25439
25722
  */
25440
- const layer$44 = Layer.effect(ServerEnvironment, make$49).pipe(Layer.provide(layer$52));
25723
+ const layer$45 = Layer.effect(ServerEnvironment, make$50).pipe(Layer.provide(layer$53));
25441
25724
  //#endregion
25442
25725
  //#region src/provider/Services/ProviderSessionReaper.ts
25443
25726
  var ProviderSessionReaper = class extends Context.Service()("@p4code/cli/provider/Services/ProviderSessionReaper") {};
@@ -26513,7 +26796,7 @@ const maybeOpenBrowser = (target) => Effect.gen(function* () {
26513
26796
  yield* (yield* ExternalLauncher).launchBrowser(target).pipe(Effect.catch(() => Effect.logInfo("browser auto-open unavailable", { hint: `Open ${target} in your browser.` })));
26514
26797
  });
26515
26798
  const runStartupPhase = (phase, effect) => effect.pipe(Effect.annotateSpans({ "startup.phase": phase }), Effect.withSpan(`server.startup.${phase}`));
26516
- const make$48 = Effect.gen(function* () {
26799
+ const make$49 = Effect.gen(function* () {
26517
26800
  const serverConfig = yield* ServerConfig$1;
26518
26801
  const keybindings = yield* Keybindings;
26519
26802
  const orchestrationReactor = yield* OrchestrationReactor;
@@ -26654,7 +26937,7 @@ const make$48 = Effect.gen(function* () {
26654
26937
  enqueueCommand: commandGate.enqueueCommand
26655
26938
  };
26656
26939
  });
26657
- const layer$43 = Layer.effect(ServerRuntimeStartup, make$48);
26940
+ const layer$44 = Layer.effect(ServerRuntimeStartup, make$49);
26658
26941
  //#endregion
26659
26942
  //#region src/serverRuntimeState.ts
26660
26943
  const PersistedServerRuntimeState = Schema$1.Struct({
@@ -26802,7 +27085,7 @@ function expandHomePath$2(input, path) {
26802
27085
  if (input.startsWith("~/") || input.startsWith("~\\")) return path.join(NodeOS.homedir(), input.slice(2));
26803
27086
  return input;
26804
27087
  }
26805
- const make$47 = Effect.gen(function* () {
27088
+ const make$48 = Effect.gen(function* () {
26806
27089
  const fileSystem = yield* FileSystem.FileSystem;
26807
27090
  const path = yield* Path.Path;
26808
27091
  const statWorkspaceRoot = Effect.fn("WorkspacePaths.statWorkspaceRoot")(function* (workspaceRoot, normalizedWorkspaceRoot, phase) {
@@ -26859,7 +27142,7 @@ const make$47 = Effect.gen(function* () {
26859
27142
  resolveRelativePathWithinRoot
26860
27143
  });
26861
27144
  });
26862
- const layer$42 = Layer.effect(WorkspacePaths, make$47);
27145
+ const layer$43 = Layer.effect(WorkspacePaths, make$48);
26863
27146
  //#endregion
26864
27147
  //#region src/cli/project.ts
26865
27148
  const isEnvironmentHttpCommonError = Schema$1.is(EnvironmentHttpCommonError);
@@ -26965,7 +27248,7 @@ const projectCommandUuid = Crypto.Crypto.pipe(Effect.flatMap((crypto) => crypto.
26965
27248
  operation: "generateProjectCommandId",
26966
27249
  cause
26967
27250
  })));
26968
- const ProjectCliRuntimeLive = Layer.mergeAll(layer$42, OrchestrationLayerLive.pipe(Layer.provideMerge(layer$51), Layer.provideMerge(layerConfig)));
27251
+ const ProjectCliRuntimeLive = Layer.mergeAll(layer$43, OrchestrationLayerLive.pipe(Layer.provideMerge(layer$52), Layer.provideMerge(layerConfig)));
26969
27252
  const PROJECT_CLI_LIVE_SERVER_TIMEOUT = Duration.seconds(1);
26970
27253
  const withProjectCliSessionToken = (environmentAuth, run) => Effect.acquireUseRelease(environmentAuth.issueSession({
26971
27254
  scopes: AuthAdministrativeScopes,
@@ -27056,7 +27339,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
27056
27339
  });
27057
27340
  yield* Console.log(output);
27058
27341
  }));
27059
- const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$67(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
27342
+ const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$68(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
27060
27343
  return yield* Effect.gen(function* () {
27061
27344
  const snapshot = yield* getOfflineSnapshot();
27062
27345
  const orchestrationEngine = yield* OrchestrationEngineService;
@@ -27067,7 +27350,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
27067
27350
  });
27068
27351
  yield* Console.log(output);
27069
27352
  }).pipe(Effect.provide(offlineRuntimeLayer));
27070
- }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$42).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$67(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
27353
+ }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$43).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$68(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
27071
27354
  });
27072
27355
  const projectAddCommand = Command.make("add", {
27073
27356
  ...projectLocationFlags,
@@ -27674,7 +27957,7 @@ const logP4ProjectFileLoadError = (error) => Effect.logWarning(error).pipe(Effec
27674
27957
  filePath: error.filePath,
27675
27958
  errorTag: error._tag
27676
27959
  }));
27677
- const make$46 = Effect.gen(function* () {
27960
+ const make$47 = Effect.gen(function* () {
27678
27961
  const fileSystem = yield* FileSystem.FileSystem;
27679
27962
  const path = yield* Path.Path;
27680
27963
  const load = Effect.fn("P4ProjectFileLoader.load")(function* (workspaceRoot) {
@@ -27695,7 +27978,7 @@ const make$46 = Effect.gen(function* () {
27695
27978
  });
27696
27979
  return P4ProjectFileLoader.of({ load });
27697
27980
  });
27698
- const layer$41 = Layer.effect(P4ProjectFileLoader, make$46);
27981
+ const layer$42 = Layer.effect(P4ProjectFileLoader, make$47);
27699
27982
  //#endregion
27700
27983
  //#region src/project/ProjectFaviconResolver.ts
27701
27984
  /**
@@ -27766,7 +28049,7 @@ function extractIconHref(source) {
27766
28049
  return null;
27767
28050
  }
27768
28051
  const optionOnNotFound$1 = (effect) => effect.pipe(Effect.map(Option.some), Effect.catchTags({ PlatformError: (error) => error.reason._tag === "NotFound" ? Effect.succeed(Option.none()) : Effect.fail(error) }));
27769
- const make$45 = Effect.gen(function* () {
28052
+ const make$46 = Effect.gen(function* () {
27770
28053
  const fileSystem = yield* FileSystem.FileSystem;
27771
28054
  const path = yield* Path.Path;
27772
28055
  const workspacePaths = yield* WorkspacePaths;
@@ -27835,7 +28118,7 @@ const make$45 = Effect.gen(function* () {
27835
28118
  });
27836
28119
  return ProjectFaviconResolver.of({ resolvePath });
27837
28120
  });
27838
- const layer$40 = Layer.effect(ProjectFaviconResolver, make$45);
28121
+ const layer$41 = Layer.effect(ProjectFaviconResolver, make$46);
27839
28122
  //#endregion
27840
28123
  //#region src/assets/AssetAccess.ts
27841
28124
  const ASSET_ROUTE_PREFIX = "/api/assets";
@@ -28088,10 +28371,10 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
28088
28371
  //#endregion
28089
28372
  //#region src/observability/BrowserTraceCollector.ts
28090
28373
  var BrowserTraceCollector = class extends Context.Service()("@p4code/cli/observability/BrowserTraceCollector") {};
28091
- const make$44 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
28374
+ const make$45 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
28092
28375
  for (const record of records) sink.push(record);
28093
28376
  }) });
28094
- const layer$39 = (sink) => Layer.succeed(BrowserTraceCollector, make$44(sink));
28377
+ const layer$40 = (sink) => Layer.succeed(BrowserTraceCollector, make$45(sink));
28095
28378
  //#endregion
28096
28379
  //#region src/auth/http.ts
28097
28380
  const CREDENTIAL_RESPONSE_HEADERS = {
@@ -30305,7 +30588,7 @@ const classifyNonZeroExit = (command, stderr) => {
30305
30588
  if (command === "gh" && (normalized.includes("could not resolve to a pullrequest") || normalized.includes("repository.pullrequest") || normalized.includes("no pull requests found for branch") || normalized.includes("pull request not found")) || command === "glab" && (normalized.includes("merge request not found") || normalized.includes("not found") || normalized.includes("404")) || command === "az" && normalized.includes("pull request") && (normalized.includes("not found") || normalized.includes("does not exist"))) return "not-found";
30306
30589
  return "command-failed";
30307
30590
  };
30308
- const make$43 = Effect.gen(function* () {
30591
+ const make$44 = Effect.gen(function* () {
30309
30592
  const processRunner = yield* ProcessRunner;
30310
30593
  const run = Effect.fn("VcsProcess.run")(function* (input) {
30311
30594
  const baseError = {
@@ -30362,7 +30645,7 @@ const make$43 = Effect.gen(function* () {
30362
30645
  });
30363
30646
  return VcsProcess.of({ run });
30364
30647
  });
30365
- const layer$38 = Layer.effect(VcsProcess, make$43).pipe(Layer.provide(layer$52));
30648
+ const layer$39 = Layer.effect(VcsProcess, make$44).pipe(Layer.provide(layer$53));
30366
30649
  //#endregion
30367
30650
  //#region src/vcs/VcsDriver.ts
30368
30651
  var VcsDriver = class extends Context.Service()("@p4code/cli/vcs/VcsDriver") {};
@@ -30813,12 +31096,12 @@ const makeVcsDriver = Effect.gen(function* () {
30813
31096
  const driver = yield* makeVcsDriverShape();
30814
31097
  return VcsDriver.of(driver);
30815
31098
  });
30816
- const make$42 = Effect.gen(function* () {
31099
+ const make$43 = Effect.gen(function* () {
30817
31100
  const git = yield* makeGitVcsDriverCore();
30818
31101
  return GitVcsDriver.of(git);
30819
31102
  });
30820
31103
  Layer.effect(VcsDriver, makeVcsDriver);
30821
- const layer$37 = Layer.effect(GitVcsDriver, make$42);
31104
+ const layer$38 = Layer.effect(GitVcsDriver, make$43);
30822
31105
  //#endregion
30823
31106
  //#region src/vcs/VcsProjectConfig.ts
30824
31107
  const ProjectVcsConfigJson = fromLenientJson(Schema$1.Struct({
@@ -30850,7 +31133,7 @@ const logVcsProjectConfigError = (error) => Effect.logWarning(error).pipe(Effect
30850
31133
  configPath: error.configPath,
30851
31134
  errorTag: error._tag
30852
31135
  }));
30853
- const make$41 = Effect.gen(function* () {
31136
+ const make$42 = Effect.gen(function* () {
30854
31137
  const fileSystem = yield* FileSystem.FileSystem;
30855
31138
  const path = yield* Path.Path;
30856
31139
  const findConfigPath = Effect.fn("VcsProjectConfig.findConfigPath")(function* (cwd) {
@@ -30891,7 +31174,7 @@ const make$41 = Effect.gen(function* () {
30891
31174
  });
30892
31175
  return VcsProjectConfig.of({ resolveKind });
30893
31176
  });
30894
- const layer$36 = Layer.effect(VcsProjectConfig, make$41);
31177
+ const layer$37 = Layer.effect(VcsProjectConfig, make$42);
30895
31178
  //#endregion
30896
31179
  //#region src/vcs/VcsDriverRegistry.ts
30897
31180
  const DETECTION_CACHE_CAPACITY = 2048;
@@ -30911,7 +31194,7 @@ function parseDetectionCacheKey(key) {
30911
31194
  cwd: key.slice(separatorIndex + 1)
30912
31195
  };
30913
31196
  }
30914
- const make$40 = Effect.gen(function* () {
31197
+ const make$41 = Effect.gen(function* () {
30915
31198
  const projectConfig = yield* VcsProjectConfig;
30916
31199
  const git = yield* makeVcsDriver;
30917
31200
  const drivers = { git };
@@ -30968,7 +31251,7 @@ const make$40 = Effect.gen(function* () {
30968
31251
  resolve
30969
31252
  });
30970
31253
  });
30971
- const layer$35 = Layer.effect(VcsDriverRegistry, make$40).pipe(Layer.provide(layer$36));
31254
+ const layer$36 = Layer.effect(VcsDriverRegistry, make$41).pipe(Layer.provide(layer$37));
30972
31255
  //#endregion
30973
31256
  //#region src/checkpointing/CheckpointStore.ts
30974
31257
  /**
@@ -30988,7 +31271,7 @@ const layer$35 = Layer.effect(VcsDriverRegistry, make$40).pipe(Layer.provide(lay
30988
31271
  */
30989
31272
  /** Service tag for checkpoint persistence and restore operations. */
30990
31273
  var CheckpointStore = class extends Context.Service()("@p4code/cli/checkpointing/CheckpointStore") {};
30991
- const make$39 = Effect.gen(function* () {
31274
+ const make$40 = Effect.gen(function* () {
30992
31275
  const vcsRegistry = yield* VcsDriverRegistry;
30993
31276
  const resolveCheckpoints = Effect.fn("CheckpointStore.resolveCheckpoints")(function* (operation, cwd) {
30994
31277
  const handle = yield* vcsRegistry.resolve({ cwd });
@@ -31027,7 +31310,7 @@ const make$39 = Effect.gen(function* () {
31027
31310
  deleteCheckpointRefs
31028
31311
  });
31029
31312
  });
31030
- const layer$34 = Layer.effect(CheckpointStore, make$39);
31313
+ const layer$35 = Layer.effect(CheckpointStore, make$40);
31031
31314
  //#endregion
31032
31315
  //#region src/checkpointing/CheckpointDiffQuery.ts
31033
31316
  /**
@@ -31049,7 +31332,7 @@ function buildTurnDiffResult(input, diff) {
31049
31332
  diff
31050
31333
  };
31051
31334
  }
31052
- const make$38 = Effect.gen(function* () {
31335
+ const make$39 = Effect.gen(function* () {
31053
31336
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
31054
31337
  const checkpointStore = yield* CheckpointStore;
31055
31338
  const getTurnDiff = Effect.fn("getTurnDiff")(function* (input) {
@@ -31185,7 +31468,7 @@ const make$38 = Effect.gen(function* () {
31185
31468
  getFullThreadDiff
31186
31469
  });
31187
31470
  });
31188
- const layer$33 = Layer.effect(CheckpointDiffQuery, make$38);
31471
+ const layer$34 = Layer.effect(CheckpointDiffQuery, make$39);
31189
31472
  //#endregion
31190
31473
  //#region src/orchestration/ActivityPayloadProjection.ts
31191
31474
  function asRecord$1(value) {
@@ -32038,7 +32321,7 @@ function makeUpdateState(input) {
32038
32321
  output: input.output ?? null
32039
32322
  };
32040
32323
  }
32041
- const make$37 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
32324
+ const make$38 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
32042
32325
  const providerRegistry = yield* ProviderRegistry;
32043
32326
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
32044
32327
  const httpClient = yield* HttpClient.HttpClient;
@@ -32153,7 +32436,7 @@ const make$37 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
32153
32436
  });
32154
32437
  return ProviderMaintenanceRunner.of({ updateProvider });
32155
32438
  });
32156
- const layer$32 = Layer.effect(ProviderMaintenanceRunner, make$37());
32439
+ const layer$33 = Layer.effect(ProviderMaintenanceRunner, make$38());
32157
32440
  //#endregion
32158
32441
  //#region src/provider/Services/ProviderInstanceRegistry.ts
32159
32442
  var ProviderInstanceRegistry = class extends Context.Service()("@p4code/cli/provider/Services/ProviderInstanceRegistry") {};
@@ -32177,11 +32460,228 @@ const makeTextGenerationFromRegistry = (registry) => TextGeneration.of({
32177
32460
  detail: "This provider does not report account usage."
32178
32461
  }))))
32179
32462
  });
32180
- const make$36 = Effect.gen(function* () {
32463
+ const make$37 = Effect.gen(function* () {
32181
32464
  const registry = yield* ProviderInstanceRegistry;
32182
32465
  return makeTextGenerationFromRegistry(registry);
32183
32466
  });
32184
- const layer$31 = Layer.effect(TextGeneration, make$36);
32467
+ const layer$32 = Layer.effect(TextGeneration, make$37);
32468
+ const SKILL_MANIFEST_FILENAME = "SKILL.md";
32469
+ /**
32470
+ * Split a catalogue id (`owner/repo/skill-name`) into its parts.
32471
+ *
32472
+ * The skill segment is everything after the repository, because a nested skill
32473
+ * id contains slashes and rejoining the tail is the only reading that survives
32474
+ * one.
32475
+ */
32476
+ function parseRegistrySkillId(id) {
32477
+ const segments = id.split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0);
32478
+ if (segments.length < 3) return null;
32479
+ const [owner, repo, ...rest] = segments;
32480
+ if (!owner || !repo || rest.length === 0) return null;
32481
+ return {
32482
+ owner,
32483
+ repo,
32484
+ skillId: rest.join("/")
32485
+ };
32486
+ }
32487
+ /**
32488
+ * Where the skill lives in the repository, from the repository's file list.
32489
+ *
32490
+ * Matched on `<...>/<skillId>/SKILL.md` rather than on any fixed layout,
32491
+ * because repositories disagree: some keep skills at the root, some under
32492
+ * `skills/`, some several levels down inside a plugin. The shallowest match
32493
+ * wins, which is what picks the skill itself over a copy vendored inside an
32494
+ * example or a test fixture.
32495
+ */
32496
+ function chooseSkillRoot(entries, skillId) {
32497
+ const leaf = skillId.split("/").pop() ?? skillId;
32498
+ const candidates = [];
32499
+ for (const entry of entries) {
32500
+ if (entry.type !== "blob" || !entry.path.endsWith(`/SKILL.md`)) {
32501
+ if (entry.type === "blob" && entry.path === "SKILL.md") candidates.push("");
32502
+ continue;
32503
+ }
32504
+ const root = entry.path.slice(0, -9);
32505
+ if ((root.split("/").pop() ?? root) === leaf || root === skillId || root.endsWith(`/${skillId}`)) candidates.push(root);
32506
+ }
32507
+ if (candidates.length === 0) return null;
32508
+ candidates.sort((left, right) => {
32509
+ const depth = left.split("/").length - right.split("/").length;
32510
+ return depth === 0 ? left.localeCompare(right) : depth;
32511
+ });
32512
+ return candidates[0] ?? null;
32513
+ }
32514
+ /**
32515
+ * The files under a skill root, bounded and with the manifest first.
32516
+ *
32517
+ * `SKILL.md` leads because it is the one file that must arrive: everything
32518
+ * downstream — the local create refusal, the panel preview, discovery — keys on
32519
+ * it, so if a bound is going to drop something it must not be that.
32520
+ */
32521
+ function selectSkillFiles(entries, root) {
32522
+ const prefix = root === "" ? "" : `${root}/`;
32523
+ const manifestPath = `${prefix}${SKILL_MANIFEST_FILENAME}`;
32524
+ const inRoot = entries.filter((entry) => entry.type === "blob" && entry.path.startsWith(prefix) && entry.path !== `${prefix}`);
32525
+ const ordered = [...inRoot.filter((entry) => entry.path === manifestPath), ...inRoot.filter((entry) => entry.path !== manifestPath).sort((left, right) => left.path.localeCompare(right.path))];
32526
+ const paths = [];
32527
+ const skipped = [];
32528
+ let totalBytes = 0;
32529
+ for (const entry of ordered) {
32530
+ if (entry.size !== void 0 && entry.size > 262144) {
32531
+ skipped.push({
32532
+ path: entry.path,
32533
+ reason: "too-large"
32534
+ });
32535
+ continue;
32536
+ }
32537
+ if (paths.length >= 40) {
32538
+ skipped.push({
32539
+ path: entry.path,
32540
+ reason: "too-many-files"
32541
+ });
32542
+ continue;
32543
+ }
32544
+ const size = entry.size ?? 0;
32545
+ if (totalBytes + size > 1048576) {
32546
+ skipped.push({
32547
+ path: entry.path,
32548
+ reason: "over-total-size"
32549
+ });
32550
+ continue;
32551
+ }
32552
+ totalBytes += size;
32553
+ paths.push(entry.path);
32554
+ }
32555
+ return {
32556
+ paths,
32557
+ skipped
32558
+ };
32559
+ }
32560
+ /**
32561
+ * The asset-relative path of a repository file, for writing on disk.
32562
+ *
32563
+ * A skill asset's files are named relative to its own directory, so the
32564
+ * repository prefix comes off here rather than at the call site — the sync's
32565
+ * file shape and the registry's are the same shape, and only this line knows
32566
+ * why they differ.
32567
+ */
32568
+ function toAssetFilePath(repositoryPath, root) {
32569
+ return root === "" ? repositoryPath : repositoryPath.slice(root.length + 1);
32570
+ }
32571
+ //#endregion
32572
+ //#region src/skills/SkillRegistry.ts
32573
+ const REGISTRY_SEARCH_URL = "https://www.skills.sh/api/search";
32574
+ const GITHUB_API_URL = "https://api.github.com";
32575
+ const GITHUB_RAW_URL = "https://raw.githubusercontent.com";
32576
+ const REQUEST_TIMEOUT_MS = 15e3;
32577
+ /** More than a person reads, few enough that the panel is a list and not a feed. */
32578
+ const MAX_SEARCH_RESULTS = 25;
32579
+ /**
32580
+ * The catalogue's search response, decoded loosely on purpose.
32581
+ *
32582
+ * Only the four fields we display are required. This is an undocumented public
32583
+ * endpoint on someone else's service; a field appearing or disappearing beside
32584
+ * these should not turn search into an error.
32585
+ */
32586
+ const SearchResponse = Schema$1.Struct({ skills: Schema$1.Array(Schema$1.Struct({
32587
+ id: Schema$1.String,
32588
+ name: Schema$1.String,
32589
+ source: Schema$1.String,
32590
+ installs: Schema$1.optional(Schema$1.Number)
32591
+ })) });
32592
+ const decodeSearchResponse = Schema$1.decodeUnknownEffect(SearchResponse);
32593
+ const TreeResponse = Schema$1.Struct({
32594
+ tree: Schema$1.Array(Schema$1.Struct({
32595
+ path: Schema$1.String,
32596
+ type: Schema$1.String,
32597
+ size: Schema$1.optional(Schema$1.Number)
32598
+ })),
32599
+ truncated: Schema$1.optional(Schema$1.Boolean)
32600
+ });
32601
+ const decodeTreeResponse = Schema$1.decodeUnknownEffect(TreeResponse);
32602
+ var SkillRegistry = class extends Context.Service()("@p4code/cli/skills/SkillRegistry") {};
32603
+ const emptyFetch = (id, unavailable) => ({
32604
+ found: false,
32605
+ id,
32606
+ name: "",
32607
+ source: "",
32608
+ sourceUrl: "",
32609
+ files: [],
32610
+ skipped: [],
32611
+ unavailable
32612
+ });
32613
+ const make$36 = Effect.gen(function* () {
32614
+ const http = yield* HttpClient.HttpClient;
32615
+ const request = Effect.fn("SkillRegistry.request")(function* (url) {
32616
+ return yield* http.execute(HttpClientRequest.get(url).pipe(HttpClientRequest.setHeader("accept", "application/json"), HttpClientRequest.setHeader("user-agent", "p4code"))).pipe(Effect.timeout(REQUEST_TIMEOUT_MS));
32617
+ });
32618
+ const search = (query) => Effect.gen(function* () {
32619
+ const response = yield* request(`${REGISTRY_SEARCH_URL}?q=${encodeURIComponent(query)}`).pipe(Effect.orElseSucceed(() => null));
32620
+ if (response === null) return {
32621
+ results: [],
32622
+ unavailable: "The skill catalogue could not be reached."
32623
+ };
32624
+ if (response.status !== 200) return {
32625
+ results: [],
32626
+ unavailable: `The skill catalogue answered ${response.status}.`
32627
+ };
32628
+ const body = yield* response.json.pipe(Effect.flatMap(decodeSearchResponse), Effect.orElseSucceed(() => null));
32629
+ if (body === null) return {
32630
+ results: [],
32631
+ unavailable: "The skill catalogue answered something unreadable."
32632
+ };
32633
+ return {
32634
+ results: body.skills.slice(0, MAX_SEARCH_RESULTS).map((skill) => ({
32635
+ id: skill.id,
32636
+ name: skill.name,
32637
+ source: skill.source,
32638
+ installs: Math.trunc(skill.installs ?? 0)
32639
+ })),
32640
+ unavailable: null
32641
+ };
32642
+ });
32643
+ const fetch = (id) => Effect.gen(function* () {
32644
+ const ref = parseRegistrySkillId(id);
32645
+ if (ref === null) return emptyFetch(id, "Expected owner/repo/skill-name.");
32646
+ const repository = `${ref.owner}/${ref.repo}`;
32647
+ const treeResponse = yield* request(`${GITHUB_API_URL}/repos/${repository}/git/trees/HEAD?recursive=1`).pipe(Effect.orElseSucceed(() => null));
32648
+ if (treeResponse === null) return emptyFetch(id, `${repository} could not be reached.`);
32649
+ if (treeResponse.status === 403 || treeResponse.status === 429) return emptyFetch(id, "GitHub is rate limiting this machine. Try again later.");
32650
+ if (treeResponse.status !== 200) return emptyFetch(id, `GitHub answered ${treeResponse.status} for ${repository}.`);
32651
+ const tree = yield* treeResponse.json.pipe(Effect.flatMap(decodeTreeResponse), Effect.orElseSucceed(() => null));
32652
+ if (tree === null) return emptyFetch(id, `GitHub answered something unreadable for ${repository}.`);
32653
+ const entries = tree.tree;
32654
+ const root = chooseSkillRoot(entries, ref.skillId);
32655
+ if (root === null) return emptyFetch(id, tree.truncated === true ? `${repository} is too large for GitHub to list in one response, and ${ref.skillId} was not in the part it returned.` : `${repository} has no ${ref.skillId}/SKILL.md.`);
32656
+ const selection = selectSkillFiles(entries, root);
32657
+ const files = [];
32658
+ for (const path of selection.paths) {
32659
+ const fileResponse = yield* request(`${GITHUB_RAW_URL}/${repository}/HEAD/${path.split("/").map(encodeURIComponent).join("/")}`).pipe(Effect.orElseSucceed(() => null));
32660
+ if (fileResponse === null || fileResponse.status !== 200) return emptyFetch(id, `${path} could not be downloaded.`);
32661
+ const content = yield* fileResponse.text.pipe(Effect.orElseSucceed(() => null));
32662
+ if (content === null) return emptyFetch(id, `${path} is not text, so this skill cannot be installed here.`);
32663
+ files.push({
32664
+ path: toAssetFilePath(path, root),
32665
+ content
32666
+ });
32667
+ }
32668
+ return {
32669
+ found: true,
32670
+ id,
32671
+ name: root === "" ? ref.repo : root.split("/").pop() ?? ref.skillId,
32672
+ source: repository,
32673
+ sourceUrl: root === "" ? `https://github.com/${repository}` : `https://github.com/${repository}/tree/HEAD/${root}`,
32674
+ files,
32675
+ skipped: selection.skipped,
32676
+ unavailable: null
32677
+ };
32678
+ });
32679
+ return {
32680
+ search,
32681
+ fetch
32682
+ };
32683
+ });
32684
+ const layer$31 = Layer.effect(SkillRegistry, make$36);
32185
32685
  //#endregion
32186
32686
  //#region ../../packages/shared/src/KeyedCoalescingWorker.ts
32187
32687
  const makeKeyedCoalescingWorker = (options) => Effect.gen(function* () {
@@ -32396,7 +32896,7 @@ const COMMON_DEV_PORTS = Object.freeze([
32396
32896
  8888,
32397
32897
  9e3
32398
32898
  ]);
32399
- const POLL_INTERVAL = Duration.seconds(3);
32899
+ const POLL_INTERVAL$1 = Duration.seconds(3);
32400
32900
  const LSOF_TIMEOUT_MS = 5e3;
32401
32901
  const WINDOWS_LISTENER_TIMEOUT_MS = 5e3;
32402
32902
  const terminalOwnerKey = (owner) => `${owner.threadId}\u0000${owner.terminalId}`;
@@ -32571,7 +33071,7 @@ const make$35 = Effect.gen(function* PortDiscoveryMake() {
32571
33071
  lastSnapshot: next
32572
33072
  }])) yield* broadcast(next);
32573
33073
  }, Effect.catchCause((cause) => Effect.logWarning("preview port scan failed", Cause.pretty(cause))));
32574
- yield* Effect.forkScoped(pollTick().pipe(Effect.repeat(Schedule.spaced(POLL_INTERVAL))));
33074
+ yield* Effect.forkScoped(pollTick().pipe(Effect.repeat(Schedule.spaced(POLL_INTERVAL$1))));
32575
33075
  const acquireRetention = Effect.fn("PortDiscovery.retain")(function* () {
32576
33076
  if (yield* Ref.modify(stateRef, (state) => [state.retainCount === 0, {
32577
33077
  ...state,
@@ -34271,7 +34771,7 @@ const makeWithOptions$1 = Effect.fn("TerminalManager.makeWithOptions")(function*
34271
34771
  subscribeMetadata
34272
34772
  });
34273
34773
  });
34274
- const layer$29 = Layer.effect(TerminalManager, make$34()).pipe(Layer.provide(layer$52));
34774
+ const layer$29 = Layer.effect(TerminalManager, make$34()).pipe(Layer.provide(layer$53));
34275
34775
  //#endregion
34276
34776
  //#region src/mcp/McpInvocationContext.ts
34277
34777
  var McpInvocationContext = class extends Context.Service()("@p4code/cli/mcp/McpInvocationContext") {};
@@ -41454,6 +41954,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
41454
41954
  const hubLink = yield* HubLink;
41455
41955
  const assetSync = yield* AssetSync;
41456
41956
  const mcpRegistry = yield* McpRegistry;
41957
+ const skillRegistry = yield* SkillRegistry;
41457
41958
  const startup = yield* ServerRuntimeStartup;
41458
41959
  const workspaceEntries = yield* WorkspaceEntries;
41459
41960
  const workspaceFileSystem = yield* WorkspaceFileSystem;
@@ -42038,6 +42539,8 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
42038
42539
  status: yield* assetSync.status
42039
42540
  };
42040
42541
  }), { "rpc.aggregate": "skills" }),
42542
+ [WS_METHODS.skillRegistrySearch]: ({ query }) => observeRpcEffect$1(WS_METHODS.skillRegistrySearch, skillRegistry.search(query), { "rpc.aggregate": "skills" }),
42543
+ [WS_METHODS.skillRegistryFetch]: ({ id }) => observeRpcEffect$1(WS_METHODS.skillRegistryFetch, skillRegistry.fetch(id), { "rpc.aggregate": "skills" }),
42041
42544
  [WS_METHODS.mcpList]: (_input) => observeRpcEffect$1(WS_METHODS.mcpList, mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))), { "rpc.aggregate": "mcp" }),
42042
42545
  [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" }),
42043
42546
  [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" }),
@@ -42219,7 +42722,7 @@ const websocketRpcRouteLayer = Layer.unwrap(Effect.gen(function* () {
42219
42722
  const serverAuth = yield* EnvironmentAuth;
42220
42723
  const sessions = yield* SessionStore;
42221
42724
  const session = yield* serverAuth.authenticateWebSocketUpgrade(request).pipe(Effect.catchIf(isServerAuthCredentialError, (error) => failEnvironmentAuthInvalid(serverAuthCredentialReason(error))), Effect.catchIf(isServerAuthInternalError, (error) => failEnvironmentInternal("internal_error", error)));
42222
- const rpcWebSocketHttpEffect = yield* RpcServer.toHttpEffectWebsocket(WsRpcGroup, { disableTracing: true }).pipe(Effect.provide(makeWsRpcLayer(session, previewAutomationBroker).pipe(Layer.provideMerge(RpcSerialization.layerJson), Layer.provide(layer$32), Layer.provide(Layer.succeed(ServerSelfUpdate, serverSelfUpdate)), Layer.provide(Layer.succeed(TaskRepository, taskRepository)), Layer.provide(Layer.succeed(ProjectionProjectRepository, projectionProjects)), Layer.provide(layer$5.pipe(Layer.provide(layer$14.pipe(Layer.provide(Layer.mergeAll(layer$22, layer$20, layer$18, layer$16)), Layer.provideMerge(layer$37), Layer.provide(layer$35.pipe(Layer.provide(layer$36))))), Layer.provide(layer$38))))));
42725
+ const rpcWebSocketHttpEffect = yield* RpcServer.toHttpEffectWebsocket(WsRpcGroup, { disableTracing: true }).pipe(Effect.provide(makeWsRpcLayer(session, previewAutomationBroker).pipe(Layer.provideMerge(RpcSerialization.layerJson), Layer.provide(layer$33), Layer.provide(Layer.succeed(ServerSelfUpdate, serverSelfUpdate)), Layer.provide(Layer.succeed(TaskRepository, taskRepository)), Layer.provide(Layer.succeed(ProjectionProjectRepository, projectionProjects)), Layer.provide(layer$5.pipe(Layer.provide(layer$14.pipe(Layer.provide(Layer.mergeAll(layer$22, layer$20, layer$18, layer$16)), Layer.provideMerge(layer$38), Layer.provide(layer$36.pipe(Layer.provide(layer$37))))), Layer.provide(layer$39))))));
42223
42726
  return yield* Effect.acquireUseRelease(sessions.markConnected(session.sessionId), () => rpcWebSocketHttpEffect, () => sessions.markDisconnected(session.sessionId));
42224
42727
  }).pipe(Effect.catchTags({
42225
42728
  EnvironmentAuthInvalidError: HttpServerRespondable.toResponse,
@@ -42227,6 +42730,281 @@ const websocketRpcRouteLayer = Layer.unwrap(Effect.gen(function* () {
42227
42730
  })));
42228
42731
  }));
42229
42732
  //#endregion
42733
+ //#region src/persistence/Layers/RemoteTasks.ts
42734
+ /**
42735
+ * The board, kept on the hub instead of in this machine's database.
42736
+ *
42737
+ * A drop-in `TaskRepository`: same interface, same events, so the MCP toolkit,
42738
+ * the websocket RPCs and the board itself are unchanged and do not know which
42739
+ * one they are talking to. That was the point of making it an interface.
42740
+ *
42741
+ * **An unreachable hub fails loudly, by decision.** There is no local fallback
42742
+ * and no write queue. A server that answered from a local copy while the hub
42743
+ * was down would recreate exactly the divergence the hub exists to remove —
42744
+ * two Macs with two boards, silently — and the failure would be invisible until
42745
+ * someone noticed a task missing on the other machine. So a hub that cannot be
42746
+ * reached means the board says so and nothing is written. The cost is real and
42747
+ * is the point: no board while the hub is down.
42748
+ *
42749
+ * **Changes are polled, because the hub has no push.** The interface promises
42750
+ * a change stream, and the honest implementation of that against a plain HTTP
42751
+ * API is a poll with a diff. A write made through *this* server publishes
42752
+ * immediately, so the local board is live; the poll is what carries the other
42753
+ * machine's writes, at up to `POLL_INTERVAL` of lag.
42754
+ *
42755
+ * @module persistence/Layers/RemoteTasks
42756
+ */
42757
+ const HUB_REQUEST_TIMEOUT_MS = 15e3;
42758
+ /**
42759
+ * How stale another machine's write may look here.
42760
+ *
42761
+ * Short enough that a board left open follows along, long enough that two
42762
+ * servers idling all day are not a steady stream of requests at a hosted
42763
+ * service. Only changes made elsewhere wait for it.
42764
+ */
42765
+ const POLL_INTERVAL = Duration.seconds(10);
42766
+ const TaskListPage = Schema$1.Struct({ tasks: Schema$1.Array(Task) });
42767
+ const ConflictBody = Schema$1.Struct({ current: Task });
42768
+ const decodeTaskListPage = Schema$1.decodeUnknownEffect(TaskListPage);
42769
+ const decodeTask = Schema$1.decodeUnknownEffect(Task);
42770
+ const decodeConflictBody = Schema$1.decodeUnknownEffect(ConflictBody);
42771
+ /**
42772
+ * Every failure here is reported as the interface's own error type.
42773
+ *
42774
+ * `PersistenceSqlError` names a store that would not answer, which is exactly
42775
+ * what this is from a caller's point of view — the detail says the store is the
42776
+ * hub. Inventing a second error type would mean touching every call site to
42777
+ * handle a case they already handle.
42778
+ */
42779
+ const hubUnavailable = (operation, detail) => new PersistenceSqlError({
42780
+ operation: `RemoteTaskRepository.${operation}`,
42781
+ detail: `The hub board is unavailable: ${detail}`,
42782
+ cause: null
42783
+ });
42784
+ /**
42785
+ * @param isActive Whether this server is currently reading its board from the
42786
+ * hub. The poll asks before every pass rather than being started once: a
42787
+ * machine with the board set to `local` must not be sending a request to a
42788
+ * hosted service every ten seconds for a board nobody is reading, and the
42789
+ * setting can change while the server runs.
42790
+ */
42791
+ const makeRemoteTaskRepository = Effect.fn("makeRemoteTaskRepository")(function* (isActive) {
42792
+ const http = yield* HttpClient.HttpClient;
42793
+ const link = yield* HubLink;
42794
+ const changes = yield* PubSub.unbounded();
42795
+ const publish = (event) => PubSub.publish(changes, event).pipe(Effect.asVoid);
42796
+ /** The board as of the last poll, for diffing the next one against. */
42797
+ const lastSeen = yield* Ref.make(null);
42798
+ const requireSettings = (operation) => Effect.gen(function* () {
42799
+ const state = yield* link.current;
42800
+ if (Option.isNone(state.settings)) return yield* hubUnavailable(operation, "no hub is configured on this server");
42801
+ return state.settings.value;
42802
+ });
42803
+ const send = (operation, settings, request) => http.execute(request.pipe(HttpClientRequest.setHeader("authorization", `Bearer ${settings.token}`), HttpClientRequest.setHeader("accept", "application/json"))).pipe(Effect.timeout(HUB_REQUEST_TIMEOUT_MS), Effect.mapError((cause) => hubUnavailable(operation, `${cause._tag ?? "request failed"}`)));
42804
+ const list = (filter) => Effect.gen(function* () {
42805
+ const settings = yield* requireSettings("list");
42806
+ const query = new URLSearchParams();
42807
+ for (const key of [
42808
+ "projectId",
42809
+ "repositoryKey",
42810
+ "threadId",
42811
+ "status",
42812
+ "assignee"
42813
+ ]) {
42814
+ const value = filter[key];
42815
+ if (value !== void 0) query.set(key, value);
42816
+ }
42817
+ const suffix = query.size === 0 ? "" : `?${query.toString()}`;
42818
+ const response = yield* send("list", settings, HttpClientRequest.get(`${settings.baseUrl}/tasks${suffix}`));
42819
+ if (response.status !== 200) return yield* hubUnavailable("list", `status ${response.status}`);
42820
+ return (yield* response.json.pipe(Effect.flatMap(decodeTaskListPage), Effect.mapError(() => hubUnavailable("list", "the response did not match the contract")))).tasks;
42821
+ });
42822
+ const getById = ({ taskId }) => Effect.gen(function* () {
42823
+ const settings = yield* requireSettings("getById");
42824
+ const response = yield* send("getById", settings, HttpClientRequest.get(`${settings.baseUrl}/tasks/${encodeURIComponent(taskId)}`));
42825
+ if (response.status === 404) return Option.none();
42826
+ if (response.status !== 200) return yield* hubUnavailable("getById", `status ${response.status}`);
42827
+ return Option.some(yield* response.json.pipe(Effect.flatMap(decodeTask), Effect.mapError(() => hubUnavailable("getById", "the response did not match the contract"))));
42828
+ });
42829
+ /**
42830
+ * Upsert is a create here, and that is a real difference from the local
42831
+ * store.
42832
+ *
42833
+ * The hub mints its own ids and timestamps, so a row written through this
42834
+ * comes back with the hub's version of both. The caller's `taskId` is not
42835
+ * carried: honouring it would need a hub route that takes one, and inventing
42836
+ * that quietly would let two servers mint colliding ids.
42837
+ */
42838
+ const upsert = (row) => Effect.gen(function* () {
42839
+ const settings = yield* requireSettings("upsert");
42840
+ const response = yield* send("upsert", settings, HttpClientRequest.bodyJsonUnsafe(HttpClientRequest.post(`${settings.baseUrl}/tasks`), {
42841
+ ...row.projectId === null ? {} : { projectId: row.projectId },
42842
+ ...row.repositoryKey === null ? {} : { repositoryKey: row.repositoryKey },
42843
+ ...row.threadId === null ? {} : { threadId: row.threadId },
42844
+ title: row.title,
42845
+ body: row.body,
42846
+ status: row.status,
42847
+ priority: row.priority,
42848
+ ...row.assignee === null ? {} : { assignee: row.assignee },
42849
+ labels: row.labels
42850
+ }));
42851
+ if (response.status !== 201 && response.status !== 200) return yield* hubUnavailable("upsert", `status ${response.status}`);
42852
+ const created = yield* response.json.pipe(Effect.flatMap(decodeTask), Effect.mapError(() => hubUnavailable("upsert", "the response did not match the contract")));
42853
+ yield* publish({
42854
+ type: "upserted",
42855
+ task: created
42856
+ });
42857
+ });
42858
+ const patch = (input) => Effect.gen(function* () {
42859
+ const settings = yield* requireSettings("patch");
42860
+ const { taskId, ...fields } = input;
42861
+ const response = yield* send("patch", settings, HttpClientRequest.bodyJsonUnsafe(HttpClientRequest.patch(`${settings.baseUrl}/tasks/${encodeURIComponent(taskId)}`), fields));
42862
+ if (response.status === 404) return Option.none();
42863
+ if (response.status !== 200) return yield* hubUnavailable("patch", `status ${response.status}`);
42864
+ const updated = yield* response.json.pipe(Effect.flatMap(decodeTask), Effect.mapError(() => hubUnavailable("patch", "the response did not match the contract")));
42865
+ yield* publish({
42866
+ type: "upserted",
42867
+ task: updated
42868
+ });
42869
+ return Option.some(updated);
42870
+ });
42871
+ const patchIfStatus = (input) => Effect.gen(function* () {
42872
+ const settings = yield* requireSettings("patchIfStatus");
42873
+ const { taskId, ...fields } = input.patch;
42874
+ const response = yield* send("patchIfStatus", settings, HttpClientRequest.bodyJsonUnsafe(HttpClientRequest.patch(`${settings.baseUrl}/tasks/${encodeURIComponent(taskId)}`), {
42875
+ ...fields,
42876
+ expectedStatus: input.expectedStatus
42877
+ }));
42878
+ if (response.status === 404) return { outcome: "missing" };
42879
+ if (response.status === 409) return {
42880
+ outcome: "conflict",
42881
+ current: (yield* response.json.pipe(Effect.flatMap(decodeConflictBody), Effect.mapError(() => hubUnavailable("patchIfStatus", "the conflict response did not match the contract")))).current
42882
+ };
42883
+ if (response.status !== 200) return yield* hubUnavailable("patchIfStatus", `status ${response.status}`);
42884
+ const updated = yield* response.json.pipe(Effect.flatMap(decodeTask), Effect.mapError(() => hubUnavailable("patchIfStatus", "the response did not match the contract")));
42885
+ yield* publish({
42886
+ type: "upserted",
42887
+ task: updated
42888
+ });
42889
+ return {
42890
+ outcome: "updated",
42891
+ task: updated
42892
+ };
42893
+ });
42894
+ const deleteById = ({ taskId }) => Effect.gen(function* () {
42895
+ const settings = yield* requireSettings("deleteById");
42896
+ const response = yield* send("deleteById", settings, HttpClientRequest.delete(`${settings.baseUrl}/tasks/${encodeURIComponent(taskId)}`));
42897
+ if (response.status !== 200 && response.status !== 204 && response.status !== 404) return yield* hubUnavailable("deleteById", `status ${response.status}`);
42898
+ yield* publish({
42899
+ type: "deleted",
42900
+ taskId
42901
+ });
42902
+ });
42903
+ /**
42904
+ * One poll: read the board, publish what differs from last time.
42905
+ *
42906
+ * Compared on `updatedAt` rather than deep equality, because that is the
42907
+ * field every hub write moves and it makes the diff O(n) with no schema
42908
+ * knowledge. A failed poll publishes nothing and leaves the last snapshot in
42909
+ * place — a hub blip should not empty every open board.
42910
+ */
42911
+ const pollOnce = Effect.gen(function* () {
42912
+ if (!(yield* isActive)) return;
42913
+ const current = yield* list({});
42914
+ const previous = yield* Ref.getAndSet(lastSeen, current);
42915
+ if (previous === null) return;
42916
+ const previousById = new Map(previous.map((task) => [task.taskId, task]));
42917
+ for (const task of current) {
42918
+ const before = previousById.get(task.taskId);
42919
+ if (before === void 0 || before.updatedAt !== task.updatedAt) yield* publish({
42920
+ type: "upserted",
42921
+ task
42922
+ });
42923
+ previousById.delete(task.taskId);
42924
+ }
42925
+ for (const taskId of previousById.keys()) yield* publish({
42926
+ type: "deleted",
42927
+ taskId
42928
+ });
42929
+ }).pipe(Effect.ignoreCause({ log: true }));
42930
+ yield* Effect.forever(pollOnce.pipe(Effect.andThen(Effect.sleep(POLL_INTERVAL)))).pipe(Effect.forkScoped);
42931
+ return {
42932
+ upsert,
42933
+ patch,
42934
+ patchIfStatus,
42935
+ getById,
42936
+ list,
42937
+ deleteById,
42938
+ streamChanges: Stream.fromPubSub(changes),
42939
+ streamWithSnapshot: Stream.unwrap(Effect.gen(function* () {
42940
+ const subscription = yield* PubSub.subscribe(changes);
42941
+ const snapshot = yield* list({});
42942
+ yield* Ref.set(lastSeen, snapshot);
42943
+ return Stream.concat(Stream.succeed({
42944
+ type: "snapshot",
42945
+ tasks: snapshot
42946
+ }), Stream.fromSubscription(subscription));
42947
+ }))
42948
+ };
42949
+ });
42950
+ Layer.effect(TaskRepository, makeRemoteTaskRepository(Effect.succeed(true)));
42951
+ //#endregion
42952
+ //#region src/persistence/Layers/TaskBoardSource.ts
42953
+ /**
42954
+ * Which board a call goes to: this machine's database, or the hub's.
42955
+ *
42956
+ * Both repositories are built, and every call reads the setting and delegates.
42957
+ * That is deliberate rather than picking one at startup: `taskBoardSource` is
42958
+ * an ordinary setting a person changes in a panel, and a setting that only
42959
+ * takes effect after a restart is the same hazard the hub link already
42960
+ * documents — you change it, nothing happens, and there is nothing on screen
42961
+ * saying why.
42962
+ *
42963
+ * **Subscriptions pick their source when they subscribe.** A stream cannot
42964
+ * change its mind mid-flight without inventing a "your board moved" event that
42965
+ * nothing knows how to render, so an open board keeps reading the source it
42966
+ * opened against and picks up the change when it reconnects. Switching is rare;
42967
+ * a wrong row on screen is not worth a new event type.
42968
+ *
42969
+ * @module persistence/Layers/TaskBoardSource
42970
+ */
42971
+ const makeRoutedTaskRepository = Effect.gen(function* () {
42972
+ const local = yield* makeTaskRepository;
42973
+ const usingHub = (yield* ServerSettingsService).getSettings.pipe(Effect.map((current) => current.taskBoardSource === "hub"), Effect.orElseSucceed(() => false));
42974
+ const remote = yield* makeRemoteTaskRepository(usingHub);
42975
+ /**
42976
+ * `local` on a settings read failure, and that direction is chosen.
42977
+ *
42978
+ * The alternative is refusing every board call because a settings file could
42979
+ * not be read, which turns one broken file into a dead board. Falling back to
42980
+ * the machine's own database is the answer that still works and cannot lose a
42981
+ * hub write, because a write that never reached the hub was never accepted.
42982
+ */
42983
+ const pick = usingHub.pipe(Effect.map((hub) => hub ? remote : local));
42984
+ return {
42985
+ upsert: (row) => pick.pipe(Effect.flatMap((repository) => repository.upsert(row))),
42986
+ patch: (input, updatedAt) => pick.pipe(Effect.flatMap((repository) => repository.patch(input, updatedAt))),
42987
+ patchIfStatus: (input, updatedAt) => pick.pipe(Effect.flatMap((repository) => repository.patchIfStatus(input, updatedAt))),
42988
+ getById: (input) => pick.pipe(Effect.flatMap((repository) => repository.getById(input))),
42989
+ list: (filter) => pick.pipe(Effect.flatMap((repository) => repository.list(filter))),
42990
+ deleteById: (input) => pick.pipe(Effect.flatMap((repository) => repository.deleteById(input))),
42991
+ get streamChanges() {
42992
+ return Stream.unwrap(pick.pipe(Effect.map((repository) => repository.streamChanges)));
42993
+ },
42994
+ get streamWithSnapshot() {
42995
+ return Stream.unwrap(pick.pipe(Effect.map((repository) => repository.streamWithSnapshot)));
42996
+ }
42997
+ };
42998
+ });
42999
+ /**
43000
+ * The board, wherever it lives.
43001
+ *
43002
+ * Replaces `TaskRepositoryLive` at the one place the route tree provides it, so
43003
+ * the MCP toolkit and the websocket handlers keep sharing a single instance —
43004
+ * which is what makes a task an agent files appear on an open board.
43005
+ */
43006
+ const RoutedTaskRepositoryLive = Layer.effect(TaskRepository, makeRoutedTaskRepository);
43007
+ //#endregion
42230
43008
  //#region src/persistence/ProviderSessionRuntime.ts
42231
43009
  /**
42232
43010
  * ProviderSessionRuntimeRepository - Repository interface for provider runtime sessions.
@@ -44246,7 +45024,7 @@ const makeOpenCodeRuntime = Effect.gen(function* () {
44246
45024
  };
44247
45025
  });
44248
45026
  var OpenCodeRuntime = class extends Context.Service()("@p4code/cli/provider/opencodeRuntime") {};
44249
- const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$68));
45027
+ const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$69));
44250
45028
  //#endregion
44251
45029
  //#region src/textGeneration/TextGenerationUtils.ts
44252
45030
  const isTextGenerationError$2 = Schema$1.is(TextGenerationError);
@@ -45218,7 +45996,7 @@ const runClaudeCommand = Effect.fn("runClaudeCommand")(function* (claudeSettings
45218
45996
  });
45219
45997
  return yield* spawnAndCollect(claudeSettings.binaryPath, command);
45220
45998
  });
45221
- const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")(function* (claudeSettings, resolveCapabilities, environment, cwd) {
45999
+ const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")(function* (claudeSettings, resolveCapabilities, environment, cwd, disabledSkills) {
45222
46000
  const resolvedEnvironment = environment ?? process.env;
45223
46001
  const checkedAt = DateTime.formatIso(yield* DateTime.now);
45224
46002
  const allModels = providerModelsFromSettings(BUILT_IN_MODELS, claudeSettings.customModels, DEFAULT_CLAUDE_MODEL_CAPABILITIES);
@@ -45292,7 +46070,7 @@ const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")(functio
45292
46070
  const models = providerModelsFromSettings(getBuiltInClaudeModelsForVersion(parsedVersion), claudeSettings.customModels, DEFAULT_CLAUDE_MODEL_CAPABILITIES);
45293
46071
  const versionUpgradeMessage = supportsClaudeOpus5(parsedVersion) ? void 0 : supportsClaudeFable5(parsedVersion) ? formatClaudeOpus5UpgradeMessage(parsedVersion) : supportsClaudeOpus48(parsedVersion) ? formatClaudeFable5UpgradeMessage(parsedVersion) : supportsClaudeOpus47(parsedVersion) ? formatClaudeOpus48UpgradeMessage(parsedVersion) : formatClaudeOpus47UpgradeMessage(parsedVersion);
45294
46072
  const capabilities = resolveCapabilities ? yield* resolveCapabilities(claudeSettings).pipe(Effect.orElseSucceed(() => void 0)) : void 0;
45295
- const skills = yield* discoverClaudeSkills(claudeSettings, cwd, resolvedEnvironment);
46073
+ const skills = yield* discoverClaudeSkills(claudeSettings, cwd, resolvedEnvironment, disabledSkills);
45296
46074
  const dedupedSlashCommands = dedupeSlashCommands(capabilities?.slashCommands ?? []);
45297
46075
  if (!capabilities) return buildServerProvider({
45298
46076
  presentation: CLAUDE_PRESENTATION,
@@ -45693,6 +46471,43 @@ function parseCliArgs(args, options) {
45693
46471
  };
45694
46472
  }
45695
46473
  //#endregion
46474
+ //#region src/provider/askUserQuestionAnswers.ts
46475
+ /**
46476
+ * What separates the options of one multi-select answer.
46477
+ *
46478
+ * Comma-and-space rather than a bare comma: the SDK renders this string into a
46479
+ * tool result a model reads, and option labels are prose ("Fail loudly, no
46480
+ * fallback"), so the space is what keeps two joined labels from reading as one.
46481
+ */
46482
+ const MULTI_SELECT_SEPARATOR = ", ";
46483
+ function formatAnswerValue(value) {
46484
+ if (typeof value === "string") {
46485
+ const trimmed = value.trim();
46486
+ return trimmed.length > 0 ? trimmed : null;
46487
+ }
46488
+ if (Array.isArray(value)) {
46489
+ const parts = value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
46490
+ return parts.length > 0 ? parts.join(MULTI_SELECT_SEPARATOR) : null;
46491
+ }
46492
+ return null;
46493
+ }
46494
+ /**
46495
+ * The answers map to hand back to the SDK.
46496
+ *
46497
+ * Questions whose answer is empty, or is neither a string nor a list of them,
46498
+ * are dropped rather than stringified. `String(value)` on an object would put
46499
+ * `[object Object]` in front of the model as though it were the user's choice,
46500
+ * and an absent key is at least a fact the SDK can see.
46501
+ */
46502
+ function formatAskUserQuestionAnswers(answers) {
46503
+ const formatted = {};
46504
+ for (const [question, value] of Object.entries(answers)) {
46505
+ const answer = formatAnswerValue(value);
46506
+ if (answer !== null) formatted[question] = answer;
46507
+ }
46508
+ return formatted;
46509
+ }
46510
+ //#endregion
45696
46511
  //#region src/provider/Layers/ClaudeAdapter.ts
45697
46512
  /**
45698
46513
  * ClaudeAdapterLive - Scoped live implementation for the Claude Agent provider adapter.
@@ -46183,20 +46998,50 @@ function planStepsFromClaudeTasks(tasks) {
46183
46998
  };
46184
46999
  });
46185
47000
  }
47001
+ const TOOL_SUMMARY_MAX_LENGTH = 400;
47002
+ const TOOL_PROMPT_SUMMARY_MAX_LENGTH = 200;
47003
+ const TOOL_PATH_INPUT_KEYS = [
47004
+ "file_path",
47005
+ "filePath",
47006
+ "notebook_path",
47007
+ "path"
47008
+ ];
47009
+ function readTrimmedStringInput(input, keys) {
47010
+ for (const key of keys) {
47011
+ const value = input[key];
47012
+ if (typeof value === "string" && value.trim().length > 0) return value.trim();
47013
+ }
47014
+ }
47015
+ /**
47016
+ * Read/Grep/Glob carry no `command`, so without this they fall through to the
47017
+ * raw-JSON fallback and the work log shows `Read: {"file_path":...,"offset":80}`.
47018
+ */
47019
+ function summarizeFileToolRequest(toolName, input) {
47020
+ const pattern = readTrimmedStringInput(input, ["pattern", "query"]);
47021
+ const path = readTrimmedStringInput(input, TOOL_PATH_INPUT_KEYS);
47022
+ if (pattern) return path ? `${toolName}: ${pattern} in ${path}` : `${toolName}: ${pattern}`;
47023
+ if (!path) return;
47024
+ const offset = input.offset;
47025
+ const limit = input.limit;
47026
+ if (typeof offset === "number" && Number.isFinite(offset)) return `${toolName}: ${path}:${offset}${typeof limit === "number" && Number.isFinite(limit) && limit > 0 ? `-${offset + limit - 1}` : ""}`;
47027
+ return `${toolName}: ${path}`;
47028
+ }
46186
47029
  function summarizeToolRequest(toolName, input) {
46187
47030
  const commandValue = input.command ?? input.cmd;
46188
47031
  const command = typeof commandValue === "string" ? commandValue : void 0;
46189
- if (command && command.trim().length > 0) return `${toolName}: ${command.trim().slice(0, 400)}`;
47032
+ if (command && command.trim().length > 0) return `${toolName}: ${command.trim().slice(0, TOOL_SUMMARY_MAX_LENGTH)}`;
46190
47033
  if (classifyToolItemType(toolName) === "collab_agent_tool_call") {
46191
47034
  const description = typeof input.description === "string" ? input.description.trim() : void 0;
46192
47035
  const prompt = typeof input.prompt === "string" ? input.prompt.trim() : void 0;
46193
47036
  const subagentType = typeof input.subagent_type === "string" ? input.subagent_type.trim() : void 0;
46194
- const label = description || (prompt ? prompt.slice(0, 200) : void 0);
47037
+ const label = description || (prompt ? prompt.slice(0, TOOL_PROMPT_SUMMARY_MAX_LENGTH) : void 0);
46195
47038
  if (label) return subagentType ? `${subagentType}: ${label}` : label;
46196
47039
  }
47040
+ const fileSummary = summarizeFileToolRequest(toolName, input);
47041
+ if (fileSummary) return fileSummary.slice(0, TOOL_SUMMARY_MAX_LENGTH);
46197
47042
  const serialized = encodeJsonStringForDiagnostics$2(input) ?? "[unserializable input]";
46198
- if (serialized.length <= 400) return `${toolName}: ${serialized}`;
46199
- return `${toolName}: ${serialized.slice(0, 397)}...`;
47043
+ if (serialized.length <= TOOL_SUMMARY_MAX_LENGTH) return `${toolName}: ${serialized}`;
47044
+ return `${toolName}: ${serialized.slice(0, TOOL_SUMMARY_MAX_LENGTH - 3)}...`;
46200
47045
  }
46201
47046
  function titleForTool(itemType) {
46202
47047
  switch (itemType) {
@@ -46237,6 +47082,23 @@ function buildUserMessage(input) {
46237
47082
  }
46238
47083
  };
46239
47084
  }
47085
+ function userMessageContentBlocks(message) {
47086
+ const content = message.message.content;
47087
+ if (typeof content === "string") return content.length > 0 ? [{
47088
+ type: "text",
47089
+ text: content
47090
+ }] : [];
47091
+ return Array.isArray(content) ? content : [];
47092
+ }
47093
+ /**
47094
+ * Messages typed while a turn runs are delivered as one prompt, not one turn
47095
+ * each: a user who sends three corrections and then hits Stop means them to be
47096
+ * read together, and replaying them as separate turns made the agent act on the
47097
+ * first before seeing the rest.
47098
+ */
47099
+ function mergeUserMessages(previous, next) {
47100
+ return buildUserMessage({ sdkContent: [...userMessageContentBlocks(previous), ...userMessageContentBlocks(next)] });
47101
+ }
46240
47102
  function buildClaudeImageContentBlock(input) {
46241
47103
  return {
46242
47104
  type: "image",
@@ -46876,6 +47738,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
46876
47738
  title: tool.title,
46877
47739
  ...tool.detail ? { detail: tool.detail } : {},
46878
47740
  data: {
47741
+ toolCallId: tool.itemId,
46879
47742
  toolName: tool.toolName,
46880
47743
  input: tool.input
46881
47744
  }
@@ -46988,18 +47851,19 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
46988
47851
  });
46989
47852
  });
46990
47853
  /**
46991
- * Start the next queued sendTurn, if the session has gone idle.
47854
+ * Start the queued sendTurn, if the session has gone idle.
46992
47855
  *
46993
- * Runs after every turn completion. A message sent during a running turn
46994
- * waits here for the agent loop to end; pressing Stop ends the loop early,
46995
- * and the same drain is what makes Stop mean "and run my message now".
46996
- * One request per drain, so each queued message gets its own turn boundary -
46997
- * the next one starts when this turn's result arrives.
47856
+ * Runs after every turn completion. Messages sent during a running turn wait
47857
+ * here for the agent loop to end; pressing Stop ends the loop early, and the
47858
+ * same drain is what makes Stop mean "and run my messages now". Everything
47859
+ * queued during that turn is already merged into one request by `sendTurn`,
47860
+ * so it starts as a single turn.
46998
47861
  */
46999
47862
  const drainPendingTurns = Effect.fn("drainPendingTurns")(function* (context) {
47000
47863
  if (context.stopped || context.turnState !== void 0) return;
47001
- const pending = context.pendingTurnRequests.shift();
47864
+ const pending = context.pendingTurnRequest;
47002
47865
  if (pending === void 0) return;
47866
+ context.pendingTurnRequest = void 0;
47003
47867
  yield* applyTurnSessionOptions(context, pending.modelSelection, pending.interactionMode).pipe(Effect.catchCause((cause) => Effect.logWarning("claude pending turn session options failed", { cause })));
47004
47868
  yield* beginTurn(context, pending.turnId, pending.modelSelection?.model);
47005
47869
  yield* Queue.offer(context.promptQueue, {
@@ -47086,6 +47950,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
47086
47950
  title: nextTool.title,
47087
47951
  ...nextTool.detail ? { detail: nextTool.detail } : {},
47088
47952
  data: {
47953
+ toolCallId: nextTool.itemId,
47089
47954
  toolName: nextTool.toolName,
47090
47955
  input: nextTool.input
47091
47956
  }
@@ -47155,6 +48020,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
47155
48020
  title: tool.title,
47156
48021
  ...tool.detail ? { detail: tool.detail } : {},
47157
48022
  data: {
48023
+ toolCallId: tool.itemId,
47158
48024
  toolName: tool.toolName,
47159
48025
  input: toolInput
47160
48026
  }
@@ -47192,6 +48058,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
47192
48058
  const itemStatus = toolResult.isError ? "failed" : "completed";
47193
48059
  const toolUseResult = readClaudeToolUseResult(message);
47194
48060
  const toolData = {
48061
+ toolCallId: tool.itemId,
47195
48062
  toolName: tool.toolName,
47196
48063
  input: tool.input,
47197
48064
  result: toolResult.block
@@ -47852,7 +48719,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
47852
48719
  behavior: "allow",
47853
48720
  updatedInput: {
47854
48721
  questions: toolInput.questions,
47855
- answers
48722
+ answers: formatAskUserQuestionAnswers(answers)
47856
48723
  }
47857
48724
  };
47858
48725
  });
@@ -47981,10 +48848,13 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
47981
48848
  auto: "auto",
47982
48849
  "full-access": "bypassPermissions"
47983
48850
  }[input.runtimeMode];
48851
+ const disabledSkills = options?.resolveDisabledSkills === void 0 ? [] : yield* options.resolveDisabledSkills;
48852
+ const skillOverrides = disabledSkills.length === 0 ? void 0 : buildSkillOverrides(disabledSkills, yield* discoverClaudeSkills(claudeSettings, input.cwd, claudeEnvironment).pipe(Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path)));
47984
48853
  const settings = {
47985
48854
  ...typeof thinking === "boolean" ? { alwaysThinkingEnabled: thinking } : {},
47986
48855
  ...fastMode ? { fastMode: true } : {},
47987
- ...ultracode ? { ultracode: true } : {}
48856
+ ...ultracode ? { ultracode: true } : {},
48857
+ ...skillOverrides ? { skillOverrides } : {}
47988
48858
  };
47989
48859
  const mcpSession = readMcpProviderSession(input.threadId);
47990
48860
  const externalMcpServers = options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers;
@@ -48085,7 +48955,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
48085
48955
  inFlightTools,
48086
48956
  claudeTasks,
48087
48957
  turnState: void 0,
48088
- pendingTurnRequests: [],
48958
+ pendingTurnRequest: void 0,
48089
48959
  lastKnownContextWindow: initialContextWindow,
48090
48960
  lastKnownTokenUsage: void 0,
48091
48961
  lastKnownTotalProcessedTokens: void 0,
@@ -48154,13 +49024,14 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
48154
49024
  boundInstanceId
48155
49025
  });
48156
49026
  if (context.turnState) {
48157
- const turnId = TurnId.make(yield* randomUUIDv4);
48158
- context.pendingTurnRequests.push({
49027
+ const pending = context.pendingTurnRequest;
49028
+ const turnId = pending?.turnId ?? TurnId.make(yield* randomUUIDv4);
49029
+ context.pendingTurnRequest = {
48159
49030
  turnId,
48160
- message,
49031
+ message: pending ? mergeUserMessages(pending.message, message) : message,
48161
49032
  modelSelection,
48162
49033
  interactionMode: input.interactionMode
48163
- });
49034
+ };
48164
49035
  return {
48165
49036
  threadId: context.session.threadId,
48166
49037
  turnId,
@@ -48346,7 +49217,8 @@ function mergeProviderInstanceEnvironment(environment, baseEnv = process.env) {
48346
49217
  function makeProviderSnapshotSettings(provider, settings) {
48347
49218
  return {
48348
49219
  provider,
48349
- enableProviderUpdateChecks: settings.enableProviderUpdateChecks
49220
+ enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
49221
+ disabledSkills: settings.disabledSkills
48350
49222
  };
48351
49223
  }
48352
49224
  function haveProviderSnapshotSettingsChanged(previous, next) {
@@ -48438,10 +49310,13 @@ const ClaudeDriver = {
48438
49310
  accentColor,
48439
49311
  continuationGroupKey
48440
49312
  });
49313
+ const mcpRegistry = yield* McpRegistry;
49314
+ const resolveDisabledSkills = serverSettings.getSettings.pipe(Effect.map((settings) => settings.disabledSkills), Effect.orElseSucceed(() => []));
48441
49315
  const adapter = yield* makeClaudeAdapter(effectiveConfig, {
48442
49316
  instanceId,
48443
49317
  environment: processEnv,
48444
- resolveMcpServers: (yield* McpRegistry).resolveForSession,
49318
+ resolveMcpServers: mcpRegistry.resolveForSession,
49319
+ resolveDisabledSkills,
48445
49320
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}
48446
49321
  });
48447
49322
  const textGeneration = yield* makeClaudeTextGeneration(effectiveConfig, processEnv);
@@ -48451,7 +49326,7 @@ const ClaudeDriver = {
48451
49326
  lookup: () => probeClaudeCapabilities(effectiveConfig, processEnv, cwd).pipe(Effect.provideService(Path.Path, path))
48452
49327
  });
48453
49328
  const capabilitiesCacheKey = yield* makeClaudeCapabilitiesCacheKey(effectiveConfig, cwd);
48454
- const checkProvider = checkClaudeProviderStatus(effectiveConfig, () => Cache.get(capabilitiesProbeCache, capabilitiesCacheKey), processEnv, cwd).pipe(Effect.map(stampIdentity), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path));
49329
+ const checkProvider = resolveDisabledSkills.pipe(Effect.flatMap((disabledSkills) => checkClaudeProviderStatus(effectiveConfig, () => Cache.get(capabilitiesProbeCache, capabilitiesCacheKey), processEnv, cwd, disabledSkills)), Effect.map(stampIdentity), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path));
48455
49330
  const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
48456
49331
  const snapshot = yield* makeManagedServerProvider({
48457
49332
  maintenanceCapabilities,
@@ -83338,7 +84213,7 @@ const ObservabilityLive = Layer.unwrap(Effect.gen(function* () {
83338
84213
  sink,
83339
84214
  ...delegate ? { delegate } : {}
83340
84215
  });
83341
- return Layer.mergeAll(Layer.succeed(Tracer.Tracer, tracer), layer$39(sink));
84216
+ return Layer.mergeAll(Layer.succeed(Tracer.Tracer, tracer), layer$40(sink));
83342
84217
  })).pipe(Layer.provide(OtlpExporter.layerFlusher), Layer.provideMerge(otlpSerializationLayer));
83343
84218
  const metricsLayer = config.otlpMetricsUrl === void 0 ? Layer.empty : OtlpMetrics.layer({
83344
84219
  url: config.otlpMetricsUrl,
@@ -83617,25 +84492,25 @@ const ReactorLayerLive = Layer.empty.pipe(Layer.provideMerge(OrchestrationReacto
83617
84492
  const ProviderSessionDirectoryLayerLive = ProviderSessionDirectoryLive.pipe(Layer.provide(layer$3));
83618
84493
  const ProviderLayerLive = ProviderServiceLive.pipe(Layer.provide(ProviderAdapterRegistryLive), Layer.provideMerge(ProviderSessionDirectoryLayerLive));
83619
84494
  const PersistenceLayerLive = Layer.empty.pipe(Layer.provideMerge(layerConfig));
83620
- const VcsDriverRegistryLayerLive = layer$35.pipe(Layer.provide(layer$36));
83621
- const SourceControlProviderRegistryLayerLive = layer$14.pipe(Layer.provide(Layer.mergeAll(layer$22, layer$20, layer$18, layer$16)), Layer.provideMerge(layer$37), Layer.provideMerge(VcsDriverRegistryLayerLive));
83622
- const GitManagerLayerLive = layer$13.pipe(Layer.provideMerge(layer$23), Layer.provideMerge(layer$37), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(layer$31));
83623
- const GitLayerLive = Layer.empty.pipe(Layer.provideMerge(GitManagerLayerLive), Layer.provideMerge(layer$37));
84495
+ const VcsDriverRegistryLayerLive = layer$36.pipe(Layer.provide(layer$37));
84496
+ const SourceControlProviderRegistryLayerLive = layer$14.pipe(Layer.provide(Layer.mergeAll(layer$22, layer$20, layer$18, layer$16)), Layer.provideMerge(layer$38), Layer.provideMerge(VcsDriverRegistryLayerLive));
84497
+ const GitManagerLayerLive = layer$13.pipe(Layer.provideMerge(layer$23), Layer.provideMerge(layer$38), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(layer$32));
84498
+ const GitLayerLive = Layer.empty.pipe(Layer.provideMerge(GitManagerLayerLive), Layer.provideMerge(layer$38));
83624
84499
  const GitWorkflowLayerLive = layer$12.pipe(Layer.provideMerge(VcsDriverRegistryLayerLive), Layer.provideMerge(GitLayerLive));
83625
- const SourceControlRepositoryServiceLayerLive = layer$4.pipe(Layer.provideMerge(layer$37), Layer.provideMerge(SourceControlProviderRegistryLayerLive));
83626
- const ReviewLayerLive = layer$9.pipe(Layer.provideMerge(layer$37), Layer.provideMerge(VcsDriverRegistryLayerLive));
83627
- const VcsLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$36), Layer.provideMerge(VcsDriverRegistryLayerLive), Layer.provideMerge(layer$10.pipe(Layer.provide(VcsDriverRegistryLayerLive))), Layer.provideMerge(GitWorkflowLayerLive), Layer.provideMerge(ReviewLayerLive), Layer.provideMerge(SourceControlRepositoryServiceLayerLive), Layer.provideMerge(layer$11.pipe(Layer.provide(GitWorkflowLayerLive))));
83628
- const CheckpointingLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$33), Layer.provideMerge(layer$34.pipe(Layer.provide(VcsDriverRegistryLayerLive))));
83629
- const PortScannerLayerLive = layer$30.pipe(Layer.provide(layer$52));
84500
+ const SourceControlRepositoryServiceLayerLive = layer$4.pipe(Layer.provideMerge(layer$38), Layer.provideMerge(SourceControlProviderRegistryLayerLive));
84501
+ const ReviewLayerLive = layer$9.pipe(Layer.provideMerge(layer$38), Layer.provideMerge(VcsDriverRegistryLayerLive));
84502
+ const VcsLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$37), Layer.provideMerge(VcsDriverRegistryLayerLive), Layer.provideMerge(layer$10.pipe(Layer.provide(VcsDriverRegistryLayerLive))), Layer.provideMerge(GitWorkflowLayerLive), Layer.provideMerge(ReviewLayerLive), Layer.provideMerge(SourceControlRepositoryServiceLayerLive), Layer.provideMerge(layer$11.pipe(Layer.provide(GitWorkflowLayerLive))));
84503
+ const CheckpointingLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$34), Layer.provideMerge(layer$35.pipe(Layer.provide(VcsDriverRegistryLayerLive))));
84504
+ const PortScannerLayerLive = layer$30.pipe(Layer.provide(layer$53));
83630
84505
  const TerminalLayerLive = layer$29.pipe(Layer.provide(PtyAdapterLive), Layer.provide(PortScannerLayerLive));
83631
84506
  const PreviewLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$27), Layer.provideMerge(PortScannerLayerLive));
83632
- const WorkspaceEntriesLayerLive = layer$25.pipe(Layer.provide(layer$42));
83633
- const WorkspaceFileSystemLayerLive = layer$24.pipe(Layer.provide(layer$42), Layer.provide(WorkspaceEntriesLayerLive));
83634
- const WorkspaceLayerLive = Layer.mergeAll(layer$42, WorkspaceEntriesLayerLive, WorkspaceFileSystemLayerLive);
83635
- const ProjectFaviconResolverLayerLive = layer$40.pipe(Layer.provide(layer$42), Layer.provide(layer$41));
83636
- const AuthLayerLive = layer$60.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$64));
84507
+ const WorkspaceEntriesLayerLive = layer$25.pipe(Layer.provide(layer$43));
84508
+ const WorkspaceFileSystemLayerLive = layer$24.pipe(Layer.provide(layer$43), Layer.provide(WorkspaceEntriesLayerLive));
84509
+ const WorkspaceLayerLive = Layer.mergeAll(layer$43, WorkspaceEntriesLayerLive, WorkspaceFileSystemLayerLive);
84510
+ const ProjectFaviconResolverLayerLive = layer$41.pipe(Layer.provide(layer$43), Layer.provide(layer$42));
84511
+ const AuthLayerLive = layer$61.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$65));
83637
84512
  const ProviderRuntimeLayerLive = ProviderSessionReaperLive.pipe(Layer.provideMerge(ProviderLayerLive), Layer.provideMerge(OrchestrationLayerLive));
83638
- 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$50), Layer.provideMerge(ProviderRegistryLive), Layer.provideMerge(ProviderInstanceRegistryHydrationLive), Layer.provideMerge(ProviderEventLoggersLive), Layer.provideMerge(OpenCodeRuntimeLive), Layer.provideMerge(layer$57.pipe(Layer.provide(layer$64))), Layer.provideMerge(WorkspaceLayerLive), Layer.provideMerge(ProjectFaviconResolverLayerLive), Layer.provideMerge(layer$51), Layer.provideMerge(layer$44), Layer.provideMerge(AuthLayerLive), Layer.provideMerge(layer$56), Layer.provideMerge(layer$64)).pipe(Layer.provideMerge(layer$8), Layer.provideMerge(layer$7), Layer.provideMerge(layer$6), Layer.provideMerge(layer$47), Layer.provideMerge(layer$49), Layer.provideMerge(layer$48), Layer.provide(layer$68));
84513
+ 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$58.pipe(Layer.provide(layer$65))), 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)), Layer.provideMerge(layer$65)).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$69));
83639
84514
  /**
83640
84515
  * Hub asset sync.
83641
84516
  *
@@ -83643,9 +84518,9 @@ const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(Checkpo
83643
84518
  * not-configured shape, and every call reports that rather than failing — so
83644
84519
  * this costs a server with no hub nothing but a layer.
83645
84520
  */
83646
- const AssetSyncLive = layer$53.pipe(Layer.provideMerge(layer$54), Layer.provideMerge(layer$55));
83647
- const RuntimeServicesLive = layer$43.pipe(Layer.provideMerge(AssetSyncLive), Layer.provideMerge(RuntimeDependenciesLive));
83648
- const makeRoutesLayer = Layer.mergeAll(Layer.mergeAll(HttpApiBuilder.layer(EnvironmentHttpApi).pipe(Layer.provide(authHttpApiLayer), Layer.provide(orchestrationHttpApiLayer), Layer.provide(serverEnvironmentHttpApiLayer), Layer.provide(environmentAuthenticatedAuthLayer)), otlpTracesProxyRouteLayer, assetRouteLayer, staticAndDevRouteLayer, websocketRpcRouteLayer), layer.pipe(Layer.provide(layer$2))).pipe(Layer.provide(TaskRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(ProjectionProjectRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(layer$28), Layer.provide(layer$45), Layer.provide(browserApiCorsLayer), Layer.provide(httpCompressionLayer));
84521
+ const AssetSyncLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56));
84522
+ const RuntimeServicesLive = layer$44.pipe(Layer.provideMerge(AssetSyncLive), Layer.provideMerge(RuntimeDependenciesLive));
84523
+ const makeRoutesLayer = Layer.mergeAll(Layer.mergeAll(HttpApiBuilder.layer(EnvironmentHttpApi).pipe(Layer.provide(authHttpApiLayer), Layer.provide(orchestrationHttpApiLayer), Layer.provide(serverEnvironmentHttpApiLayer), Layer.provide(environmentAuthenticatedAuthLayer)), otlpTracesProxyRouteLayer, assetRouteLayer, staticAndDevRouteLayer, websocketRpcRouteLayer), layer.pipe(Layer.provide(layer$2))).pipe(Layer.provide(RoutedTaskRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(ProjectionProjectRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(layer$28), Layer.provide(layer$46), Layer.provide(browserApiCorsLayer), Layer.provide(httpCompressionLayer));
83649
84524
  const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
83650
84525
  const config = yield* ServerConfig$1;
83651
84526
  yield* fixPath();
@@ -83688,7 +84563,7 @@ const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
83688
84563
  cause,
83689
84564
  servePort: configured.servePort
83690
84565
  }))) : Effect.void)) : Layer.empty;
83691
- return Layer.mergeAll(HttpRouter.serve(makeRoutesLayer, { disableLogger: !config.logWebSocketEvents }), httpListeningLayer, runtimeStateLayer, tailscaleServeLayer).pipe(Layer.provideMerge(RuntimeServicesLive), Layer.provideMerge(HttpResponseCompressionLive), Layer.provideMerge(HttpServerLive), Layer.provide(ObservabilityLive), Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(layer$38), Layer.provideMerge(PlatformServicesLive));
84566
+ return Layer.mergeAll(HttpRouter.serve(makeRoutesLayer, { disableLogger: !config.logWebSocketEvents }), httpListeningLayer, runtimeStateLayer, tailscaleServeLayer).pipe(Layer.provideMerge(RuntimeServicesLive), Layer.provideMerge(HttpResponseCompressionLive), Layer.provideMerge(HttpServerLive), Layer.provide(ObservabilityLive), Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(layer$39), Layer.provideMerge(PlatformServicesLive));
83692
84567
  }));
83693
84568
  const runServer = Layer.launch(makeServerLayer);
83694
84569
  //#endregion
@@ -83850,11 +84725,11 @@ const reconcileWithNewBinary = Effect.fn("cli.selfUpdate.reconcileWithNewBinary"
83850
84725
  //#endregion
83851
84726
  //#region src/cli/service.ts
83852
84727
  const isBootServiceCommandError = Schema$1.is(BootServiceCommandError);
83853
- const bootServiceLayer = (config) => layer$46({
84728
+ const bootServiceLayer = (config) => layer$47({
83854
84729
  baseDir: config.baseDir,
83855
84730
  logsDir: config.logsDir,
83856
84731
  cliVersion: version
83857
- }).pipe(Layer.provide(layer$52));
84732
+ }).pipe(Layer.provide(layer$53));
83858
84733
  /** Install, update, or repair the service using the CLI version running this command. */
83859
84734
  const reconcileService = Effect.fn("cli.service.reconcile")(function* () {
83860
84735
  const service = yield* BootService;
@@ -83901,7 +84776,7 @@ const runServiceCommand = Effect.fn("cli.service.run")(function* (flags, run, pr
83901
84776
  const baseDirNotice = yield* describeNonDefaultBaseDir(config.baseDir);
83902
84777
  if (baseDirNotice !== null) yield* Console.error(baseDirNotice);
83903
84778
  if (prepare !== void 0) yield* prepare(config);
83904
- return yield* run.pipe(Effect.tapError((error) => isBootServiceCommandError(error) ? BootService.pipe(Effect.flatMap((service) => Console.error(`Details: ${service.logPath}`))) : Effect.void), Effect.provide(Layer.mergeAll(bootServiceLayer(config), layer$52)));
84779
+ return yield* run.pipe(Effect.tapError((error) => isBootServiceCommandError(error) ? BootService.pipe(Effect.flatMap((service) => Console.error(`Details: ${service.logPath}`))) : Effect.void), Effect.provide(Layer.mergeAll(bootServiceLayer(config), layer$53)));
83905
84780
  });
83906
84781
  /**
83907
84782
  * Options the installed unit carries, rather than ones this command consumes.
@@ -84055,7 +84930,7 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
84055
84930
  ]));
84056
84931
  //#endregion
84057
84932
  //#region src/bin.ts
84058
- const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$68, FetchHttpClient.layer);
84933
+ const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$69, FetchHttpClient.layer);
84059
84934
  /**
84060
84935
  * Prints an update reminder before dispatching, at most once a day.
84061
84936
  *