@p4code/cli 0.1.16 → 0.1.18

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 (90) hide show
  1. package/README.md +1 -1
  2. package/dist/bin.mjs +2518 -499
  3. package/dist/client/assets/DiffPanel-CP_cM9m0.js +98 -0
  4. package/dist/client/assets/{FilePreviewPanel-CXPZlxI3.js → FilePreviewPanel-CLho0PPu.js} +5 -5
  5. package/dist/client/assets/PreviewPanel-DvnUpMQv.js +2 -0
  6. package/dist/client/assets/{angular-html-B5E_J1fS.js → angular-html-CEMakyzJ.js} +2 -2
  7. package/dist/client/assets/{angular-ts-COv5JKxn.js → angular-ts-YXZHq2uz.js} +2 -2
  8. package/dist/client/assets/{apl-BQsQyMXO.js → apl-BTa85Bsd.js} +2 -2
  9. package/dist/client/assets/arrow-right-Bi8kADrV.js +2 -0
  10. package/dist/client/assets/{astro-B8L9Cn_4.js → astro-DIbti84c.js} +2 -2
  11. package/dist/client/assets/{blade-B_Che9pT.js → blade-CKAdvdwG.js} +2 -2
  12. package/dist/client/assets/{c-CPSBTKBx.js → c-DW17xzCK.js} +2 -2
  13. package/dist/client/assets/{cobol-BriE1iNK.js → cobol-DXiicIcZ.js} +2 -2
  14. package/dist/client/assets/{coffee-ClgsI2Oz.js → coffee-9Pdmmdn2.js} +2 -2
  15. package/dist/client/assets/{cpp-BoIGp4CN.js → cpp-bm3vFVmW.js} +2 -2
  16. package/dist/client/assets/{crystal-B-s92Xor.js → crystal-DbxZDZf9.js} +2 -2
  17. package/dist/client/assets/{css-lm7yIvqf.js → css-BEBnbxDe.js} +2 -2
  18. package/dist/client/assets/{edge-BdwKb_XJ.js → edge-K97wVEy_.js} +2 -2
  19. package/dist/client/assets/{elixir-Dd3gZy8B.js → elixir-Rc2JDLLD.js} +2 -2
  20. package/dist/client/assets/{elm-BUwJ0Z6D.js → elm-QsA8aREL.js} +2 -2
  21. package/dist/client/assets/{erb-BmkGyaa3.js → erb-CliRJz4v.js} +2 -2
  22. package/dist/client/assets/{fileCommentAnnotations-aElZ1ls9.js → fileCommentAnnotations-DtIPA0Fm.js} +2 -2
  23. package/dist/client/assets/{git-rebase-CgG-fpnH.js → git-rebase-Da_Wuhd_.js} +2 -2
  24. package/dist/client/assets/{glimmer-js-CgCxySf7.js → glimmer-js-XPbTw3tC.js} +2 -2
  25. package/dist/client/assets/{glimmer-ts-D0qJCdA3.js → glimmer-ts-BtK3NOkH.js} +2 -2
  26. package/dist/client/assets/{glsl-D-TJl_NC.js → glsl-DqEtJptk.js} +2 -2
  27. package/dist/client/assets/{graphql-tJKOdjT8.js → graphql-BSRTeXs0.js} +2 -2
  28. package/dist/client/assets/{hack-CNRyS4CV.js → hack-Dw9HaNHZ.js} +2 -2
  29. package/dist/client/assets/{haml-DZHEkAiU.js → haml-BBNabTlb.js} +2 -2
  30. package/dist/client/assets/{handlebars-C2vebdS9.js → handlebars-BgXzhWSj.js} +2 -2
  31. package/dist/client/assets/{html-derivative-C5tQldZt.js → html-derivative-CANLUZ-z.js} +2 -2
  32. package/dist/client/assets/{html-DCuQyWj1.js → html-wBdSHoow.js} +2 -2
  33. package/dist/client/assets/{http-BAgKJQ4_.js → http-BY44QKMy.js} +2 -2
  34. package/dist/client/assets/{hurl-CPO35wiX.js → hurl-EMZQkkjM.js} +2 -2
  35. package/dist/client/assets/index-Dol3ssFp.css +1 -0
  36. package/dist/client/assets/index-kwzTYbVb.js +775 -0
  37. package/dist/client/assets/{java-DdKunJP-.js → java-ByjPbT42.js} +2 -2
  38. package/dist/client/assets/{javascript-BzCImGGh.js → javascript-C9vbUEcm.js} +2 -2
  39. package/dist/client/assets/{jinja-KxDS67Zm.js → jinja-DH-AbsBN.js} +2 -2
  40. package/dist/client/assets/{jison-CB_VQ7nH.js → jison-Bef1Ntr_.js} +2 -2
  41. package/dist/client/assets/{json-DW5yQfU4.js → json-Gk_oM0bP.js} +2 -2
  42. package/dist/client/assets/{jsx-BCRm4K8K.js → jsx-Ds7YHLou.js} +2 -2
  43. package/dist/client/assets/{julia-B7zmtt-j.js → julia-Dm-6xpIK.js} +2 -2
  44. package/dist/client/assets/{just-BPUjF3fe.js → just-BXY93QN4.js} +2 -2
  45. package/dist/client/assets/{latex-DlHsgJiO.js → latex-B3-eYkFA.js} +2 -2
  46. package/dist/client/assets/{liquid-DkAYrmIm.js → liquid-C10OBLnm.js} +2 -2
  47. package/dist/client/assets/{lua-CkWXcEtU.js → lua-BUR8bsxC.js} +2 -2
  48. package/dist/client/assets/{marko-BreU7Tr4.js → marko-COPLM_fz.js} +2 -2
  49. package/dist/client/assets/{mdc-BIy4U_CM.js → mdc-CTAUTBsz.js} +2 -2
  50. package/dist/client/assets/{nginx-CaBRBNvW.js → nginx-D1BLqLRM.js} +2 -2
  51. package/dist/client/assets/{nim-Dh_VcD-W.js → nim-Xs8VbhdY.js} +2 -2
  52. package/dist/client/assets/{perl-DljrVQhk.js → perl-D7-zmFa1.js} +2 -2
  53. package/dist/client/assets/{php-DcpMefw4.js → php-BiTVgoaL.js} +2 -2
  54. package/dist/client/assets/{pug-BquSKFGg.js → pug-DphfHoFa.js} +2 -2
  55. package/dist/client/assets/{qml-DEzduZ1z.js → qml-CYcNnFOd.js} +2 -2
  56. package/dist/client/assets/{r-D0PJ1YHw.js → r-BrJ-p0TS.js} +2 -2
  57. package/dist/client/assets/{razor-C9NzXzG1.js → razor-1gio6m_g.js} +2 -2
  58. package/dist/client/assets/{regexp-Bppxv8Nd.js → regexp-CNiuKup7.js} +2 -2
  59. package/dist/client/assets/{rst-BHL4HPZF.js → rst-BPOsO8_U.js} +2 -2
  60. package/dist/client/assets/{ruby-BgqgMbbJ.js → ruby-CpfKHKDc.js} +2 -2
  61. package/dist/client/assets/{sas-CWVKvcbG.js → sas-CngX1we2.js} +2 -2
  62. package/dist/client/assets/{scss-Cw6AvzKE.js → scss-B2remLQX.js} +2 -2
  63. package/dist/client/assets/{shellscript-BmSXT-3L.js → shellscript-CQmxALRY.js} +2 -2
  64. package/dist/client/assets/{shellsession-CoR9jXze.js → shellsession-BB-5CB_r.js} +2 -2
  65. package/dist/client/assets/{soy-C4LA8zVY.js → soy-kYUnX51I.js} +2 -2
  66. package/dist/client/assets/{sql-ByI0x14l.js → sql-Cq9fRkwr.js} +2 -2
  67. package/dist/client/assets/{stata-fHDl5JMD.js → stata-17nboilR.js} +2 -2
  68. package/dist/client/assets/{surrealql-bNPgbvaA.js → surrealql-D1hrcsSn.js} +2 -2
  69. package/dist/client/assets/{svelte-BvpeBLSH.js → svelte-GmGi3eK8.js} +2 -2
  70. package/dist/client/assets/{templ-uUxwDReQ.js → templ-DySdTLEs.js} +2 -2
  71. package/dist/client/assets/{tex-DvBkmY5z.js → tex-CblcFqPi.js} +2 -2
  72. package/dist/client/assets/textarea-Cf56oU_6.js +46 -0
  73. package/dist/client/assets/{ts-tags-CNdGGSEK.js → ts-tags-BQC5pzJI.js} +2 -2
  74. package/dist/client/assets/{tsx-C-xKLmxT.js → tsx-1bNjXgiV.js} +2 -2
  75. package/dist/client/assets/{twig-BwP3uniF.js → twig-CNwthYXl.js} +2 -2
  76. package/dist/client/assets/{typescript-EVQqiZdz.js → typescript-BTKoaKmx.js} +2 -2
  77. package/dist/client/assets/{vue-CcDCYMax.js → vue-B4XpWxge.js} +2 -2
  78. package/dist/client/assets/{vue-html-D78T-MxH.js → vue-html-CcUSqexV.js} +2 -2
  79. package/dist/client/assets/{vue-vine-CZ6XjTDM.js → vue-vine-JDMd26pY.js} +2 -2
  80. package/dist/client/assets/{xml-Clr4M-ss.js → xml-DRuNSJP8.js} +2 -2
  81. package/dist/client/assets/{xsl-CboPzliu.js → xsl-BIJJg1B0.js} +2 -2
  82. package/dist/client/assets/{yaml-DOfnzofq.js → yaml-BNEnOsJI.js} +2 -2
  83. package/dist/client/index.html +3 -3
  84. package/package.json +1 -1
  85. package/dist/client/assets/DiffPanel-rTTo7hcH.js +0 -98
  86. package/dist/client/assets/PreviewPanel-BFuAVjo6.js +0 -2
  87. package/dist/client/assets/arrow-right-SCFydakV.js +0 -2
  88. package/dist/client/assets/index-DXGA7g9I.js +0 -655
  89. package/dist/client/assets/index-MItVmi4T.css +0 -1
  90. package/dist/client/assets/textarea-CbUaa52I.js +0 -46
package/dist/bin.mjs CHANGED
@@ -233,7 +233,7 @@ const make$75 = () => {
233
233
  const layer$71 = Layer.sync(NetService, make$75);
234
234
  //#endregion
235
235
  //#region package.json
236
- var version = "0.1.16";
236
+ var version = "0.1.18";
237
237
  //#endregion
238
238
  //#region src/config.ts
239
239
  /**
@@ -1509,6 +1509,7 @@ const CODEX_DRIVER_KIND = ProviderDriverKind.make("codex");
1509
1509
  const CLAUDE_DRIVER_KIND = ProviderDriverKind.make("claudeAgent");
1510
1510
  const CURSOR_DRIVER_KIND = ProviderDriverKind.make("cursor");
1511
1511
  const GROK_DRIVER_KIND$1 = ProviderDriverKind.make("grok");
1512
+ const MUSE_DRIVER_KIND = ProviderDriverKind.make("muse");
1512
1513
  const OPENCODE_DRIVER_KIND = ProviderDriverKind.make("opencode");
1513
1514
  const DEFAULT_MODEL = "gpt-5.6-sol";
1514
1515
  /**
@@ -1523,6 +1524,7 @@ const DEFAULT_MODEL_BY_PROVIDER = {
1523
1524
  [CLAUDE_DRIVER_KIND]: "claude-sonnet-5",
1524
1525
  [CURSOR_DRIVER_KIND]: "auto",
1525
1526
  [GROK_DRIVER_KIND$1]: "grok-build",
1527
+ [MUSE_DRIVER_KIND]: "muse-spark-1.2",
1526
1528
  [OPENCODE_DRIVER_KIND]: "openai/gpt-5"
1527
1529
  };
1528
1530
  /** Per-provider text generation model defaults. */
@@ -1530,6 +1532,7 @@ const DEFAULT_TEXT_GENERATION_MODEL_BY_PROVIDER = {
1530
1532
  [CODEX_DRIVER_KIND]: DEFAULT_TEXT_GENERATION_MODEL,
1531
1533
  [CLAUDE_DRIVER_KIND]: "claude-haiku-4-5",
1532
1534
  [CURSOR_DRIVER_KIND]: "composer-2",
1535
+ [MUSE_DRIVER_KIND]: "muse-spark-1.2-contributor",
1533
1536
  [OPENCODE_DRIVER_KIND]: "openai/gpt-5"
1534
1537
  };
1535
1538
  const MODEL_SLUG_ALIASES_BY_PROVIDER = {
@@ -4618,6 +4621,7 @@ const RuntimeEventRawSource = Schema$1.Union([
4618
4621
  Schema$1.Literal("claude.sdk.permission"),
4619
4622
  Schema$1.Literal("codex.sdk.thread-event"),
4620
4623
  Schema$1.Literal("opencode.sdk.event"),
4624
+ Schema$1.Literal("muse.exec.jsonl"),
4621
4625
  Schema$1.Literal("acp.jsonrpc"),
4622
4626
  Schema$1.TemplateLiteral([
4623
4627
  "acp.",
@@ -4769,6 +4773,7 @@ Schema$1.Literals([
4769
4773
  "config.warning",
4770
4774
  "deprecation.notice",
4771
4775
  "files.persisted",
4776
+ "code.published",
4772
4777
  "runtime.warning",
4773
4778
  "runtime.error"
4774
4779
  ]);
@@ -4817,6 +4822,7 @@ const ModelReroutedType = Schema$1.Literal("model.rerouted");
4817
4822
  const ConfigWarningType = Schema$1.Literal("config.warning");
4818
4823
  const DeprecationNoticeType = Schema$1.Literal("deprecation.notice");
4819
4824
  const FilesPersistedType = Schema$1.Literal("files.persisted");
4825
+ const CodePublishedType = Schema$1.Literal("code.published");
4820
4826
  const ToolDeniedType = Schema$1.Literal("tool.denied");
4821
4827
  const RuntimeWarningType = Schema$1.Literal("runtime.warning");
4822
4828
  const RuntimeErrorType = Schema$1.Literal("runtime.error");
@@ -5119,6 +5125,12 @@ const FilesPersistedPayload = Schema$1.Struct({
5119
5125
  error: TrimmedNonEmptyStringSchema$1
5120
5126
  })))
5121
5127
  });
5128
+ const CodePublishedPayload = Schema$1.Struct({
5129
+ hostingProvider: TrimmedNonEmptyStringSchema$1,
5130
+ url: TrimmedNonEmptyStringSchema$1,
5131
+ repo: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
5132
+ identifier: Schema$1.optional(TrimmedNonEmptyStringSchema$1)
5133
+ });
5122
5134
  const ToolDeniedPayload = Schema$1.Struct({
5123
5135
  toolName: TrimmedNonEmptyStringSchema$1,
5124
5136
  toolUseId: Schema$1.optional(TrimmedNonEmptyStringSchema$1),
@@ -5359,6 +5371,11 @@ const ProviderRuntimeFilesPersistedEvent = Schema$1.Struct({
5359
5371
  type: FilesPersistedType,
5360
5372
  payload: FilesPersistedPayload
5361
5373
  });
5374
+ const ProviderRuntimeCodePublishedEvent = Schema$1.Struct({
5375
+ ...ProviderRuntimeEventBase.fields,
5376
+ type: CodePublishedType,
5377
+ payload: CodePublishedPayload
5378
+ });
5362
5379
  const ProviderRuntimeToolDeniedEvent = Schema$1.Struct({
5363
5380
  ...ProviderRuntimeEventBase.fields,
5364
5381
  type: ToolDeniedType,
@@ -5420,6 +5437,7 @@ Schema$1.Union([
5420
5437
  ProviderRuntimeConfigWarningEvent,
5421
5438
  ProviderRuntimeDeprecationNoticeEvent,
5422
5439
  ProviderRuntimeFilesPersistedEvent,
5440
+ ProviderRuntimeCodePublishedEvent,
5423
5441
  ProviderRuntimeToolDeniedEvent,
5424
5442
  ProviderRuntimeWarningEvent,
5425
5443
  ProviderRuntimeErrorEvent
@@ -5712,6 +5730,26 @@ const GrokSettings = makeProviderSettingsSchema({
5712
5730
  })),
5713
5731
  customModels: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([])), Schema$1.annotateKey({ providerSettingsForm: { hidden: true } }))
5714
5732
  }, { order: ["binaryPath"] });
5733
+ const MuseSettings = makeProviderSettingsSchema({
5734
+ enabled: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(false)), Schema$1.annotateKey({ providerSettingsForm: { hidden: true } })),
5735
+ binaryPath: makeBinaryPathSetting("muse").pipe(Schema$1.annotateKey({
5736
+ title: "Binary path",
5737
+ description: "Path to the Muse Code binary.",
5738
+ providerSettingsForm: {
5739
+ placeholder: "muse",
5740
+ clearWhenEmpty: "omit"
5741
+ }
5742
+ })),
5743
+ baseUrl: TrimmedString.pipe(Schema$1.withDecodingDefault(Effect.succeed("")), Schema$1.annotateKey({
5744
+ title: "Base URL",
5745
+ description: "Override the Meta Model API base URL for this instance.",
5746
+ providerSettingsForm: {
5747
+ placeholder: "https://api.meta.ai/v1",
5748
+ clearWhenEmpty: "omit"
5749
+ }
5750
+ })),
5751
+ customModels: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([])), Schema$1.annotateKey({ providerSettingsForm: { hidden: true } }))
5752
+ }, { order: ["binaryPath", "baseUrl"] });
5715
5753
  const OpenCodeSettings = makeProviderSettingsSchema({
5716
5754
  enabled: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true)), Schema$1.annotateKey({ providerSettingsForm: { hidden: true } })),
5717
5755
  binaryPath: makeBinaryPathSetting("opencode").pipe(Schema$1.annotateKey({
@@ -5771,6 +5809,20 @@ const ServerSettings = Schema$1.Struct({
5771
5809
  * back for sessions started by the Claude provider.
5772
5810
  */
5773
5811
  enableToolCallNarration: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true))),
5812
+ /**
5813
+ * Whether the model may spawn subagents without being asked to.
5814
+ *
5815
+ * On by default: a bounded search or review whose result is far smaller than
5816
+ * the reading it takes to produce is exactly the work a subagent is for, and
5817
+ * an agent that has to ask first will simply do it inline instead.
5818
+ *
5819
+ * Stated in the appended prompt whichever way it is set, rather than only
5820
+ * when off. The provider's own preset prompt carries an instruction not to
5821
+ * spawn subagents unless asked, and p4code requests that preset wholesale —
5822
+ * so there is nothing to withhold, and only a later, more specific
5823
+ * instruction can override an earlier general one.
5824
+ */
5825
+ enableUnpromptedSubagents: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true))),
5774
5826
  automaticGitFetchInterval: Schema$1.DurationFromMillis.pipe(Schema$1.withDecodingDefault(Effect.succeed(Duration.toMillis(DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL)))),
5775
5827
  defaultThreadEnvMode: ThreadEnvMode.pipe(Schema$1.withDecodingDefault(Effect.succeed("local"))),
5776
5828
  newWorktreesStartFromOrigin: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true))),
@@ -5822,6 +5874,7 @@ const ServerSettings = Schema$1.Struct({
5822
5874
  claudeAgent: ClaudeSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
5823
5875
  cursor: CursorSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
5824
5876
  grok: GrokSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
5877
+ muse: MuseSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
5825
5878
  opencode: OpenCodeSettings.pipe(Schema$1.withDecodingDefault(Effect.succeed({})))
5826
5879
  }).pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
5827
5880
  providerInstances: Schema$1.Record(ProviderInstanceId, ProviderInstanceConfig).pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
@@ -5887,6 +5940,12 @@ const GrokSettingsPatch = Schema$1.Struct({
5887
5940
  binaryPath: Schema$1.optionalKey(TrimmedString),
5888
5941
  customModels: Schema$1.optionalKey(Schema$1.Array(Schema$1.String))
5889
5942
  });
5943
+ const MuseSettingsPatch = Schema$1.Struct({
5944
+ enabled: Schema$1.optionalKey(Schema$1.Boolean),
5945
+ binaryPath: Schema$1.optionalKey(TrimmedString),
5946
+ baseUrl: Schema$1.optionalKey(TrimmedString),
5947
+ customModels: Schema$1.optionalKey(Schema$1.Array(Schema$1.String))
5948
+ });
5890
5949
  const OpenCodeSettingsPatch = Schema$1.Struct({
5891
5950
  enabled: Schema$1.optionalKey(Schema$1.Boolean),
5892
5951
  binaryPath: Schema$1.optionalKey(TrimmedString),
@@ -5898,6 +5957,7 @@ const ServerSettingsPatch = Schema$1.Struct({
5898
5957
  enableAssistantStreaming: Schema$1.optionalKey(Schema$1.Boolean),
5899
5958
  enableProviderUpdateChecks: Schema$1.optionalKey(Schema$1.Boolean),
5900
5959
  enableToolCallNarration: Schema$1.optionalKey(Schema$1.Boolean),
5960
+ enableUnpromptedSubagents: Schema$1.optionalKey(Schema$1.Boolean),
5901
5961
  automaticGitFetchInterval: Schema$1.optionalKey(Schema$1.DurationFromMillis),
5902
5962
  defaultThreadEnvMode: Schema$1.optionalKey(ThreadEnvMode),
5903
5963
  newWorktreesStartFromOrigin: Schema$1.optionalKey(Schema$1.Boolean),
@@ -5920,6 +5980,7 @@ const ServerSettingsPatch = Schema$1.Struct({
5920
5980
  claudeAgent: Schema$1.optionalKey(ClaudeSettingsPatch),
5921
5981
  cursor: Schema$1.optionalKey(CursorSettingsPatch),
5922
5982
  grok: Schema$1.optionalKey(GrokSettingsPatch),
5983
+ muse: Schema$1.optionalKey(MuseSettingsPatch),
5923
5984
  opencode: Schema$1.optionalKey(OpenCodeSettingsPatch)
5924
5985
  })),
5925
5986
  providerInstances: Schema$1.optionalKey(Schema$1.Record(ProviderInstanceId, ProviderInstanceConfig))
@@ -6059,6 +6120,14 @@ const ServerProvider = Schema$1.Struct({
6059
6120
  continuation: Schema$1.optional(ServerProviderContinuation),
6060
6121
  showInteractionModeToggle: Schema$1.optional(Schema$1.Boolean),
6061
6122
  requiresNewThreadForModelChange: Schema$1.optional(Schema$1.Boolean),
6123
+ /**
6124
+ * Runtime modes this provider can actually honour. Absent means every
6125
+ * mode is available, which is the case for every provider that can ask
6126
+ * the user for an approval mid-turn. A provider that only runs headless
6127
+ * (Muse Code) lists the subset it can deliver, and clients disable the
6128
+ * rest instead of offering a mode the driver would silently downgrade.
6129
+ */
6130
+ supportedRuntimeModes: Schema$1.optional(Schema$1.Array(RuntimeMode)),
6062
6131
  enabled: Schema$1.Boolean,
6063
6132
  installed: Schema$1.Boolean,
6064
6133
  version: Schema$1.NullOr(TrimmedNonEmptyString),
@@ -7780,11 +7849,17 @@ const AGENT_ASSET_TOTAL_MAX_BYTES = 4 * 1024 * 1024;
7780
7849
  * directory rather than the provider's. The definition travels; the bearer
7781
7850
  * tokens and API keys it references do not, and stay in each machine's own
7782
7851
  * secret store.
7852
+ * - `agent` — a subagent definition, a single markdown file in
7853
+ * `<configDir>/agents`. The name is the filename, as for `memory`. This is the
7854
+ * only artifact that bounds what a subagent is handed and what it hands back,
7855
+ * because p4code observes subagent runs rather than constructing their
7856
+ * prompts — so the I/O contract can only ship as a file the provider reads.
7783
7857
  */
7784
7858
  const AgentAssetKind = Schema$1.Literals([
7785
7859
  "skill",
7786
7860
  "memory",
7787
- "mcp"
7861
+ "mcp",
7862
+ "agent"
7788
7863
  ]);
7789
7864
  /**
7790
7865
  * An asset's name, which for a skill is also its directory name.
@@ -15492,7 +15567,15 @@ function buildSkillOverrides(disabled, discovered) {
15492
15567
  * @module provider/Drivers/ClaudeSkills
15493
15568
  */
15494
15569
  const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
15495
- function parseSkillFrontmatter(contents) {
15570
+ /**
15571
+ * The `name`/`description` header a skill and a subagent definition both carry.
15572
+ *
15573
+ * Exported because agent definitions are the same header in a different file,
15574
+ * and the sync validates them before publishing one. A second copy of this
15575
+ * would be a second answer to "does this load in the provider", which is the
15576
+ * one question both callers are asking.
15577
+ */
15578
+ function parseMarkdownFrontmatter(contents) {
15496
15579
  const match = FRONTMATTER_PATTERN.exec(contents);
15497
15580
  if (!match) return { kind: "missing" };
15498
15581
  let parsed;
@@ -15543,6 +15626,19 @@ const resolveClaudeUserSkillsDir = Effect.fn("resolveClaudeUserSkillsDir")(funct
15543
15626
  return path.join(configDirPath, "skills");
15544
15627
  });
15545
15628
  /**
15629
+ * The user-scope subagent directory the CLI would read.
15630
+ *
15631
+ * Same resolution as the skills directory beside it, for the same reason: the
15632
+ * sync materializes into exactly the directory the provider loads from, and
15633
+ * deriving it a second time is how the two come to disagree about where an
15634
+ * agent definition lives.
15635
+ */
15636
+ const resolveClaudeUserAgentsDir = Effect.fn("resolveClaudeUserAgentsDir")(function* (config, environment, cwd) {
15637
+ const path = yield* Path.Path;
15638
+ const configDirPath = yield* resolveClaudeConfigDirPath(config, environment ?? process.env, cwd);
15639
+ return path.join(configDirPath, "agents");
15640
+ });
15641
+ /**
15546
15642
  * Enumerate Claude Code skills from the user config dir and the workspace.
15547
15643
  * Discovery is best-effort: unreadable roots and malformed skill entries are
15548
15644
  * skipped so a broken skill never degrades the provider snapshot. On name
@@ -15567,7 +15663,7 @@ const discoverClaudeSkills = Effect.fn("discoverClaudeSkills")(function* (config
15567
15663
  const skillPath = path.join(root.directory, entry, "SKILL.md");
15568
15664
  const contents = yield* fileSystem.readFileString(skillPath).pipe(Effect.orElseSucceed(() => void 0));
15569
15665
  if (contents === void 0) continue;
15570
- const frontmatter = parseSkillFrontmatter(contents);
15666
+ const frontmatter = parseMarkdownFrontmatter(contents);
15571
15667
  if (frontmatter.kind === "malformed") continue;
15572
15668
  const name = (frontmatter.kind === "parsed" ? frontmatter.name : void 0) ?? entry.trim();
15573
15669
  if (!name) continue;
@@ -16389,6 +16485,288 @@ const make$62 = Effect.gen(function* () {
16389
16485
  });
16390
16486
  const layer$57 = Layer.effect(McpRegistry, make$62);
16391
16487
  //#endregion
16488
+ //#region src/sync/skillDirectory.ts
16489
+ /**
16490
+ * Reading and writing skill directories on disk.
16491
+ *
16492
+ * Kept apart from the sync itself so the filesystem shape has its own tests,
16493
+ * and so the rules about what is refusable — binaries, oversized files, deep
16494
+ * trees — live in one place rather than being rediscovered at each call site.
16495
+ *
16496
+ * @module sync/skillDirectory
16497
+ */
16498
+ /** Bounded so a stray symlink or a vendored `node_modules` cannot walk forever. */
16499
+ const MAX_SKILL_DEPTH = 4;
16500
+ /**
16501
+ * Entries that are never part of a skill, skipped rather than refused.
16502
+ *
16503
+ * The distinction matters. Refusing an asset because it cannot be represented
16504
+ * faithfully is right — a half-materialized skill loads and misbehaves. But a
16505
+ * `.DS_Store` is not part of the skill at all, and macOS drops one into any
16506
+ * directory that has been opened in Finder, so refusing on its account rejects
16507
+ * a perfectly good skill for a reason its author cannot see.
16508
+ *
16509
+ * These could not sync in any case: `AgentAssetFilePath` rejects a leading dot,
16510
+ * so a dotfile has no representable path even if it were text.
16511
+ */
16512
+ const IGNORED_ENTRIES = /* @__PURE__ */ new Set([
16513
+ ".DS_Store",
16514
+ "Thumbs.db",
16515
+ ".git",
16516
+ ".svn",
16517
+ ".hg",
16518
+ "node_modules",
16519
+ "__pycache__",
16520
+ ".venv",
16521
+ ".pytest_cache",
16522
+ ".ruff_cache",
16523
+ ".mypy_cache"
16524
+ ]);
16525
+ /**
16526
+ * Anything else with a leading dot is skipped too — an editor's `.idea`, a
16527
+ * `.gitignore` that belongs to the checkout rather than the skill. The rule is
16528
+ * the same one the path schema already enforces, applied earlier so it reads as
16529
+ * "not part of the skill" instead of "this skill is broken".
16530
+ */
16531
+ const isIgnoredEntry = (entry) => IGNORED_ENTRIES.has(entry) || entry.startsWith(".");
16532
+ /**
16533
+ * A file is binary if decoding it yields a NUL.
16534
+ *
16535
+ * Cheap, and right for what is being asked: the question is not "is this valid
16536
+ * UTF-8" but "can this round-trip through a JSON text column", and a NUL is
16537
+ * what actually breaks that on the way back out of SQLite.
16538
+ *
16539
+ * Exported so the single-file kinds ask it the same way this one does, rather
16540
+ * than each keeping a copy that could drift into a different answer.
16541
+ */
16542
+ const looksBinary$1 = (content) => content.includes("\0");
16543
+ /**
16544
+ * Read one directory as an asset's files, or say why it cannot be one.
16545
+ *
16546
+ * Exported because memory's `global-memory/` is the same shape by a different
16547
+ * name: a directory whose whole contents are the asset. Sharing this keeps the
16548
+ * refusal rules — depth, file count, binaries, size — identical for both,
16549
+ * rather than letting a second copy drift into accepting what the first
16550
+ * rejects.
16551
+ */
16552
+ const readSkillFiles = Effect.fn("skillDirectory.readSkillFiles")(function* (root) {
16553
+ const fileSystem = yield* FileSystem.FileSystem;
16554
+ const path = yield* Path.Path;
16555
+ const files = [];
16556
+ const walk = Effect.fn("skillDirectory.walk")(function* (directory, prefix, depth) {
16557
+ if (depth > MAX_SKILL_DEPTH) return "too-deep";
16558
+ const entries = yield* fileSystem.readDirectory(directory).pipe(Effect.orElseSucceed(() => []));
16559
+ for (const entry of [...entries].sort()) {
16560
+ if (isIgnoredEntry(entry)) continue;
16561
+ const absolute = path.join(directory, entry);
16562
+ const relative = prefix === "" ? entry : `${prefix}/${entry}`;
16563
+ const info = yield* fileSystem.stat(absolute).pipe(Effect.orElseSucceed(() => void 0));
16564
+ if (info === void 0) return "unreadable";
16565
+ if (info.type === "Directory") {
16566
+ const nested = yield* walk(absolute, relative, depth + 1);
16567
+ if (nested !== null) return nested;
16568
+ continue;
16569
+ }
16570
+ if (info.type !== "File") continue;
16571
+ if (files.length >= 512) return "too-many-files";
16572
+ const content = yield* fileSystem.readFileString(absolute).pipe(Effect.orElseSucceed(() => void 0));
16573
+ if (content === void 0) return "unreadable";
16574
+ if (looksBinary$1(content)) return "binary-file";
16575
+ if (content.length > 524288) return "file-too-large";
16576
+ files.push({
16577
+ path: relative,
16578
+ content
16579
+ });
16580
+ }
16581
+ return null;
16582
+ });
16583
+ const refusal = yield* walk(root, "", 1);
16584
+ if (refusal !== null) return { refusal };
16585
+ if (agentAssetTotalBytes(files) > 4194304) return { refusal: "asset-too-large" };
16586
+ return { files };
16587
+ });
16588
+ /**
16589
+ * Read every skill directory under a user-scope `skills/` root.
16590
+ *
16591
+ * A directory with no `SKILL.md` is not a skill and is skipped silently —
16592
+ * Claude Code would ignore it too, so reporting it would be noise about
16593
+ * something that was never a skill in the first place.
16594
+ */
16595
+ const readSkillDirectory = Effect.fn("skillDirectory.readSkillDirectory")(function* (skillsRoot) {
16596
+ const fileSystem = yield* FileSystem.FileSystem;
16597
+ const path = yield* Path.Path;
16598
+ const entries = yield* fileSystem.readDirectory(skillsRoot).pipe(Effect.orElseSucceed(() => []));
16599
+ const skills = [];
16600
+ const refused = [];
16601
+ for (const entry of [...entries].sort()) {
16602
+ if (isIgnoredEntry(entry)) continue;
16603
+ const directory = path.join(skillsRoot, entry);
16604
+ if ((yield* fileSystem.stat(directory).pipe(Effect.orElseSucceed(() => void 0)))?.type !== "Directory") continue;
16605
+ if (!(yield* fileSystem.exists(path.join(directory, "SKILL.md")).pipe(Effect.orElseSucceed(() => false)))) continue;
16606
+ const read = yield* readSkillFiles(directory);
16607
+ if ("refusal" in read) {
16608
+ refused.push({
16609
+ name: entry,
16610
+ reason: read.refusal
16611
+ });
16612
+ continue;
16613
+ }
16614
+ skills.push({
16615
+ name: entry,
16616
+ files: read.files
16617
+ });
16618
+ }
16619
+ return {
16620
+ skills,
16621
+ refused
16622
+ };
16623
+ });
16624
+ /**
16625
+ * Replace a skill directory with exactly the asset's files.
16626
+ *
16627
+ * Written to a sibling and then swapped, so a crash mid-write leaves the old
16628
+ * skill intact rather than half of the new one. A skill is loaded as a unit and
16629
+ * a partially written one is instructions with the middle missing, which an
16630
+ * agent will happily follow.
16631
+ */
16632
+ const writeSkillDirectory = Effect.fn("skillDirectory.writeSkillDirectory")(function* (input) {
16633
+ const fileSystem = yield* FileSystem.FileSystem;
16634
+ const path = yield* Path.Path;
16635
+ const target = path.join(input.skillsRoot, input.name);
16636
+ const staging = path.join(input.skillsRoot, `.${input.name}.p4code-staging`);
16637
+ yield* fileSystem.makeDirectory(input.skillsRoot, { recursive: true });
16638
+ yield* fileSystem.remove(staging, {
16639
+ recursive: true,
16640
+ force: true
16641
+ });
16642
+ yield* fileSystem.makeDirectory(staging, { recursive: true });
16643
+ for (const file of input.files) {
16644
+ const destination = path.join(staging, file.path);
16645
+ yield* fileSystem.makeDirectory(path.dirname(destination), { recursive: true });
16646
+ yield* fileSystem.writeFileString(destination, file.content);
16647
+ }
16648
+ yield* fileSystem.remove(target, {
16649
+ recursive: true,
16650
+ force: true
16651
+ });
16652
+ yield* fileSystem.rename(staging, target);
16653
+ });
16654
+ const removeSkillDirectory = Effect.fn("skillDirectory.removeSkillDirectory")(function* (input) {
16655
+ const fileSystem = yield* FileSystem.FileSystem;
16656
+ const path = yield* Path.Path;
16657
+ yield* fileSystem.remove(path.join(input.skillsRoot, input.name), {
16658
+ recursive: true,
16659
+ force: true
16660
+ });
16661
+ });
16662
+ /**
16663
+ * Whether this text is a definition the provider would actually load.
16664
+ *
16665
+ * Both fields, not just the header. `name` is how a subagent is addressed and
16666
+ * `description` is how the orchestrator decides to address it, so a definition
16667
+ * missing either is present on disk and unreachable in practice.
16668
+ */
16669
+ const isLoadableAgentDefinition = (content) => {
16670
+ const frontmatter = parseMarkdownFrontmatter(content);
16671
+ return frontmatter.kind === "parsed" && frontmatter.name !== void 0 && frontmatter.description !== void 0;
16672
+ };
16673
+ /**
16674
+ * Every definition in the directory, as syncable assets.
16675
+ *
16676
+ * A file that will not load is refused rather than skipped, unlike a stray
16677
+ * `.DS_Store`: a `.md` in this directory is meant to be an agent, so a broken
16678
+ * header is a fault worth reporting instead of noise to ignore.
16679
+ */
16680
+ const readAgentDefinitions = Effect.fn("agentDefinitionFiles.read")(function* (agentsRoot) {
16681
+ const fileSystem = yield* FileSystem.FileSystem;
16682
+ const path = yield* Path.Path;
16683
+ const entries = yield* fileSystem.readDirectory(agentsRoot).pipe(Effect.orElseSucceed(() => []));
16684
+ const skills = [];
16685
+ const refused = [];
16686
+ for (const entry of [...entries].sort()) {
16687
+ if (!entry.endsWith(".md") || entry.startsWith(".")) continue;
16688
+ const absolute = path.join(agentsRoot, entry);
16689
+ if ((yield* fileSystem.stat(absolute).pipe(Effect.orElseSucceed(() => void 0)))?.type !== "File") continue;
16690
+ const content = yield* fileSystem.readFileString(absolute).pipe(Effect.orElseSucceed(() => void 0));
16691
+ if (content === void 0) {
16692
+ refused.push({
16693
+ name: entry,
16694
+ reason: "unreadable"
16695
+ });
16696
+ continue;
16697
+ }
16698
+ if (looksBinary$1(content)) {
16699
+ refused.push({
16700
+ name: entry,
16701
+ reason: "binary-file"
16702
+ });
16703
+ continue;
16704
+ }
16705
+ if (content.length > 524288) {
16706
+ refused.push({
16707
+ name: entry,
16708
+ reason: "file-too-large"
16709
+ });
16710
+ continue;
16711
+ }
16712
+ if (!isLoadableAgentDefinition(content)) {
16713
+ refused.push({
16714
+ name: entry,
16715
+ reason: "unreadable"
16716
+ });
16717
+ continue;
16718
+ }
16719
+ const files = [{
16720
+ path: entry,
16721
+ content
16722
+ }];
16723
+ if (agentAssetTotalBytes(files) > 4194304) {
16724
+ refused.push({
16725
+ name: entry,
16726
+ reason: "asset-too-large"
16727
+ });
16728
+ continue;
16729
+ }
16730
+ skills.push({
16731
+ name: entry,
16732
+ files
16733
+ });
16734
+ }
16735
+ return {
16736
+ skills,
16737
+ refused
16738
+ };
16739
+ });
16740
+ /**
16741
+ * Write a definition that arrived from the hub.
16742
+ *
16743
+ * Refused unless it is exactly one markdown file whose path is the asset's own
16744
+ * name and whose frontmatter would load. The last check is the one that matters
16745
+ * across machines: it is what stops a hub row edited by hand from installing a
16746
+ * file the provider quietly ignores on every machine that syncs it.
16747
+ *
16748
+ * Written atomically because a definition is read whole when a subagent starts,
16749
+ * and half of one is instructions with the contract missing.
16750
+ */
16751
+ const writeAgentDefinition = Effect.fn("agentDefinitionFiles.write")(function* (input) {
16752
+ const fileSystem = yield* FileSystem.FileSystem;
16753
+ const path = yield* Path.Path;
16754
+ const file = input.files[0];
16755
+ if (!input.name.endsWith(".md") || input.files.length !== 1 || file === void 0 || file.path !== input.name) return "refused";
16756
+ if (!isLoadableAgentDefinition(file.content)) return "refused";
16757
+ yield* fileSystem.makeDirectory(input.agentsRoot, { recursive: true }).pipe(Effect.ignore);
16758
+ return yield* writeFileStringAtomically({
16759
+ filePath: path.join(input.agentsRoot, input.name),
16760
+ contents: file.content
16761
+ }).pipe(Effect.as("written"), Effect.orElseSucceed(() => "failed"));
16762
+ });
16763
+ const removeAgentDefinition = Effect.fn("agentDefinitionFiles.remove")(function* (input) {
16764
+ if (!input.name.endsWith(".md")) return;
16765
+ const fileSystem = yield* FileSystem.FileSystem;
16766
+ const path = yield* Path.Path;
16767
+ yield* fileSystem.remove(path.join(input.agentsRoot, input.name), { force: true });
16768
+ });
16769
+ //#endregion
16392
16770
  //#region src/sync/HubLink.ts
16393
16771
  /**
16394
16772
  * Where this server's hub is, what it authenticates with, and whether it syncs
@@ -16762,178 +17140,6 @@ const removeMcpRegistration = Effect.fn("mcpRegistrationFiles.remove")(function*
16762
17140
  yield* fileSystem.remove(path.join(input.registrationsRoot, input.name), { force: true });
16763
17141
  });
16764
17142
  //#endregion
16765
- //#region src/sync/skillDirectory.ts
16766
- /**
16767
- * Reading and writing skill directories on disk.
16768
- *
16769
- * Kept apart from the sync itself so the filesystem shape has its own tests,
16770
- * and so the rules about what is refusable — binaries, oversized files, deep
16771
- * trees — live in one place rather than being rediscovered at each call site.
16772
- *
16773
- * @module sync/skillDirectory
16774
- */
16775
- /** Bounded so a stray symlink or a vendored `node_modules` cannot walk forever. */
16776
- const MAX_SKILL_DEPTH = 4;
16777
- /**
16778
- * Entries that are never part of a skill, skipped rather than refused.
16779
- *
16780
- * The distinction matters. Refusing an asset because it cannot be represented
16781
- * faithfully is right — a half-materialized skill loads and misbehaves. But a
16782
- * `.DS_Store` is not part of the skill at all, and macOS drops one into any
16783
- * directory that has been opened in Finder, so refusing on its account rejects
16784
- * a perfectly good skill for a reason its author cannot see.
16785
- *
16786
- * These could not sync in any case: `AgentAssetFilePath` rejects a leading dot,
16787
- * so a dotfile has no representable path even if it were text.
16788
- */
16789
- const IGNORED_ENTRIES = /* @__PURE__ */ new Set([
16790
- ".DS_Store",
16791
- "Thumbs.db",
16792
- ".git",
16793
- ".svn",
16794
- ".hg",
16795
- "node_modules",
16796
- "__pycache__",
16797
- ".venv",
16798
- ".pytest_cache",
16799
- ".ruff_cache",
16800
- ".mypy_cache"
16801
- ]);
16802
- /**
16803
- * Anything else with a leading dot is skipped too — an editor's `.idea`, a
16804
- * `.gitignore` that belongs to the checkout rather than the skill. The rule is
16805
- * the same one the path schema already enforces, applied earlier so it reads as
16806
- * "not part of the skill" instead of "this skill is broken".
16807
- */
16808
- const isIgnoredEntry = (entry) => IGNORED_ENTRIES.has(entry) || entry.startsWith(".");
16809
- /**
16810
- * A file is binary if decoding it yields a NUL.
16811
- *
16812
- * Cheap, and right for what is being asked: the question is not "is this valid
16813
- * UTF-8" but "can this round-trip through a JSON text column", and a NUL is
16814
- * what actually breaks that on the way back out of SQLite.
16815
- */
16816
- const looksBinary$1 = (content) => content.includes("\0");
16817
- /**
16818
- * Read one directory as an asset's files, or say why it cannot be one.
16819
- *
16820
- * Exported because memory's `global-memory/` is the same shape by a different
16821
- * name: a directory whose whole contents are the asset. Sharing this keeps the
16822
- * refusal rules — depth, file count, binaries, size — identical for both,
16823
- * rather than letting a second copy drift into accepting what the first
16824
- * rejects.
16825
- */
16826
- const readSkillFiles = Effect.fn("skillDirectory.readSkillFiles")(function* (root) {
16827
- const fileSystem = yield* FileSystem.FileSystem;
16828
- const path = yield* Path.Path;
16829
- const files = [];
16830
- const walk = Effect.fn("skillDirectory.walk")(function* (directory, prefix, depth) {
16831
- if (depth > MAX_SKILL_DEPTH) return "too-deep";
16832
- const entries = yield* fileSystem.readDirectory(directory).pipe(Effect.orElseSucceed(() => []));
16833
- for (const entry of [...entries].sort()) {
16834
- if (isIgnoredEntry(entry)) continue;
16835
- const absolute = path.join(directory, entry);
16836
- const relative = prefix === "" ? entry : `${prefix}/${entry}`;
16837
- const info = yield* fileSystem.stat(absolute).pipe(Effect.orElseSucceed(() => void 0));
16838
- if (info === void 0) return "unreadable";
16839
- if (info.type === "Directory") {
16840
- const nested = yield* walk(absolute, relative, depth + 1);
16841
- if (nested !== null) return nested;
16842
- continue;
16843
- }
16844
- if (info.type !== "File") continue;
16845
- if (files.length >= 512) return "too-many-files";
16846
- const content = yield* fileSystem.readFileString(absolute).pipe(Effect.orElseSucceed(() => void 0));
16847
- if (content === void 0) return "unreadable";
16848
- if (looksBinary$1(content)) return "binary-file";
16849
- if (content.length > 524288) return "file-too-large";
16850
- files.push({
16851
- path: relative,
16852
- content
16853
- });
16854
- }
16855
- return null;
16856
- });
16857
- const refusal = yield* walk(root, "", 1);
16858
- if (refusal !== null) return { refusal };
16859
- if (agentAssetTotalBytes(files) > 4194304) return { refusal: "asset-too-large" };
16860
- return { files };
16861
- });
16862
- /**
16863
- * Read every skill directory under a user-scope `skills/` root.
16864
- *
16865
- * A directory with no `SKILL.md` is not a skill and is skipped silently —
16866
- * Claude Code would ignore it too, so reporting it would be noise about
16867
- * something that was never a skill in the first place.
16868
- */
16869
- const readSkillDirectory = Effect.fn("skillDirectory.readSkillDirectory")(function* (skillsRoot) {
16870
- const fileSystem = yield* FileSystem.FileSystem;
16871
- const path = yield* Path.Path;
16872
- const entries = yield* fileSystem.readDirectory(skillsRoot).pipe(Effect.orElseSucceed(() => []));
16873
- const skills = [];
16874
- const refused = [];
16875
- for (const entry of [...entries].sort()) {
16876
- if (isIgnoredEntry(entry)) continue;
16877
- const directory = path.join(skillsRoot, entry);
16878
- if ((yield* fileSystem.stat(directory).pipe(Effect.orElseSucceed(() => void 0)))?.type !== "Directory") continue;
16879
- if (!(yield* fileSystem.exists(path.join(directory, "SKILL.md")).pipe(Effect.orElseSucceed(() => false)))) continue;
16880
- const read = yield* readSkillFiles(directory);
16881
- if ("refusal" in read) {
16882
- refused.push({
16883
- name: entry,
16884
- reason: read.refusal
16885
- });
16886
- continue;
16887
- }
16888
- skills.push({
16889
- name: entry,
16890
- files: read.files
16891
- });
16892
- }
16893
- return {
16894
- skills,
16895
- refused
16896
- };
16897
- });
16898
- /**
16899
- * Replace a skill directory with exactly the asset's files.
16900
- *
16901
- * Written to a sibling and then swapped, so a crash mid-write leaves the old
16902
- * skill intact rather than half of the new one. A skill is loaded as a unit and
16903
- * a partially written one is instructions with the middle missing, which an
16904
- * agent will happily follow.
16905
- */
16906
- const writeSkillDirectory = Effect.fn("skillDirectory.writeSkillDirectory")(function* (input) {
16907
- const fileSystem = yield* FileSystem.FileSystem;
16908
- const path = yield* Path.Path;
16909
- const target = path.join(input.skillsRoot, input.name);
16910
- const staging = path.join(input.skillsRoot, `.${input.name}.p4code-staging`);
16911
- yield* fileSystem.makeDirectory(input.skillsRoot, { recursive: true });
16912
- yield* fileSystem.remove(staging, {
16913
- recursive: true,
16914
- force: true
16915
- });
16916
- yield* fileSystem.makeDirectory(staging, { recursive: true });
16917
- for (const file of input.files) {
16918
- const destination = path.join(staging, file.path);
16919
- yield* fileSystem.makeDirectory(path.dirname(destination), { recursive: true });
16920
- yield* fileSystem.writeFileString(destination, file.content);
16921
- }
16922
- yield* fileSystem.remove(target, {
16923
- recursive: true,
16924
- force: true
16925
- });
16926
- yield* fileSystem.rename(staging, target);
16927
- });
16928
- const removeSkillDirectory = Effect.fn("skillDirectory.removeSkillDirectory")(function* (input) {
16929
- const fileSystem = yield* FileSystem.FileSystem;
16930
- const path = yield* Path.Path;
16931
- yield* fileSystem.remove(path.join(input.skillsRoot, input.name), {
16932
- recursive: true,
16933
- force: true
16934
- });
16935
- });
16936
- //#endregion
16937
17143
  //#region src/sync/memoryFile.ts
16938
17144
  /**
16939
17145
  * Reading and writing user-scope memory files.
@@ -17214,12 +17420,20 @@ const PROCEED = { _tag: "proceed" };
17214
17420
  * - A skill without `SKILL.md` would be invisible to discovery: the picker
17215
17421
  * skips directories without one, so the create would look like it silently
17216
17422
  * failed. Refused with the reason instead.
17423
+ * - An agent definition is one markdown file whose name is the asset's own, and
17424
+ * anything else is invisible in the same way — the provider reads `.md` in
17425
+ * that directory and nothing else. The frontmatter check is the writer's,
17426
+ * because it needs a YAML parse this module deliberately does without.
17217
17427
  * - An existing local name is never overwritten. Create means create; editing
17218
17428
  * is a different operation with a different surface.
17219
17429
  */
17220
17430
  function decideCreateLocal(input) {
17221
17431
  if (input.asset.kind === "mcp") return refuse("refused", "MCP registrations are created through mcp.save, not as files.");
17222
17432
  if (input.asset.kind === "skill" && !input.asset.files.some((file) => file.path === "SKILL.md")) return refuse("refused", "A skill needs a SKILL.md at its root; without one, discovery skips the directory.");
17433
+ if (input.asset.kind === "agent") {
17434
+ const [file, ...rest] = input.asset.files;
17435
+ if (!input.asset.name.endsWith(".md") || rest.length > 0 || file?.path !== input.asset.name) return refuse("refused", "An agent definition is a single markdown file named after the asset, for example 'reviewer.md' holding 'reviewer.md'.");
17436
+ }
17223
17437
  if (input.localNames.has(input.asset.name)) return refuse("exists", `An asset named '${input.asset.name}' already exists locally.`);
17224
17438
  return PROCEED;
17225
17439
  }
@@ -17462,6 +17676,22 @@ const make$59 = Effect.gen(function* () {
17462
17676
  name
17463
17677
  }).pipe(Effect.ignore)
17464
17678
  },
17679
+ {
17680
+ kind: "agent",
17681
+ resolveRoot: Effect.gen(function* () {
17682
+ return yield* resolveClaudeUserAgentsDir(yield* claudeHome());
17683
+ }),
17684
+ read: (root) => readAgentDefinitions(root),
17685
+ write: ({ root, name, files }) => writeAgentDefinition({
17686
+ agentsRoot: root,
17687
+ name,
17688
+ files
17689
+ }),
17690
+ remove: ({ root, name }) => removeAgentDefinition({
17691
+ agentsRoot: root,
17692
+ name
17693
+ }).pipe(Effect.ignore)
17694
+ },
17465
17695
  {
17466
17696
  kind: "mcp",
17467
17697
  resolveRoot: Effect.succeed(path.join(config.stateDir, "mcp")),
@@ -18103,6 +18333,262 @@ const make$59 = Effect.gen(function* () {
18103
18333
  });
18104
18334
  const layer$54 = Layer.effect(AssetSync, make$59);
18105
18335
  //#endregion
18336
+ //#region src/provider/CompressPrompts.ts
18337
+ /**
18338
+ * Caveman-style response compression rulesets, adapted from the caveman
18339
+ * plugin's SKILL.md. Pre-baked per level so injection is a lookup, not a
18340
+ * runtime template. Applies to assistant prose only: code blocks, commits,
18341
+ * PRs, error strings, and safety-critical text stay uncompressed.
18342
+ */
18343
+ const COMPRESS_SHARED_RULES = `Respond terse. All technical substance stays. Only fluff dies.
18344
+
18345
+ ## Persistence
18346
+
18347
+ Active every response. No revert after many turns. No filler drift. Still active if unsure.
18348
+
18349
+ ## Rules
18350
+
18351
+ Drop filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Short synonyms (big not extensive, fix not "implement a solution for"). No decorative tables/emoji, no dumping long raw error logs unless asked - quote shortest decisive line. Standard well-known tech acronyms OK (DB/API/HTTP); never invent new abbreviations (cfg/impl/req/res/fn) - tokenizers split them same as the full word: zero tokens saved, reader still decodes. No causal arrows (->) in prose. Technical terms exact. Code blocks unchanged. Errors quoted exact.
18352
+
18353
+ Never drop not/never/no/only/except: flipping the meaning costs more than any token saved. Numbers and units exact.
18354
+
18355
+ Tool calls: fire direct. No plan, no progress note between calls, never announce the next call. If the harness asks for a short lead-in before tool calls, write that one line and nothing more. Otherwise text before a call only to clarify, warn about a security or irreversible action, or resolve ambiguity.
18356
+
18357
+ Preserve the user's dominant language: reply in the language the user writes, whatever language the examples or the surrounding context use. Compress the style, not the language. Every emitted line in that language, lead-in lines included, not just the final reply. Always keep technical terms, code, API names, CLI commands, commit-type keywords (feat/fix/...), and exact error strings verbatim unless the user explicitly asks for translation.
18358
+
18359
+ Dropping articles applies to article languages only. Where small markers carry case or role (particles, postpositions), keep them: grammar, not filler. Compress politeness and filler instead.
18360
+
18361
+ No self-reference. Never name or announce the style. No compressed answer plus normal recap - compressed output only. Exception: user explicitly asks what the mode is.
18362
+
18363
+ ## Auto-Clarity
18364
+
18365
+ Drop compression and write normally when:
18366
+ - Security warnings
18367
+ - Irreversible action confirmations
18368
+ - Multi-step sequences where fragment order or omitted conjunctions risk misread
18369
+ - Compression itself creates technical ambiguity (e.g. "migrate table drop column backup first" - order unclear without articles and conjunctions)
18370
+ - User asks to clarify or repeats a question
18371
+
18372
+ Resume compression after the clear part is done. The example below shows the format only: write the warning in the session's language, not the example's.
18373
+
18374
+ Example - destructive operation:
18375
+ > **Warning:** This will permanently delete all rows in the \`users\` table and cannot be undone.
18376
+ > \`\`\`sql
18377
+ > DROP TABLE users;
18378
+ > \`\`\`
18379
+ > Compression resumes. Verify a backup exists first.
18380
+
18381
+ ## Boundaries
18382
+
18383
+ Anything persisted outside the chat: write normal, uncompressed prose. Covers code, code comments, commit messages, PR and issue text, docs, memory files, and messages to third parties.`;
18384
+ const COMPRESS_RULESETS = {
18385
+ lite: `## Response compression: lite
18386
+
18387
+ ${COMPRESS_SHARED_RULES}
18388
+
18389
+ ## Intensity: lite
18390
+
18391
+ No filler or hedging. Keep articles and full sentences. Professional but tight.
18392
+
18393
+ Example - "Why does my React component re-render?"
18394
+ "Your component re-renders because you create a new object reference each render. Wrap it in \`useMemo\`."
18395
+
18396
+ Example - "Explain database connection pooling."
18397
+ "Connection pooling reuses open connections instead of creating a new one per request. Avoids repeated handshake overhead."`,
18398
+ full: `## Response compression: full
18399
+
18400
+ ${COMPRESS_SHARED_RULES}
18401
+
18402
+ ## Intensity: full
18403
+
18404
+ Drop articles (a/an/the), fragments OK, short synonyms. Pattern: [thing] [action] [reason]. [next step].
18405
+
18406
+ Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
18407
+ Yes: "Bug in auth middleware. Token expiry check use \`<\` not \`<=\`. Fix:"
18408
+
18409
+ Example - "Why does my React component re-render?"
18410
+ "New object ref each render. Inline object prop = new ref = re-render. Wrap in \`useMemo\`."
18411
+
18412
+ Example - "Explain database connection pooling."
18413
+ "Pool reuses open DB connections. No new connection per request. Skips handshake overhead."`,
18414
+ ultra: `## Response compression: ultra
18415
+
18416
+ ${COMPRESS_SHARED_RULES}
18417
+
18418
+ ## Intensity: ultra
18419
+
18420
+ Drop articles, fragments OK, short synonyms. Also strip conjunctions when cause-then-effect stays unambiguous. One word when one word is enough. State each fact once. Still no invented abbreviations (cfg/impl/req/res/fn/auth) and still no arrows (X -> Y): both measure as zero token saving and cost decode clarity. Code symbols, function names, API names, error strings: never touch.
18421
+
18422
+ Example - "Why does my React component re-render?"
18423
+ "Inline object prop, new ref, re-render. \`useMemo\`."
18424
+
18425
+ Example - "Explain database connection pooling."
18426
+ "Pool reuses open DB connections. No per-request handshake."`
18427
+ };
18428
+ const COMPRESS_TURN_REMINDERS = {
18429
+ lite: "[response style: compressed lite - no filler/hedging, full sentences; keep negations and numbers exact; code/commits/security text normal]",
18430
+ full: "[response style: compressed full - terse fragments, drop articles/filler; keep negations and numbers exact; code/commits/security text normal]",
18431
+ ultra: "[response style: compressed ultra - maximum terseness, one word when enough; keep negations and numbers exact; code/commits/security text normal]"
18432
+ };
18433
+ function compressRulesetFor(mode) {
18434
+ return mode === "off" ? void 0 : COMPRESS_RULESETS[mode];
18435
+ }
18436
+ function compressTurnReminderFor(mode) {
18437
+ return mode === "off" ? void 0 : COMPRESS_TURN_REMINDERS[mode];
18438
+ }
18439
+ //#endregion
18440
+ //#region src/sync/agentPresets.ts
18441
+ /**
18442
+ * The row ceiling both presets impose.
18443
+ *
18444
+ * A cap rather than "be brief": an uncapped list is how a subagent turns a
18445
+ * bounded answer back into a page, and a number is the only form of that
18446
+ * instruction a model cannot negotiate with.
18447
+ */
18448
+ const PRESET_MAX_RESULT_ROWS = 20;
18449
+ /**
18450
+ * Named `p4-*` on purpose.
18451
+ *
18452
+ * The directory is shared with whatever the user has written by hand, and
18453
+ * installing a preset must never quietly replace their own `reviewer`. The
18454
+ * prefix also makes provenance obvious in the settings list, where every kind
18455
+ * of agent definition appears in one column.
18456
+ */
18457
+ const PRESET_NAME_PREFIX = "p4-";
18458
+ /**
18459
+ * What every preset says about what it is handed.
18460
+ *
18461
+ * Shared because it is the same contract whatever the subagent does: no
18462
+ * inherited history, exact paths, and a refusal instead of a guess. The last
18463
+ * clause is the one that earns its place — a subagent that invents the missing
18464
+ * half of an under-specified prompt returns something confident and wrong,
18465
+ * which costs more than the turn that asked for it.
18466
+ */
18467
+ const INPUT_CONTRACT = `## What you are given
18468
+
18469
+ You inherit no session history. The prompt is the whole of what you know: one
18470
+ request, plus whatever exact paths the orchestrator has already established.
18471
+ Treat those paths as authoritative and start from them rather than searching for
18472
+ them again.
18473
+
18474
+ What the prompt does not say, you do not assume. If it names no request, or
18475
+ names a path that is not there, answer with the BLOCKED line below. Guessing at
18476
+ the missing half of a request produces an answer that reads as confident and is
18477
+ not checkable, which is worse than no answer.`;
18478
+ /**
18479
+ * What every preset says about the answer.
18480
+ *
18481
+ * The two sentinels matter as much as the table. Without `NONE` a clean run
18482
+ * comes back as a paragraph explaining that everything looked fine; without
18483
+ * `BLOCKED` an under-specified request comes back as an apology. Both are the
18484
+ * narrative this contract exists to remove, and both are cheap to name.
18485
+ */
18486
+ const outputContract = (row, extra) => [
18487
+ "## What you return",
18488
+ "",
18489
+ "Your final message is the result. It is the table and nothing else: no",
18490
+ "preamble, no restatement of the request, no summary underneath it.",
18491
+ "",
18492
+ `One row per finding, at most ${PRESET_MAX_RESULT_ROWS}, most important first:`,
18493
+ "",
18494
+ ` ${row}`,
18495
+ "",
18496
+ "Nothing to report: the single word NONE.",
18497
+ "Request insufficient: BLOCKED - <what is missing>, on one line.",
18498
+ "",
18499
+ "Paths are repository-relative and carry a line number. A row without one is",
18500
+ "a row you have not verified: open the file and get it.",
18501
+ ...extra
18502
+ ].join("\n");
18503
+ /**
18504
+ * Assemble one definition.
18505
+ *
18506
+ * The compression ruleset goes last so the contract above it is read first.
18507
+ * Both are instructions to the same model and neither overrides the other:
18508
+ * the contract fixes the shape, the ruleset fixes the prose inside it.
18509
+ */
18510
+ const buildPreset = (input) => {
18511
+ const name = `${PRESET_NAME_PREFIX}${input.name}`;
18512
+ const content = [
18513
+ "---",
18514
+ `name: ${name}`,
18515
+ `description: ${JSON.stringify(input.description)}`,
18516
+ `tools: ${input.tools}`,
18517
+ "---",
18518
+ "",
18519
+ input.body.trim(),
18520
+ "",
18521
+ compressRulesetFor("full") ?? "",
18522
+ ""
18523
+ ].join("\n");
18524
+ const fileName = `${name}.md`;
18525
+ return {
18526
+ name: fileName,
18527
+ summary: input.summary,
18528
+ files: [{
18529
+ path: fileName,
18530
+ content
18531
+ }]
18532
+ };
18533
+ };
18534
+ /** Every preset, in the order `p4c agents presets` lists them. */
18535
+ const AGENT_PRESETS = [buildPreset({
18536
+ name: "investigator",
18537
+ description: "Find where something lives in the codebase. Use when the answer is a set of locations rather than a change. Returns a fixed table of path:line rows and nothing else.",
18538
+ tools: "Read, Grep, Glob, Bash",
18539
+ summary: "Locates code and answers with a path:line table.",
18540
+ body: `You locate code. You do not change it, and you say no more about any location
18541
+ than the one clause that explains why it is in the list.
18542
+
18543
+ ${INPUT_CONTRACT}
18544
+
18545
+ ${outputContract("path:line - symbol - one clause on why it matters", [
18546
+ "",
18547
+ "Symbol is the function, type or constant the line belongs to, not a paraphrase",
18548
+ "of the line. Where there is genuinely no symbol, name the block: a route table,",
18549
+ "a config literal."
18550
+ ])}`
18551
+ }), buildPreset({
18552
+ name: "reviewer",
18553
+ description: "Review named files or a diff for defects. Use when the answer is a list of findings rather than a change. Returns a fixed table of path:line findings and nothing else.",
18554
+ tools: "Read, Grep, Glob, Bash",
18555
+ summary: "Reviews named files and answers with a severity-tagged finding table.",
18556
+ body: `You review code you did not write. You do not change it, and you do not report
18557
+ what it does well - the orchestrator asked what is wrong, and a list padded with
18558
+ approval is a list that has to be re-read to find the three rows that matter.
18559
+
18560
+ ${INPUT_CONTRACT}
18561
+
18562
+ ${outputContract("path:line - severity - what is wrong, and what it breaks", [
18563
+ "",
18564
+ "Severity is one of three words:",
18565
+ "",
18566
+ " bug - wrong behaviour reachable in ordinary use. Name the input that reaches it.",
18567
+ " risk - correct today, and depends on something the code does not state.",
18568
+ " nit - style or clarity. Include only when the file is otherwise clean.",
18569
+ "",
18570
+ "A finding you cannot reach with a concrete input is a risk, not a bug. Saying",
18571
+ "so is what keeps the bug rows worth reading."
18572
+ ])}`
18573
+ })];
18574
+ /**
18575
+ * Look one up by the name someone typed.
18576
+ *
18577
+ * Both spellings are accepted - `investigator` and `p4-investigator.md` - because
18578
+ * the listing shows the filename and the sentence people write is the bare word,
18579
+ * and refusing one of the two would be refusing whichever the person happened to
18580
+ * read most recently.
18581
+ */
18582
+ const findAgentPreset = (requested) => {
18583
+ const wanted = requested.trim().toLowerCase();
18584
+ if (wanted.length === 0) return void 0;
18585
+ return AGENT_PRESETS.find((preset) => {
18586
+ const fileName = preset.name.toLowerCase();
18587
+ const bare = fileName.slice(3, -3);
18588
+ return wanted === fileName || wanted === bare || wanted === `${PRESET_NAME_PREFIX}${bare}`;
18589
+ });
18590
+ };
18591
+ //#endregion
18106
18592
  //#region src/cli/assets.ts
18107
18593
  const SyncServicesLive = layer$54.pipe(Layer.provideMerge(layer$55), Layer.provideMerge(layer$56), Layer.provideMerge(layer$60.pipe(Layer.provide(layer$67))), Layer.provideMerge(layer$67), Layer.provideMerge(FetchHttpClient.layer));
18108
18594
  const runWithSync = (flags, run) => Effect.gen(function* () {
@@ -18146,6 +18632,14 @@ const MCP_WORDS = {
18146
18632
  rootLabel: "MCP",
18147
18633
  nameDescription: "Registration filename, for example linear.json."
18148
18634
  };
18635
+ const AGENT_WORDS = {
18636
+ kind: "agent",
18637
+ command: "agents",
18638
+ singular: "agent definition",
18639
+ plural: "agent definitions",
18640
+ rootLabel: "Agents",
18641
+ nameDescription: "Definition filename, for example p4-reviewer.md."
18642
+ };
18149
18643
  const rootFor = (status, kind) => status.roots.find((root) => root.kind === kind)?.path ?? null;
18150
18644
  /**
18151
18645
  * Exported for tests. These two are the only place a wrong report becomes a
@@ -18208,7 +18702,8 @@ const formatReport = (report) => {
18208
18702
  const ALL_WORDS = [
18209
18703
  SKILL_WORDS,
18210
18704
  MEMORY_WORDS,
18211
- MCP_WORDS
18705
+ MCP_WORDS,
18706
+ AGENT_WORDS
18212
18707
  ];
18213
18708
  /**
18214
18709
  * The whole picture, in one page.
@@ -18340,6 +18835,67 @@ const makeAssetCommands = (words) => {
18340
18835
  const skillCommands = makeAssetCommands(SKILL_WORDS);
18341
18836
  const memoryCommands = makeAssetCommands(MEMORY_WORDS);
18342
18837
  const mcpCommands = makeAssetCommands(MCP_WORDS);
18838
+ const agentCommands = makeAssetCommands(AGENT_WORDS);
18839
+ /**
18840
+ * What one install attempt did, in a sentence.
18841
+ *
18842
+ * Exported for tests: `exists` in particular must never read as success. The
18843
+ * whole point of refusing to overwrite is that someone who has edited a preset
18844
+ * keeps their edits, and a line saying "installed" would tell them the opposite.
18845
+ */
18846
+ const formatPresetInstall = (input) => {
18847
+ if (input.outcome === "created") return `Installed ${input.name}${input.path === null ? "" : ` at ${input.path}`}`;
18848
+ if (input.outcome === "exists") return `Skipped ${input.name}: it already exists here, and installing would overwrite your copy.`;
18849
+ return `Could not install ${input.name}: ${input.detail ?? input.outcome}`;
18850
+ };
18851
+ /**
18852
+ * `p4c agents presets` — what is on offer, before anything is written.
18853
+ *
18854
+ * Its own command rather than a flag on `install`, because reading the list is
18855
+ * what people do first and a listing that requires naming an install target is
18856
+ * not a listing.
18857
+ */
18858
+ const presetsCommand = Command.make("presets", { ...authLocationFlags }).pipe(Command.withDescription("List the agent definitions p4code ships, without installing any."), Command.withHandler(() => Console.log([
18859
+ ...AGENT_PRESETS.map((preset) => ` ${preset.name.padEnd(28)} ${preset.summary}`),
18860
+ "",
18861
+ "Install one with: p4c agents install <name>"
18862
+ ].join("\n"))));
18863
+ /**
18864
+ * Install a shipped definition onto this machine, and only this machine.
18865
+ *
18866
+ * `createLocal` rather than a hub write, so an installed preset starts out
18867
+ * exactly like one written by hand: local, unmanaged, and shared only when
18868
+ * something explicitly publishes it. It also means this works with no hub
18869
+ * configured, which is when a fresh machine most wants it.
18870
+ */
18871
+ const presetInstallCommand = Command.make("install", {
18872
+ ...authLocationFlags,
18873
+ name: Argument.string("name").pipe(Argument.withDescription("Preset to install, for example investigator."), Argument.optional),
18874
+ all: Flag.boolean("all").pipe(Flag.withDescription("Install every preset p4code ships."))
18875
+ }).pipe(Command.withDescription("Install a p4code agent definition into this machine's agents directory."), Command.withHandler((flags) => runWithSync(flags, ({ sync }) => Effect.gen(function* () {
18876
+ const requested = Option.getOrUndefined(flags.name);
18877
+ if (!flags.all && requested === void 0) return yield* Console.error("Name a preset, or pass --all to install every one.\nSee them with: p4c agents presets");
18878
+ const chosen = flags.all ? AGENT_PRESETS : (() => {
18879
+ const found = findAgentPreset(requested ?? "");
18880
+ return found === void 0 ? [] : [found];
18881
+ })();
18882
+ if (chosen.length === 0) return yield* Console.error(`No preset named ${requested ?? ""}. See them with: p4c agents presets`);
18883
+ const lines = [];
18884
+ for (const preset of chosen) {
18885
+ const result = yield* sync.createLocal({
18886
+ kind: AGENT_WORDS.kind,
18887
+ name: preset.name,
18888
+ files: preset.files
18889
+ });
18890
+ lines.push(formatPresetInstall({
18891
+ name: preset.name,
18892
+ outcome: result.outcome,
18893
+ path: result.path,
18894
+ detail: result.detail
18895
+ }));
18896
+ }
18897
+ return yield* Console.log(lines.join("\n"));
18898
+ }))));
18343
18899
  const shareAllCommand = Command.make("share-all", { ...authLocationFlags }).pipe(Command.withDescription("Share everything, including new items, automatically. The default."), Command.withHandler((flags) => runWithSync(flags, ({ sync, link }) => Effect.gen(function* () {
18344
18900
  yield* link.setShareMode("all");
18345
18901
  yield* Console.log(formatStatus(yield* sync.status));
@@ -18392,6 +18948,23 @@ const mcpCommand = Command.make("mcp", {}).pipe(Command.withDescription("Share M
18392
18948
  mcpCommands.showCommand,
18393
18949
  mcpCommands.removeCommand
18394
18950
  ]));
18951
+ /**
18952
+ * `p4c agents` — the subagent definitions this machine runs.
18953
+ *
18954
+ * The same six subcommands every kind gets, plus the two that are particular to
18955
+ * this one: p4code ships definitions, and a definition is the only place a
18956
+ * subagent's input and output contract can be stated.
18957
+ */
18958
+ const agentsCommand = Command.make("agents", {}).pipe(Command.withDescription("Share subagent definitions across your machines, and install p4code's."), Command.withSubcommands([
18959
+ agentCommands.statusCommand,
18960
+ agentCommands.syncCommand,
18961
+ agentCommands.publishCommand,
18962
+ agentCommands.unpublishCommand,
18963
+ agentCommands.showCommand,
18964
+ agentCommands.removeCommand,
18965
+ presetsCommand,
18966
+ presetInstallCommand
18967
+ ]));
18395
18968
  /** Exported for the hub command, which owns `connect`/`disconnect`. */
18396
18969
  const hubLinkCommands = [hubConnectCommand, hubDisconnectCommand];
18397
18970
  //#endregion
@@ -45796,12 +46369,12 @@ function decodeProviderDriverKind(providerName, operation) {
45796
46369
  cause
45797
46370
  })));
45798
46371
  }
45799
- function isRecord$3(value) {
46372
+ function isRecord$5(value) {
45800
46373
  return value !== null && typeof value === "object" && !Array.isArray(value);
45801
46374
  }
45802
46375
  function mergeRuntimePayload(existing, next) {
45803
46376
  if (next === void 0) return existing ?? null;
45804
- if (isRecord$3(existing) && isRecord$3(next)) return {
46377
+ if (isRecord$5(existing) && isRecord$5(next)) return {
45805
46378
  ...existing,
45806
46379
  ...next
45807
46380
  };
@@ -47066,6 +47639,7 @@ function buildServerProvider(input) {
47066
47639
  ...input.presentation.badgeLabel ? { badgeLabel: input.presentation.badgeLabel } : {},
47067
47640
  ...typeof input.presentation.showInteractionModeToggle === "boolean" ? { showInteractionModeToggle: input.presentation.showInteractionModeToggle } : {},
47068
47641
  ...typeof input.presentation.requiresNewThreadForModelChange === "boolean" ? { requiresNewThreadForModelChange: input.presentation.requiresNewThreadForModelChange } : {},
47642
+ ...input.presentation.supportedRuntimeModes ? { supportedRuntimeModes: input.presentation.supportedRuntimeModes } : {},
47069
47643
  enabled: input.enabled,
47070
47644
  installed: input.probe.installed,
47071
47645
  version: input.probe.version,
@@ -47522,7 +48096,7 @@ var OpenCodeRuntime = class extends Context.Service()("@p4code/cli/provider/open
47522
48096
  const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$71));
47523
48097
  //#endregion
47524
48098
  //#region src/textGeneration/TextGenerationUtils.ts
47525
- const isTextGenerationError$2 = Schema$1.is(TextGenerationError);
48099
+ const isTextGenerationError$3 = Schema$1.is(TextGenerationError);
47526
48100
  /** Convert an Effect Schema to a flat JSON Schema object, inlining `$defs` when present. */
47527
48101
  function toJsonSchemaObject(schema) {
47528
48102
  const document = Schema$1.toJsonSchemaDocument(schema);
@@ -47567,7 +48141,7 @@ function cliLabel(cliName) {
47567
48141
  * and Claude (and future providers) can share the same logic.
47568
48142
  */
47569
48143
  function normalizeCliError(cliName, operation, error, fallback) {
47570
- if (isTextGenerationError$2(error)) return error;
48144
+ if (isTextGenerationError$3(error)) return error;
47571
48145
  if (error instanceof Error) {
47572
48146
  const lower = error.message.toLowerCase();
47573
48147
  if (error.message.includes(`Command not found: ${cliName}`) || lower.includes(`spawn ${cliName}`) || lower.includes("enoent")) return new TextGenerationError({
@@ -49003,88 +49577,6 @@ function formatAskUserQuestionAnswers(answers) {
49003
49577
  return formatted;
49004
49578
  }
49005
49579
  //#endregion
49006
- //#region src/provider/CompressPrompts.ts
49007
- /**
49008
- * Caveman-style response compression rulesets, adapted from the caveman
49009
- * plugin's SKILL.md. Pre-baked per level so injection is a lookup, not a
49010
- * runtime template. Applies to assistant prose only: code blocks, commits,
49011
- * PRs, error strings, and safety-critical text stay uncompressed.
49012
- */
49013
- const COMPRESS_SHARED_RULES = `Respond terse. All technical substance stays. Only fluff dies.
49014
-
49015
- ## Persistence
49016
-
49017
- Active every response. No revert after many turns. No filler drift. Still active if unsure.
49018
-
49019
- ## Rules
49020
-
49021
- Drop filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Short synonyms (big not extensive, fix not "implement a solution for"). No tool-call narration, no decorative tables/emoji, no dumping long raw error logs unless asked - quote shortest decisive line. Standard well-known tech acronyms OK (DB/API/HTTP); never invent new abbreviations (cfg/impl/req/res/fn) - tokenizers split them same as the full word: zero tokens saved, reader still decodes. No causal arrows (->) in prose. Technical terms exact. Code blocks unchanged. Errors quoted exact.
49022
-
49023
- Preserve the user's dominant language: compress the style, not the language. Always keep technical terms, code, API names, CLI commands, commit-type keywords (feat/fix/...), and exact error strings verbatim unless the user explicitly asks for translation.
49024
-
49025
- No self-reference. Never name or announce the style. No compressed answer plus normal recap - compressed output only. Exception: user explicitly asks what the mode is.
49026
-
49027
- ## Auto-Clarity
49028
-
49029
- Drop compression and write normally when:
49030
- - Security warnings
49031
- - Irreversible action confirmations
49032
- - Multi-step sequences where fragment order or omitted conjunctions risk misread
49033
- - Compression itself creates technical ambiguity
49034
- - User asks to clarify or repeats a question
49035
-
49036
- Resume compression after the clear part is done.
49037
-
49038
- ## Boundaries
49039
-
49040
- Code, commit messages, and PR descriptions: write normal, uncompressed.`;
49041
- const COMPRESS_RULESETS = {
49042
- lite: `## Response compression: lite
49043
-
49044
- ${COMPRESS_SHARED_RULES}
49045
-
49046
- ## Intensity: lite
49047
-
49048
- No filler or hedging. Keep articles and full sentences. Professional but tight.
49049
-
49050
- Example - "Why does my React component re-render?"
49051
- "Your component re-renders because you create a new object reference each render. Wrap it in \`useMemo\`."`,
49052
- full: `## Response compression: full
49053
-
49054
- ${COMPRESS_SHARED_RULES}
49055
-
49056
- ## Intensity: full
49057
-
49058
- Drop articles (a/an/the), fragments OK, short synonyms. Pattern: [thing] [action] [reason]. [next step].
49059
-
49060
- Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
49061
- Yes: "Bug in auth middleware. Token expiry check use \`<\` not \`<=\`. Fix:"
49062
-
49063
- Example - "Why does my React component re-render?"
49064
- "New object ref each render. Inline object prop = new ref = re-render. Wrap in \`useMemo\`."`,
49065
- ultra: `## Response compression: ultra
49066
-
49067
- ${COMPRESS_SHARED_RULES}
49068
-
49069
- ## Intensity: ultra
49070
-
49071
- Drop articles, fragments OK, short synonyms. Also strip conjunctions when cause-then-effect stays unambiguous. One word when one word is enough. State each fact once. Code symbols, function names, API names, error strings: never touch.
49072
-
49073
- Example - "Why does my React component re-render?"
49074
- "Inline object prop, new ref, re-render. \`useMemo\`."`
49075
- };
49076
- const COMPRESS_TURN_REMINDERS = {
49077
- lite: "[response style: compressed lite - no filler/hedging, full sentences; code/commits/security text normal]",
49078
- full: "[response style: compressed full - terse fragments, drop articles/filler; code/commits/security text normal]",
49079
- ultra: "[response style: compressed ultra - maximum terseness, one word when enough; code/commits/security text normal]"
49080
- };
49081
- function compressRulesetFor(mode) {
49082
- return mode === "off" ? void 0 : COMPRESS_RULESETS[mode];
49083
- }
49084
- function compressTurnReminderFor(mode) {
49085
- return mode === "off" ? void 0 : COMPRESS_TURN_REMINDERS[mode];
49086
- }
49087
- //#endregion
49088
49580
  //#region src/provider/Layers/ClaudeAdapter.ts
49089
49581
  /**
49090
49582
  * ClaudeAdapterLive - Scoped live implementation for the Claude Agent provider adapter.
@@ -49096,7 +49588,7 @@ function compressTurnReminderFor(mode) {
49096
49588
  */
49097
49589
  const encodeUnknownJsonStringExit$2 = Schema$1.encodeUnknownExit(Schema$1.UnknownFromJsonString);
49098
49590
  const decodeUnknownJsonStringExit = Schema$1.decodeUnknownExit(Schema$1.UnknownFromJsonString);
49099
- const PROVIDER$5 = ProviderDriverKind.make("claudeAgent");
49591
+ const PROVIDER$6 = ProviderDriverKind.make("claudeAgent");
49100
49592
  function encodeJsonStringForDiagnostics$2(input) {
49101
49593
  const result = encodeUnknownJsonStringExit$2(input);
49102
49594
  return Exit.isSuccess(result) ? result.value : void 0;
@@ -49646,6 +50138,20 @@ const SUPPORTED_CLAUDE_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
49646
50138
  /** Emitted by the CLI but absent from the SDK's `SDKMessage` union. */
49647
50139
  const UNTYPED_COMMAND_LIFECYCLE_MESSAGE = "command_lifecycle";
49648
50140
  const NARRATE_BEFORE_TOOLS_PROMPT = "Before your first tool call in a turn, write one short sentence saying what you are about to do. Keep it to a single line and skip it when you are answering without tools.";
50141
+ /**
50142
+ * Said whichever way the setting is set, and said as an override.
50143
+ *
50144
+ * The preset system prompt this adapter requests already carries an
50145
+ * instruction not to spawn subagents unless the user asked — and a preset is
50146
+ * taken wholesale, so there is no version of it with that line removed. An
50147
+ * append that merely stayed silent when subagents are allowed would therefore
50148
+ * leave the restriction standing, which is the one outcome the setting exists
50149
+ * to change. Both texts name the earlier instruction they replace, because a
50150
+ * later instruction that does not acknowledge the conflict reads as an
50151
+ * accident rather than a decision.
50152
+ */
50153
+ const SUBAGENTS_ALLOWED_PROMPT = "You may spawn subagents with the Task tool whenever it helps, without asking the user first. This overrides any earlier instruction to use subagents only when they are requested. Prefer one for bounded search or review work whose result is much smaller than the reading it takes to produce; do the work inline when the answer is a single file or a single edit.";
50154
+ const SUBAGENTS_ON_REQUEST_PROMPT = "Do not spawn subagents with the Task tool unless the user asks for one. This overrides any earlier instruction permitting them on your own initiative. Do the work inline instead, and say so if it would have been better delegated.";
49649
50155
  const CLAUDE_SETTING_SOURCES = [
49650
50156
  "user",
49651
50157
  "project",
@@ -49704,7 +50210,7 @@ const buildUserMessageEffect = Effect.fn("buildUserMessageEffect")(function* (in
49704
50210
  for (const attachment of input.attachments ?? []) {
49705
50211
  if (attachment.type !== "image") continue;
49706
50212
  if (!SUPPORTED_CLAUDE_IMAGE_MIME_TYPES.has(attachment.mimeType)) return yield* new ProviderAdapterRequestError({
49707
- provider: PROVIDER$5,
50213
+ provider: PROVIDER$6,
49708
50214
  method: "turn/start",
49709
50215
  detail: `Unsupported Claude image attachment type '${attachment.mimeType}'.`
49710
50216
  });
@@ -49713,12 +50219,12 @@ const buildUserMessageEffect = Effect.fn("buildUserMessageEffect")(function* (in
49713
50219
  attachment
49714
50220
  });
49715
50221
  if (!attachmentPath) return yield* new ProviderAdapterRequestError({
49716
- provider: PROVIDER$5,
50222
+ provider: PROVIDER$6,
49717
50223
  method: "turn/start",
49718
50224
  detail: `Invalid attachment id '${attachment.id}'.`
49719
50225
  });
49720
50226
  const bytes = yield* dependencies.fileSystem.readFile(attachmentPath).pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
49721
- provider: PROVIDER$5,
50227
+ provider: PROVIDER$6,
49722
50228
  method: "turn/start",
49723
50229
  detail: "Failed to read attachment file.",
49724
50230
  cause
@@ -49816,12 +50322,12 @@ function toolResultBlocksFromUserMessage(message) {
49816
50322
  function toSessionError(threadId, cause) {
49817
50323
  const normalized = toMessage(cause, "").toLowerCase();
49818
50324
  if (normalized.includes("unknown session") || normalized.includes("not found")) return new ProviderAdapterSessionNotFoundError({
49819
- provider: PROVIDER$5,
50325
+ provider: PROVIDER$6,
49820
50326
  threadId,
49821
50327
  cause
49822
50328
  });
49823
50329
  if (normalized.includes("closed")) return new ProviderAdapterSessionClosedError({
49824
- provider: PROVIDER$5,
50330
+ provider: PROVIDER$6,
49825
50331
  threadId,
49826
50332
  cause
49827
50333
  });
@@ -49830,7 +50336,7 @@ function toRequestError$1(threadId, method, cause) {
49830
50336
  const sessionError = toSessionError(threadId, cause);
49831
50337
  if (sessionError) return sessionError;
49832
50338
  return new ProviderAdapterRequestError({
49833
- provider: PROVIDER$5,
50339
+ provider: PROVIDER$6,
49834
50340
  method,
49835
50341
  detail: `${method} failed`,
49836
50342
  cause
@@ -49874,6 +50380,25 @@ function sdkNativeMethod(message) {
49874
50380
  * would only duplicate a refresh that has already happened.
49875
50381
  */
49876
50382
  const CONSUMED_UNDECLARED_SYSTEM_SUBTYPES = /* @__PURE__ */ new Set(["background_tasks_changed", "vcs_state_changed"]);
50383
+ /**
50384
+ * Another undeclared-but-real subtype, emitted once the CLI has pushed the
50385
+ * turn's changes to a hosting provider:
50386
+ * `{provider: "github", url: "https://github.com/org/repo/pull/96",
50387
+ * repo: "org/repo", identifier: "96"}`. Mapped to `code.published` so the
50388
+ * work log links the pull request instead of logging an unknown-subtype
50389
+ * warning.
50390
+ */
50391
+ const CODE_CHANGE_PUBLISHED_SUBTYPE = "code_change_published";
50392
+ function codePublishedPayloadFromSdkMessage(message) {
50393
+ const record = message;
50394
+ if (typeof record.url !== "string" || record.url.length === 0) return;
50395
+ return {
50396
+ hostingProvider: typeof record.provider === "string" && record.provider.length > 0 ? record.provider : "unknown",
50397
+ url: record.url,
50398
+ ...typeof record.repo === "string" && record.repo.length > 0 ? { repo: record.repo } : {},
50399
+ ...typeof record.identifier === "string" && record.identifier.length > 0 ? { identifier: record.identifier } : {}
50400
+ };
50401
+ }
49877
50402
  const SDK_MESSAGE_NOISE_KEYS = /* @__PURE__ */ new Set([
49878
50403
  "type",
49879
50404
  "subtype",
@@ -49930,7 +50455,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
49930
50455
  const runtimeEventQueue = yield* Queue.unbounded();
49931
50456
  const nowIso = Effect.map(DateTime.now, DateTime.formatIso);
49932
50457
  const randomUUIDv4 = crypto.randomUUIDv4.pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
49933
- provider: PROVIDER$5,
50458
+ provider: PROVIDER$6,
49934
50459
  method: "crypto/randomUUIDv4",
49935
50460
  detail: "Failed to generate Claude runtime identifier.",
49936
50461
  cause
@@ -49950,7 +50475,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
49950
50475
  event: {
49951
50476
  id: "uuid" in message && typeof message.uuid === "string" ? message.uuid : yield* randomUUIDv4,
49952
50477
  kind: "notification",
49953
- provider: PROVIDER$5,
50478
+ provider: PROVIDER$6,
49954
50479
  createdAt: observedAt,
49955
50480
  method: sdkNativeMethod(message),
49956
50481
  ...typeof message.session_id === "string" ? { providerThreadId: message.session_id } : {},
@@ -49963,7 +50488,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
49963
50488
  const snapshotThread = Effect.fn("snapshotThread")(function* (context) {
49964
50489
  const threadId = context.session.threadId;
49965
50490
  if (!threadId) return yield* new ProviderAdapterValidationError({
49966
- provider: PROVIDER$5,
50491
+ provider: PROVIDER$6,
49967
50492
  operation: "readThread",
49968
50493
  issue: "Session thread id is not initialized yet."
49969
50494
  });
@@ -50036,7 +50561,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50036
50561
  yield* offerRuntimeEvent({
50037
50562
  type: "content.delta",
50038
50563
  eventId: deltaStamp.eventId,
50039
- provider: PROVIDER$5,
50564
+ provider: PROVIDER$6,
50040
50565
  createdAt: deltaStamp.createdAt,
50041
50566
  threadId: context.session.threadId,
50042
50567
  turnId: turnState.turnId,
@@ -50059,7 +50584,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50059
50584
  yield* offerRuntimeEvent({
50060
50585
  type: "item.completed",
50061
50586
  eventId: stamp.eventId,
50062
- provider: PROVIDER$5,
50587
+ provider: PROVIDER$6,
50063
50588
  createdAt: stamp.createdAt,
50064
50589
  itemId: asRuntimeItemId$1(block.itemId),
50065
50590
  threadId: context.session.threadId,
@@ -50113,7 +50638,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50113
50638
  yield* offerRuntimeEvent({
50114
50639
  type: "thread.started",
50115
50640
  eventId: stamp.eventId,
50116
- provider: PROVIDER$5,
50641
+ provider: PROVIDER$6,
50117
50642
  createdAt: stamp.createdAt,
50118
50643
  threadId: context.session.threadId,
50119
50644
  payload: { providerThreadId: nextThreadId },
@@ -50133,7 +50658,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50133
50658
  yield* offerRuntimeEvent({
50134
50659
  type: "runtime.error",
50135
50660
  eventId: stamp.eventId,
50136
- provider: PROVIDER$5,
50661
+ provider: PROVIDER$6,
50137
50662
  createdAt: stamp.createdAt,
50138
50663
  threadId: context.session.threadId,
50139
50664
  ...turnState ? { turnId: asCanonicalTurnId(turnState.turnId) } : {},
@@ -50151,7 +50676,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50151
50676
  yield* offerRuntimeEvent({
50152
50677
  type: "runtime.warning",
50153
50678
  eventId: stamp.eventId,
50154
- provider: PROVIDER$5,
50679
+ provider: PROVIDER$6,
50155
50680
  createdAt: stamp.createdAt,
50156
50681
  threadId: context.session.threadId,
50157
50682
  ...turnState ? { turnId: asCanonicalTurnId(turnState.turnId) } : {},
@@ -50171,7 +50696,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50171
50696
  yield* offerRuntimeEvent({
50172
50697
  type: "thread.token-usage.updated",
50173
50698
  eventId: stamp.eventId,
50174
- provider: PROVIDER$5,
50699
+ provider: PROVIDER$6,
50175
50700
  createdAt: stamp.createdAt,
50176
50701
  threadId: context.session.threadId,
50177
50702
  ...turnState ? { turnId: turnState.turnId } : {},
@@ -50224,7 +50749,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50224
50749
  yield* offerRuntimeEvent({
50225
50750
  type: "turn.proposed.completed",
50226
50751
  eventId: stamp.eventId,
50227
- provider: PROVIDER$5,
50752
+ provider: PROVIDER$6,
50228
50753
  createdAt: stamp.createdAt,
50229
50754
  threadId: context.session.threadId,
50230
50755
  turnId: turnState.turnId,
@@ -50244,7 +50769,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50244
50769
  yield* offerRuntimeEvent({
50245
50770
  type: "turn.plan.updated",
50246
50771
  eventId: stamp.eventId,
50247
- provider: PROVIDER$5,
50772
+ provider: PROVIDER$6,
50248
50773
  createdAt: stamp.createdAt,
50249
50774
  threadId: context.session.threadId,
50250
50775
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -50292,7 +50817,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50292
50817
  yield* offerRuntimeEvent({
50293
50818
  type: "turn.completed",
50294
50819
  eventId: stamp.eventId,
50295
- provider: PROVIDER$5,
50820
+ provider: PROVIDER$6,
50296
50821
  createdAt: stamp.createdAt,
50297
50822
  threadId: context.session.threadId,
50298
50823
  payload: {
@@ -50312,7 +50837,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50312
50837
  yield* offerRuntimeEvent({
50313
50838
  type: "item.completed",
50314
50839
  eventId: toolStamp.eventId,
50315
- provider: PROVIDER$5,
50840
+ provider: PROVIDER$6,
50316
50841
  createdAt: toolStamp.createdAt,
50317
50842
  threadId: context.session.threadId,
50318
50843
  turnId: turnState.turnId,
@@ -50355,7 +50880,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50355
50880
  yield* offerRuntimeEvent({
50356
50881
  type: "turn.completed",
50357
50882
  eventId: stamp.eventId,
50358
- provider: PROVIDER$5,
50883
+ provider: PROVIDER$6,
50359
50884
  createdAt: stamp.createdAt,
50360
50885
  threadId: context.session.threadId,
50361
50886
  turnId: turnState.turnId,
@@ -50429,7 +50954,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50429
50954
  yield* offerRuntimeEvent({
50430
50955
  type: "turn.started",
50431
50956
  eventId: turnStartedStamp.eventId,
50432
- provider: PROVIDER$5,
50957
+ provider: PROVIDER$6,
50433
50958
  createdAt: turnStartedStamp.createdAt,
50434
50959
  threadId: context.session.threadId,
50435
50960
  turnId,
@@ -50509,7 +51034,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50509
51034
  yield* offerRuntimeEvent({
50510
51035
  type: "content.delta",
50511
51036
  eventId: stamp.eventId,
50512
- provider: PROVIDER$5,
51037
+ provider: PROVIDER$6,
50513
51038
  createdAt: stamp.createdAt,
50514
51039
  threadId: context.session.threadId,
50515
51040
  turnId: context.turnState.turnId,
@@ -50553,7 +51078,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50553
51078
  yield* offerRuntimeEvent({
50554
51079
  type: "item.updated",
50555
51080
  eventId: stamp.eventId,
50556
- provider: PROVIDER$5,
51081
+ provider: PROVIDER$6,
50557
51082
  createdAt: stamp.createdAt,
50558
51083
  threadId: context.session.threadId,
50559
51084
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -50583,7 +51108,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50583
51108
  yield* offerRuntimeEvent({
50584
51109
  type: "turn.plan.updated",
50585
51110
  eventId: planStamp.eventId,
50586
- provider: PROVIDER$5,
51111
+ provider: PROVIDER$6,
50587
51112
  createdAt: planStamp.createdAt,
50588
51113
  threadId: context.session.threadId,
50589
51114
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -50623,7 +51148,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50623
51148
  yield* offerRuntimeEvent({
50624
51149
  type: "item.started",
50625
51150
  eventId: stamp.eventId,
50626
- provider: PROVIDER$5,
51151
+ provider: PROVIDER$6,
50627
51152
  createdAt: stamp.createdAt,
50628
51153
  threadId: context.session.threadId,
50629
51154
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -50681,7 +51206,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50681
51206
  yield* offerRuntimeEvent({
50682
51207
  type: "item.updated",
50683
51208
  eventId: updatedStamp.eventId,
50684
- provider: PROVIDER$5,
51209
+ provider: PROVIDER$6,
50685
51210
  createdAt: updatedStamp.createdAt,
50686
51211
  threadId: context.session.threadId,
50687
51212
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -50706,7 +51231,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50706
51231
  yield* offerRuntimeEvent({
50707
51232
  type: "content.delta",
50708
51233
  eventId: deltaStamp.eventId,
50709
- provider: PROVIDER$5,
51234
+ provider: PROVIDER$6,
50710
51235
  createdAt: deltaStamp.createdAt,
50711
51236
  threadId: context.session.threadId,
50712
51237
  turnId: context.turnState.turnId,
@@ -50727,7 +51252,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50727
51252
  yield* offerRuntimeEvent({
50728
51253
  type: "item.completed",
50729
51254
  eventId: completedStamp.eventId,
50730
- provider: PROVIDER$5,
51255
+ provider: PROVIDER$6,
50731
51256
  createdAt: completedStamp.createdAt,
50732
51257
  threadId: context.session.threadId,
50733
51258
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -50779,7 +51304,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50779
51304
  yield* offerRuntimeEvent({
50780
51305
  type: "turn.started",
50781
51306
  eventId: turnStartedStamp.eventId,
50782
- provider: PROVIDER$5,
51307
+ provider: PROVIDER$6,
50783
51308
  createdAt: turnStartedStamp.createdAt,
50784
51309
  threadId: context.session.threadId,
50785
51310
  turnId,
@@ -50832,7 +51357,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50832
51357
  const stamp = yield* makeEventStamp();
50833
51358
  const base = {
50834
51359
  eventId: stamp.eventId,
50835
- provider: PROVIDER$5,
51360
+ provider: PROVIDER$6,
50836
51361
  createdAt: stamp.createdAt,
50837
51362
  threadId: context.session.threadId,
50838
51363
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -50845,6 +51370,17 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50845
51370
  }
50846
51371
  };
50847
51372
  if (CONSUMED_UNDECLARED_SYSTEM_SUBTYPES.has(message.subtype)) return;
51373
+ if (message.subtype === CODE_CHANGE_PUBLISHED_SUBTYPE) {
51374
+ const published = codePublishedPayloadFromSdkMessage(message);
51375
+ if (published) {
51376
+ yield* offerRuntimeEvent({
51377
+ ...base,
51378
+ type: "code.published",
51379
+ payload: published
51380
+ });
51381
+ return;
51382
+ }
51383
+ }
50848
51384
  switch (message.subtype) {
50849
51385
  case "init":
50850
51386
  yield* offerRuntimeEvent({
@@ -51035,7 +51571,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51035
51571
  const stamp = yield* makeEventStamp();
51036
51572
  const base = {
51037
51573
  eventId: stamp.eventId,
51038
- provider: PROVIDER$5,
51574
+ provider: PROVIDER$6,
51039
51575
  createdAt: stamp.createdAt,
51040
51576
  threadId: context.session.threadId,
51041
51577
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -51125,12 +51661,12 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51125
51661
  }
51126
51662
  });
51127
51663
  const runSdkStream = (context) => Stream.fromAsyncIterable(context.query, (cause) => new ProviderAdapterProcessError({
51128
- provider: PROVIDER$5,
51664
+ provider: PROVIDER$6,
51129
51665
  threadId: context.session.threadId,
51130
51666
  detail: "Claude runtime stream failed.",
51131
51667
  cause
51132
51668
  })).pipe(Stream.takeWhile(() => !context.stopped), Stream.runForEach((message) => handleSdkMessage(context, message).pipe(Effect.mapError((cause) => new ProviderAdapterProcessError({
51133
- provider: PROVIDER$5,
51669
+ provider: PROVIDER$6,
51134
51670
  threadId: context.session.threadId,
51135
51671
  detail: "Failed to process Claude runtime event.",
51136
51672
  cause
@@ -51160,7 +51696,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51160
51696
  yield* offerRuntimeEvent({
51161
51697
  type: "request.resolved",
51162
51698
  eventId: stamp.eventId,
51163
- provider: PROVIDER$5,
51699
+ provider: PROVIDER$6,
51164
51700
  createdAt: stamp.createdAt,
51165
51701
  threadId: context.session.threadId,
51166
51702
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -51181,7 +51717,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51181
51717
  yield* Effect.try({
51182
51718
  try: () => context.query.close(),
51183
51719
  catch: (cause) => new ProviderAdapterProcessError({
51184
- provider: PROVIDER$5,
51720
+ provider: PROVIDER$6,
51185
51721
  threadId: context.session.threadId,
51186
51722
  detail: "Failed to close Claude runtime query.",
51187
51723
  cause
@@ -51204,7 +51740,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51204
51740
  yield* offerRuntimeEvent({
51205
51741
  type: "session.exited",
51206
51742
  eventId: stamp.eventId,
51207
- provider: PROVIDER$5,
51743
+ provider: PROVIDER$6,
51208
51744
  createdAt: stamp.createdAt,
51209
51745
  threadId: context.session.threadId,
51210
51746
  payload: {
@@ -51219,20 +51755,20 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51219
51755
  const requireSession = (threadId) => {
51220
51756
  const context = sessions.get(threadId);
51221
51757
  if (!context) return Effect.fail(new ProviderAdapterSessionNotFoundError({
51222
- provider: PROVIDER$5,
51758
+ provider: PROVIDER$6,
51223
51759
  threadId
51224
51760
  }));
51225
51761
  if (context.stopped || context.session.status === "closed") return Effect.fail(new ProviderAdapterSessionClosedError({
51226
- provider: PROVIDER$5,
51762
+ provider: PROVIDER$6,
51227
51763
  threadId
51228
51764
  }));
51229
51765
  return Effect.succeed(context);
51230
51766
  };
51231
51767
  const startSession = Effect.fn("startSession")(function* (input) {
51232
- if (input.provider !== void 0 && input.provider !== PROVIDER$5) return yield* new ProviderAdapterValidationError({
51233
- provider: PROVIDER$5,
51768
+ if (input.provider !== void 0 && input.provider !== PROVIDER$6) return yield* new ProviderAdapterValidationError({
51769
+ provider: PROVIDER$6,
51234
51770
  operation: "startSession",
51235
- issue: `Expected provider '${PROVIDER$5}' but received '${input.provider}'.`
51771
+ issue: `Expected provider '${PROVIDER$6}' but received '${input.provider}'.`
51236
51772
  });
51237
51773
  const existingContext = sessions.get(input.threadId);
51238
51774
  if (existingContext) {
@@ -51288,7 +51824,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51288
51824
  yield* offerRuntimeEvent({
51289
51825
  type: "user-input.requested",
51290
51826
  eventId: requestedStamp.eventId,
51291
- provider: PROVIDER$5,
51827
+ provider: PROVIDER$6,
51292
51828
  createdAt: requestedStamp.createdAt,
51293
51829
  threadId: context.session.threadId,
51294
51830
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -51318,7 +51854,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51318
51854
  yield* offerRuntimeEvent({
51319
51855
  type: "user-input.resolved",
51320
51856
  eventId: resolvedStamp.eventId,
51321
- provider: PROVIDER$5,
51857
+ provider: PROVIDER$6,
51322
51858
  createdAt: resolvedStamp.createdAt,
51323
51859
  threadId: context.session.threadId,
51324
51860
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -51385,7 +51921,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51385
51921
  yield* offerRuntimeEvent({
51386
51922
  type: "request.opened",
51387
51923
  eventId: requestedStamp.eventId,
51388
- provider: PROVIDER$5,
51924
+ provider: PROVIDER$6,
51389
51925
  createdAt: requestedStamp.createdAt,
51390
51926
  threadId: context.session.threadId,
51391
51927
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -51422,7 +51958,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51422
51958
  yield* offerRuntimeEvent({
51423
51959
  type: "request.resolved",
51424
51960
  eventId: resolvedStamp.eventId,
51425
- provider: PROVIDER$5,
51961
+ provider: PROVIDER$6,
51426
51962
  createdAt: resolvedStamp.createdAt,
51427
51963
  threadId: context.session.threadId,
51428
51964
  ...context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {},
@@ -51479,8 +52015,13 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51479
52015
  const mcpSession = readMcpProviderSession(input.threadId);
51480
52016
  const externalMcpServers = options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers;
51481
52017
  const narrateBeforeTools = options?.resolveToolCallNarration === void 0 ? DEFAULT_SERVER_SETTINGS.enableToolCallNarration : yield* options.resolveToolCallNarration;
52018
+ const unpromptedSubagents = options?.resolveUnpromptedSubagents === void 0 ? DEFAULT_SERVER_SETTINGS.enableUnpromptedSubagents : yield* options.resolveUnpromptedSubagents;
51482
52019
  const compressRuleset = compressRulesetFor(input.compressMode ?? "off");
51483
- const systemPromptAppend = [...narrateBeforeTools ? [NARRATE_BEFORE_TOOLS_PROMPT] : [], ...compressRuleset !== void 0 ? [compressRuleset] : []].join("\n\n");
52020
+ const systemPromptAppend = [
52021
+ ...narrateBeforeTools ? [NARRATE_BEFORE_TOOLS_PROMPT] : [],
52022
+ unpromptedSubagents ? SUBAGENTS_ALLOWED_PROMPT : SUBAGENTS_ON_REQUEST_PROMPT,
52023
+ ...compressRuleset !== void 0 ? [compressRuleset] : []
52024
+ ].join("\n\n");
51484
52025
  const queryOptions = {
51485
52026
  ...input.cwd ? { cwd: input.cwd } : {},
51486
52027
  ...apiModelId ? { model: apiModelId } : {},
@@ -51512,7 +52053,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51512
52053
  } } : {}
51513
52054
  };
51514
52055
  yield* Effect.annotateCurrentSpan({
51515
- "provider.kind": PROVIDER$5,
52056
+ "provider.kind": PROVIDER$6,
51516
52057
  "provider.thread_id": threadId,
51517
52058
  "provider.runtime_mode": input.runtimeMode,
51518
52059
  "claude.resume.source": existingResumeSessionId !== void 0 ? "resume-session" : "generated-session",
@@ -51541,7 +52082,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51541
52082
  options: queryOptions
51542
52083
  }),
51543
52084
  catch: (cause) => new ProviderAdapterProcessError({
51544
- provider: PROVIDER$5,
52085
+ provider: PROVIDER$6,
51545
52086
  threadId,
51546
52087
  detail: "Failed to start Claude runtime session.",
51547
52088
  cause
@@ -51549,7 +52090,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51549
52090
  });
51550
52091
  const session = {
51551
52092
  threadId,
51552
- provider: PROVIDER$5,
52093
+ provider: PROVIDER$6,
51553
52094
  providerInstanceId: boundInstanceId,
51554
52095
  status: "ready",
51555
52096
  runtimeMode: input.runtimeMode,
@@ -51596,7 +52137,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51596
52137
  yield* offerRuntimeEvent({
51597
52138
  type: "session.started",
51598
52139
  eventId: sessionStartedStamp.eventId,
51599
- provider: PROVIDER$5,
52140
+ provider: PROVIDER$6,
51600
52141
  createdAt: sessionStartedStamp.createdAt,
51601
52142
  threadId,
51602
52143
  payload: input.resumeCursor !== void 0 ? { resume: input.resumeCursor } : {},
@@ -51606,7 +52147,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51606
52147
  yield* offerRuntimeEvent({
51607
52148
  type: "session.configured",
51608
52149
  eventId: configuredStamp.eventId,
51609
- provider: PROVIDER$5,
52150
+ provider: PROVIDER$6,
51610
52151
  createdAt: configuredStamp.createdAt,
51611
52152
  threadId,
51612
52153
  payload: { config: {
@@ -51622,7 +52163,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51622
52163
  yield* offerRuntimeEvent({
51623
52164
  type: "session.state.changed",
51624
52165
  eventId: readyStamp.eventId,
51625
- provider: PROVIDER$5,
52166
+ provider: PROVIDER$6,
51626
52167
  createdAt: readyStamp.createdAt,
51627
52168
  threadId,
51628
52169
  payload: { state: "ready" },
@@ -51703,7 +52244,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51703
52244
  const context = yield* requireSession(threadId);
51704
52245
  const pending = context.pendingApprovals.get(requestId);
51705
52246
  if (!pending) return yield* new ProviderAdapterRequestError({
51706
- provider: PROVIDER$5,
52247
+ provider: PROVIDER$6,
51707
52248
  method: "item/requestApproval/decision",
51708
52249
  detail: `Unknown pending approval request: ${requestId}`
51709
52250
  });
@@ -51714,7 +52255,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51714
52255
  const context = yield* requireSession(threadId);
51715
52256
  const pending = context.pendingUserInputs.get(requestId);
51716
52257
  if (!pending) return yield* new ProviderAdapterRequestError({
51717
- provider: PROVIDER$5,
52258
+ provider: PROVIDER$6,
51718
52259
  method: "item/tool/respondToUserInput",
51719
52260
  detail: `Unknown pending user-input request: ${requestId}`
51720
52261
  });
@@ -51733,7 +52274,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
51733
52274
  const stopAll = () => Effect.forEach(sessions, ([, context]) => stopSessionInternal(context, { emitExitEvent: true }), { discard: true });
51734
52275
  yield* Effect.addFinalizer(() => Effect.forEach(sessions, ([, context]) => stopSessionInternal(context, { emitExitEvent: false }), { discard: true }).pipe(Effect.catch((cause) => Effect.logError("Failed to emit Claude session shutdown event.", { cause })), Effect.tap(() => Queue.shutdown(runtimeEventQueue))));
51735
52276
  return {
51736
- provider: PROVIDER$5,
52277
+ provider: PROVIDER$6,
51737
52278
  capabilities: { sessionModelSwitch: "in-session" },
51738
52279
  startSession,
51739
52280
  sendTurn,
@@ -51877,15 +52418,15 @@ function makeProviderSnapshotSettingsSource(provider, serverSettings) {
51877
52418
  * @module provider/Drivers/ClaudeDriver
51878
52419
  */
51879
52420
  const decodeClaudeSettings = Schema$1.decodeSync(ClaudeSettings);
51880
- const DRIVER_KIND$4 = ProviderDriverKind.make("claudeAgent");
51881
- const SNAPSHOT_REFRESH_INTERVAL$4 = Duration.minutes(5);
52421
+ const DRIVER_KIND$5 = ProviderDriverKind.make("claudeAgent");
52422
+ const SNAPSHOT_REFRESH_INTERVAL$5 = Duration.minutes(5);
51882
52423
  const CAPABILITIES_PROBE_TTL = Duration.minutes(5);
51883
52424
  function isClaudeNativeCommandPath(commandPath) {
51884
52425
  const normalized = normalizeCommandPath(commandPath);
51885
52426
  return normalized.endsWith("/.local/bin/claude") || normalized.endsWith("/.local/bin/claude.exe") || normalized.includes("/.local/share/claude/");
51886
52427
  }
51887
- const UPDATE$4 = makePackageManagedProviderMaintenanceResolver({
51888
- provider: DRIVER_KIND$4,
52428
+ const UPDATE$5 = makePackageManagedProviderMaintenanceResolver({
52429
+ provider: DRIVER_KIND$5,
51889
52430
  npmPackageName: "@anthropic-ai/claude-code",
51890
52431
  homebrewFormula: "claude-code",
51891
52432
  nativeUpdate: {
@@ -51895,16 +52436,16 @@ const UPDATE$4 = makePackageManagedProviderMaintenanceResolver({
51895
52436
  isCommandPath: isClaudeNativeCommandPath
51896
52437
  }
51897
52438
  });
51898
- const withInstanceIdentity$4 = (input) => (snapshot) => ({
52439
+ const withInstanceIdentity$5 = (input) => (snapshot) => ({
51899
52440
  ...snapshot,
51900
52441
  instanceId: input.instanceId,
51901
- driver: DRIVER_KIND$4,
52442
+ driver: DRIVER_KIND$5,
51902
52443
  ...input.displayName ? { displayName: input.displayName } : {},
51903
52444
  ...input.accentColor ? { accentColor: input.accentColor } : {},
51904
52445
  continuation: { groupKey: input.continuationGroupKey }
51905
52446
  });
51906
52447
  const ClaudeDriver = {
51907
- driverKind: DRIVER_KIND$4,
52448
+ driverKind: DRIVER_KIND$5,
51908
52449
  metadata: {
51909
52450
  displayName: "Claude",
51910
52451
  supportsMultipleInstances: true
@@ -51921,19 +52462,19 @@ const ClaudeDriver = {
51921
52462
  const eventLoggers = yield* ProviderEventLoggers;
51922
52463
  const processEnv = mergeProviderInstanceEnvironment(environment);
51923
52464
  const fallbackContinuationIdentity = defaultProviderContinuationIdentity({
51924
- driverKind: DRIVER_KIND$4,
52465
+ driverKind: DRIVER_KIND$5,
51925
52466
  instanceId
51926
52467
  });
51927
52468
  const effectiveConfig = {
51928
52469
  ...config,
51929
52470
  enabled
51930
52471
  };
51931
- const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$4, {
52472
+ const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$5, {
51932
52473
  binaryPath: effectiveConfig.binaryPath,
51933
52474
  env: processEnv
51934
52475
  });
51935
52476
  const continuationGroupKey = yield* makeClaudeContinuationGroupKey(effectiveConfig);
51936
- const stampIdentity = withInstanceIdentity$4({
52477
+ const stampIdentity = withInstanceIdentity$5({
51937
52478
  instanceId,
51938
52479
  displayName,
51939
52480
  accentColor,
@@ -51942,12 +52483,14 @@ const ClaudeDriver = {
51942
52483
  const mcpRegistry = yield* McpRegistry;
51943
52484
  const resolveDisabledSkills = serverSettings.getSettings.pipe(Effect.map((settings) => settings.disabledSkills), Effect.orElseSucceed(() => []));
51944
52485
  const resolveToolCallNarration = serverSettings.getSettings.pipe(Effect.map((settings) => settings.enableToolCallNarration), Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS.enableToolCallNarration));
52486
+ const resolveUnpromptedSubagents = serverSettings.getSettings.pipe(Effect.map((settings) => settings.enableUnpromptedSubagents), Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS.enableUnpromptedSubagents));
51945
52487
  const adapter = yield* makeClaudeAdapter(effectiveConfig, {
51946
52488
  instanceId,
51947
52489
  environment: processEnv,
51948
52490
  resolveMcpServers: mcpRegistry.resolveForSession,
51949
52491
  resolveDisabledSkills,
51950
52492
  resolveToolCallNarration,
52493
+ resolveUnpromptedSubagents,
51951
52494
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}
51952
52495
  });
51953
52496
  const textGeneration = yield* makeClaudeTextGeneration(effectiveConfig, processEnv);
@@ -51967,16 +52510,16 @@ const ClaudeDriver = {
51967
52510
  initialSnapshot: (settings) => makePendingClaudeProvider(settings.provider).pipe(Effect.map(stampIdentity)),
51968
52511
  checkProvider,
51969
52512
  enrichSnapshot: ({ settings, snapshot, publishSnapshot }) => enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities, { enableProviderUpdateChecks: settings.enableProviderUpdateChecks }).pipe(Effect.provideService(HttpClient.HttpClient, httpClient), Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot))),
51970
- refreshInterval: SNAPSHOT_REFRESH_INTERVAL$4
52513
+ refreshInterval: SNAPSHOT_REFRESH_INTERVAL$5
51971
52514
  }).pipe(Effect.mapError((cause) => new ProviderDriverError({
51972
- driver: DRIVER_KIND$4,
52515
+ driver: DRIVER_KIND$5,
51973
52516
  instanceId,
51974
52517
  detail: `Failed to build Claude snapshot: ${cause.message ?? String(cause)}`,
51975
52518
  cause
51976
52519
  })));
51977
52520
  return {
51978
52521
  instanceId,
51979
- driverKind: DRIVER_KIND$4,
52522
+ driverKind: DRIVER_KIND$5,
51980
52523
  continuationIdentity: {
51981
52524
  ...fallbackContinuationIdentity,
51982
52525
  continuationKey: continuationGroupKey
@@ -70810,7 +71353,7 @@ function buildCodexDeveloperInstructions(interactionMode, runtime, compressMode)
70810
71353
  //#endregion
70811
71354
  //#region src/provider/Layers/CodexSessionRuntime.ts
70812
71355
  const decodeV2TurnStartResponse = Schema$1.decodeUnknownEffect(V2TurnStartResponse);
70813
- const PROVIDER$4 = ProviderDriverKind.make("codex");
71356
+ const PROVIDER$5 = ProviderDriverKind.make("codex");
70814
71357
  const ANSI_ESCAPE_REGEX = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
70815
71358
  const CODEX_STDERR_LOG_REGEX = /^\d{4}-\d{2}-\d{2}T\S+\s+(TRACE|DEBUG|INFO|WARN|ERROR)\s+\S+:\s+(.*)$/;
70816
71359
  const BENIGN_ERROR_LOG_SNIPPETS = ["state db missing rollout path for thread", "state db record_discrepancy: find_thread_path_by_id_str_in_subdir, falling_back"];
@@ -71162,7 +71705,7 @@ const makeCodexSessionRuntime = (options) => Effect.gen(function* () {
71162
71705
  })));
71163
71706
  const sessionCreatedAt = yield* nowIso;
71164
71707
  const initialSession = {
71165
- provider: PROVIDER$4,
71708
+ provider: PROVIDER$5,
71166
71709
  ...options.providerInstanceId ? { providerInstanceId: options.providerInstanceId } : {},
71167
71710
  status: "connecting",
71168
71711
  runtimeMode: options.runtimeMode,
@@ -71179,7 +71722,7 @@ const makeCodexSessionRuntime = (options) => Effect.gen(function* () {
71179
71722
  const id = yield* randomUUIDv4("provider-event");
71180
71723
  return yield* offerEvent({
71181
71724
  id: EventId.make(id),
71182
- provider: PROVIDER$4,
71725
+ provider: PROVIDER$5,
71183
71726
  ...options.providerInstanceId ? { providerInstanceId: options.providerInstanceId } : {},
71184
71727
  createdAt: yield* nowIso,
71185
71728
  ...event
@@ -71584,20 +72127,20 @@ const isCodexAppServerProcessExitedError = Schema$1.is(CodexAppServerProcessExit
71584
72127
  const isCodexAppServerTransportError = Schema$1.is(CodexAppServerTransportError);
71585
72128
  const isCodexSessionRuntimeThreadIdMissingError = Schema$1.is(CodexSessionRuntimeThreadIdMissingError);
71586
72129
  const isCodexResumeCursorSchema = Schema$1.is(CodexResumeCursorSchema);
71587
- const PROVIDER$3 = ProviderDriverKind.make("codex");
72130
+ const PROVIDER$4 = ProviderDriverKind.make("codex");
71588
72131
  function mapCodexRuntimeError(threadId, method, error) {
71589
72132
  if (isCodexAppServerProcessExitedError(error) || isCodexAppServerTransportError(error)) return new ProviderAdapterSessionClosedError({
71590
- provider: PROVIDER$3,
72133
+ provider: PROVIDER$4,
71591
72134
  threadId,
71592
72135
  cause: error
71593
72136
  });
71594
72137
  if (isCodexSessionRuntimeThreadIdMissingError(error)) return new ProviderAdapterSessionNotFoundError({
71595
- provider: PROVIDER$3,
72138
+ provider: PROVIDER$4,
71596
72139
  threadId,
71597
72140
  cause: error
71598
72141
  });
71599
72142
  return new ProviderAdapterRequestError({
71600
- provider: PROVIDER$3,
72143
+ provider: PROVIDER$4,
71601
72144
  method,
71602
72145
  detail: error.message,
71603
72146
  cause: error
@@ -72362,10 +72905,10 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
72362
72905
  const runtimeEventQueue = yield* Queue.unbounded();
72363
72906
  const sessions = /* @__PURE__ */ new Map();
72364
72907
  const startSession = (input) => Effect.scoped(Effect.gen(function* () {
72365
- if (input.provider !== void 0 && input.provider !== PROVIDER$3) return yield* new ProviderAdapterValidationError({
72366
- provider: PROVIDER$3,
72908
+ if (input.provider !== void 0 && input.provider !== PROVIDER$4) return yield* new ProviderAdapterValidationError({
72909
+ provider: PROVIDER$4,
72367
72910
  operation: "startSession",
72368
- issue: `Expected provider '${PROVIDER$3}' but received '${input.provider}'.`
72911
+ issue: `Expected provider '${PROVIDER$4}' but received '${input.provider}'.`
72369
72912
  });
72370
72913
  const existing = sessions.get(input.threadId);
72371
72914
  if (existing && !existing.stopped) yield* Effect.suspend(() => stopSessionInternal(existing));
@@ -72400,7 +72943,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
72400
72943
  let sessionScopeTransferred = false;
72401
72944
  yield* Effect.addFinalizer(() => sessionScopeTransferred ? Effect.void : Scope.close(sessionScope, Exit.void));
72402
72945
  const runtime = yield* (options?.makeRuntime ?? makeCodexSessionRuntime)(runtimeInput).pipe(Effect.provideService(Scope.Scope, sessionScope), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, childProcessSpawner), Effect.provideService(Crypto.Crypto, crypto), Effect.mapError((cause) => new ProviderAdapterProcessError({
72403
- provider: PROVIDER$3,
72946
+ provider: PROVIDER$4,
72404
72947
  threadId: input.threadId,
72405
72948
  detail: cause.message,
72406
72949
  cause
@@ -72420,7 +72963,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
72420
72963
  yield* Queue.offerAll(runtimeEventQueue, runtimeEvents);
72421
72964
  })).pipe(Effect.forkChild);
72422
72965
  const started = yield* runtime.start().pipe(Effect.mapError((cause) => new ProviderAdapterProcessError({
72423
- provider: PROVIDER$3,
72966
+ provider: PROVIDER$4,
72424
72967
  threadId: input.threadId,
72425
72968
  detail: cause.message,
72426
72969
  cause
@@ -72441,12 +72984,12 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
72441
72984
  attachment
72442
72985
  });
72443
72986
  if (!attachmentPath) return yield* new ProviderAdapterRequestError({
72444
- provider: PROVIDER$3,
72987
+ provider: PROVIDER$4,
72445
72988
  method: "turn/start",
72446
72989
  detail: `Invalid attachment id '${attachment.id}'.`
72447
72990
  });
72448
72991
  const bytes = yield* fileSystem.readFile(attachmentPath).pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
72449
- provider: PROVIDER$3,
72992
+ provider: PROVIDER$4,
72450
72993
  method: "turn/start",
72451
72994
  detail: `Failed to read attachment file: ${cause.message}.`,
72452
72995
  cause
@@ -72474,7 +73017,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
72474
73017
  const requireSession = Effect.fn("requireSession")(function* (threadId) {
72475
73018
  const session = sessions.get(threadId);
72476
73019
  if (!session || session.stopped) return yield* new ProviderAdapterSessionNotFoundError({
72477
- provider: PROVIDER$3,
73020
+ provider: PROVIDER$4,
72478
73021
  threadId
72479
73022
  });
72480
73023
  return session;
@@ -72486,7 +73029,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
72486
73029
  })));
72487
73030
  const rollbackThread = (threadId, numTurns) => {
72488
73031
  if (!Number.isInteger(numTurns) || numTurns < 1) return Effect.fail(new ProviderAdapterValidationError({
72489
- provider: PROVIDER$3,
73032
+ provider: PROVIDER$4,
72490
73033
  operation: "rollbackThread",
72491
73034
  issue: "numTurns must be an integer >= 1."
72492
73035
  }));
@@ -72522,7 +73065,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
72522
73065
  }).pipe(Effect.asVoid);
72523
73066
  yield* Effect.acquireRelease(Effect.void, () => stopAll().pipe(Effect.andThen(Queue.shutdown(runtimeEventQueue)), Effect.andThen(managedNativeEventLogger?.close() ?? Effect.void), Effect.ignore));
72524
73067
  return {
72525
- provider: PROVIDER$3,
73068
+ provider: PROVIDER$4,
72526
73069
  capabilities: { sessionModelSwitch: "in-session" },
72527
73070
  startSession,
72528
73071
  sendTurn,
@@ -72817,8 +73360,8 @@ function codexContinuationIdentity(layout) {
72817
73360
  * @module provider/Drivers/CodexDriver
72818
73361
  */
72819
73362
  const decodeCodexSettings = Schema$1.decodeSync(CodexSettings);
72820
- const DRIVER_KIND$3 = ProviderDriverKind.make("codex");
72821
- const SNAPSHOT_REFRESH_INTERVAL$3 = Duration.minutes(5);
73363
+ const DRIVER_KIND$4 = ProviderDriverKind.make("codex");
73364
+ const SNAPSHOT_REFRESH_INTERVAL$4 = Duration.minutes(5);
72822
73365
  /**
72823
73366
  * Codex's own installer puts a launcher in `~/.local/bin` pointing at a
72824
73367
  * versioned release under `~/.codex/packages/standalone/`. That layout matches
@@ -72831,8 +73374,8 @@ function isCodexNativeCommandPath(commandPath) {
72831
73374
  const normalized = normalizeCommandPath(commandPath);
72832
73375
  return normalized.endsWith("/.local/bin/codex") || normalized.endsWith("/.local/bin/codex.exe") || normalized.includes("/.codex/packages/standalone/");
72833
73376
  }
72834
- const UPDATE$3 = makePackageManagedProviderMaintenanceResolver({
72835
- provider: DRIVER_KIND$3,
73377
+ const UPDATE$4 = makePackageManagedProviderMaintenanceResolver({
73378
+ provider: DRIVER_KIND$4,
72836
73379
  npmPackageName: "@openai/codex",
72837
73380
  homebrewFormula: "codex",
72838
73381
  nativeUpdate: {
@@ -72848,16 +73391,16 @@ const UPDATE$3 = makePackageManagedProviderMaintenanceResolver({
72848
73391
  * `providerSnapshot.ts` is widened to accept `instanceId`/`driver`, this
72849
73392
  * wrapper disappears.
72850
73393
  */
72851
- const withInstanceIdentity$3 = (input) => (snapshot) => ({
73394
+ const withInstanceIdentity$4 = (input) => (snapshot) => ({
72852
73395
  ...snapshot,
72853
73396
  instanceId: input.instanceId,
72854
- driver: DRIVER_KIND$3,
73397
+ driver: DRIVER_KIND$4,
72855
73398
  ...input.displayName ? { displayName: input.displayName } : {},
72856
73399
  ...input.accentColor ? { accentColor: input.accentColor } : {},
72857
73400
  continuation: { groupKey: input.continuationGroupKey }
72858
73401
  });
72859
73402
  const CodexDriver = {
72860
- driverKind: DRIVER_KIND$3,
73403
+ driverKind: DRIVER_KIND$4,
72861
73404
  metadata: {
72862
73405
  displayName: "Codex",
72863
73406
  supportsMultipleInstances: true
@@ -72872,14 +73415,14 @@ const CodexDriver = {
72872
73415
  const processEnv = mergeProviderInstanceEnvironment(environment);
72873
73416
  const homeLayout = yield* resolveCodexHomeLayout(config);
72874
73417
  const continuationIdentity = codexContinuationIdentity(homeLayout);
72875
- const stampIdentity = withInstanceIdentity$3({
73418
+ const stampIdentity = withInstanceIdentity$4({
72876
73419
  instanceId,
72877
73420
  displayName,
72878
73421
  accentColor,
72879
73422
  continuationGroupKey: continuationIdentity.continuationKey
72880
73423
  });
72881
73424
  yield* materializeCodexShadowHome(homeLayout).pipe(Effect.mapError((cause) => new ProviderDriverError({
72882
- driver: DRIVER_KIND$3,
73425
+ driver: DRIVER_KIND$4,
72883
73426
  instanceId,
72884
73427
  detail: cause.message,
72885
73428
  cause
@@ -72889,7 +73432,7 @@ const CodexDriver = {
72889
73432
  enabled,
72890
73433
  homePath: homeLayout.effectiveHomePath ?? ""
72891
73434
  };
72892
- const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$3, {
73435
+ const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$4, {
72893
73436
  binaryPath: effectiveConfig.binaryPath,
72894
73437
  env: processEnv
72895
73438
  });
@@ -72909,16 +73452,16 @@ const CodexDriver = {
72909
73452
  initialSnapshot: (settings) => makePendingCodexProvider(settings.provider).pipe(Effect.map(stampIdentity)),
72910
73453
  checkProvider,
72911
73454
  enrichSnapshot: ({ settings, snapshot, publishSnapshot }) => enrichProviderSnapshotWithVersionAdvisory(snapshot, maintenanceCapabilities, { enableProviderUpdateChecks: settings.enableProviderUpdateChecks }).pipe(Effect.provideService(HttpClient.HttpClient, httpClient), Effect.flatMap((enrichedSnapshot) => publishSnapshot(enrichedSnapshot))),
72912
- refreshInterval: SNAPSHOT_REFRESH_INTERVAL$3
73455
+ refreshInterval: SNAPSHOT_REFRESH_INTERVAL$4
72913
73456
  }).pipe(Effect.mapError((cause) => new ProviderDriverError({
72914
- driver: DRIVER_KIND$3,
73457
+ driver: DRIVER_KIND$4,
72915
73458
  instanceId,
72916
73459
  detail: `Failed to build Codex snapshot: ${cause.message ?? String(cause)}`,
72917
73460
  cause
72918
73461
  })));
72919
73462
  return {
72920
73463
  instanceId,
72921
- driverKind: DRIVER_KIND$3,
73464
+ driverKind: DRIVER_KIND$4,
72922
73465
  continuationIdentity,
72923
73466
  displayName,
72924
73467
  accentColor,
@@ -76895,18 +77438,18 @@ function deriveToolActivityPresentation(input) {
76895
77438
  }
76896
77439
  //#endregion
76897
77440
  //#region src/provider/acp/AcpRuntimeModel.ts
76898
- function isRecord$2(value) {
77441
+ function isRecord$4(value) {
76899
77442
  return typeof value === "object" && value !== null && !Array.isArray(value);
76900
77443
  }
76901
77444
  function isSessionModelState(value) {
76902
- if (!isRecord$2(value) || typeof value.currentModelId !== "string") return false;
77445
+ if (!isRecord$4(value) || typeof value.currentModelId !== "string") return false;
76903
77446
  if (!Array.isArray(value.availableModels)) return false;
76904
- return value.availableModels.every((model) => isRecord$2(model) && typeof model.modelId === "string" && typeof model.name === "string" && (model.description === void 0 || model.description === null || typeof model.description === "string"));
77447
+ return value.availableModels.every((model) => isRecord$4(model) && typeof model.modelId === "string" && typeof model.name === "string" && (model.description === void 0 || model.description === null || typeof model.description === "string"));
76905
77448
  }
76906
77449
  function isSessionModeState(value) {
76907
- if (!isRecord$2(value) || typeof value.currentModeId !== "string") return false;
77450
+ if (!isRecord$4(value) || typeof value.currentModeId !== "string") return false;
76908
77451
  if (!Array.isArray(value.availableModes)) return false;
76909
- return value.availableModes.every((mode) => isRecord$2(mode) && typeof mode.id === "string" && typeof mode.name === "string" && (mode.description === void 0 || typeof mode.description === "string"));
77452
+ return value.availableModes.every((mode) => isRecord$4(mode) && typeof mode.id === "string" && typeof mode.name === "string" && (mode.description === void 0 || typeof mode.description === "string"));
76910
77453
  }
76911
77454
  function extractModelConfigId(sessionResponse) {
76912
77455
  const configOptions = sessionResponse.configOptions;
@@ -76982,7 +77525,7 @@ function extractCommandFromTitle(title) {
76982
77525
  return /`([^`]+)`/.exec(title)?.[1]?.trim() || void 0;
76983
77526
  }
76984
77527
  function extractToolCallCommand(rawInput, title) {
76985
- if (isRecord$2(rawInput)) {
77528
+ if (isRecord$4(rawInput)) {
76986
77529
  const directCommand = normalizeCommandValue(rawInput.command);
76987
77530
  if (directCommand) return directCommand;
76988
77531
  const executable = typeof rawInput.executable === "string" ? rawInput.executable.trim() : "";
@@ -77104,7 +77647,7 @@ function parsePermissionRequest(params) {
77104
77647
  }
77105
77648
  function sessionUpdateIsReplay(params) {
77106
77649
  const meta = params._meta;
77107
- return isRecord$2(meta) && meta.isReplay === true;
77650
+ return isRecord$4(meta) && meta.isReplay === true;
77108
77651
  }
77109
77652
  const waitForSessionLoadReplayIdle = (input) => Effect.gen(function* () {
77110
77653
  const pollInterval = Duration.millis(25);
@@ -77119,8 +77662,8 @@ const waitForSessionLoadReplayIdle = (input) => Effect.gen(function* () {
77119
77662
  });
77120
77663
  function syntheticLoadSessionResponseFromInitialize(initializeResult) {
77121
77664
  const meta = initializeResult._meta;
77122
- const modelState = isRecord$2(meta) ? meta.modelState : void 0;
77123
- const modeState = isRecord$2(meta) ? meta.modeState : void 0;
77665
+ const modelState = isRecord$4(meta) ? meta.modelState : void 0;
77666
+ const modeState = isRecord$4(meta) ? meta.modeState : void 0;
77124
77667
  const models = isSessionModelState(modelState) ? modelState : void 0;
77125
77668
  const modes = isSessionModeState(modeState) ? modeState : void 0;
77126
77669
  return {
@@ -77678,7 +78221,7 @@ const CURSOR_PRESENTATION = {
77678
78221
  badgeLabel: "Early Access",
77679
78222
  showInteractionModeToggle: true
77680
78223
  };
77681
- const EMPTY_CAPABILITIES$1 = createModelCapabilities({ optionDescriptors: [] });
78224
+ const EMPTY_CAPABILITIES$2 = createModelCapabilities({ optionDescriptors: [] });
77682
78225
  const CURSOR_ACP_MODEL_DISCOVERY_TIMEOUT_MS = 15e3;
77683
78226
  const CURSOR_PARAMETERIZED_MODEL_PICKER_MIN_VERSION_DATE = 20260408;
77684
78227
  const CURSOR_CLI_INSTALLATION_DOCS_URL = "https://cursor.com/docs/cli/installation";
@@ -77786,7 +78329,7 @@ function getBooleanCurrentValue(option) {
77786
78329
  if (normalized === "false") return false;
77787
78330
  }
77788
78331
  function buildCursorCapabilitiesFromConfigOptions(configOptions) {
77789
- if (!configOptions || configOptions.length === 0) return EMPTY_CAPABILITIES$1;
78332
+ if (!configOptions || configOptions.length === 0) return EMPTY_CAPABILITIES$2;
77790
78333
  const reasoningConfig = findCursorEffortConfigOption(configOptions);
77791
78334
  const reasoningEffortLevels = reasoningConfig?.type === "select" ? flattenSessionConfigSelectOptions(reasoningConfig).flatMap((entry) => {
77792
78335
  const normalizedValue = normalizeCursorReasoningValue(entry.value);
@@ -77955,7 +78498,7 @@ const discoverCursorModelsViaListAvailableModels = (cursorSettings, environment)
77955
78498
  }), environment);
77956
78499
  const discoverCursorModelsViaAcp = (cursorSettings, environment) => discoverCursorModelsViaListAvailableModels(cursorSettings, environment);
77957
78500
  function getCursorFallbackModels(cursorSettings) {
77958
- return providerModelsFromSettings([], cursorSettings.customModels, EMPTY_CAPABILITIES$1);
78501
+ return providerModelsFromSettings([], cursorSettings.customModels, EMPTY_CAPABILITIES$2);
77959
78502
  }
77960
78503
  /** Timeout for `agent about` — it's slower than a simple `--version` probe. */
77961
78504
  const ABOUT_TIMEOUT_MS = 8e3;
@@ -77991,7 +78534,7 @@ function buildCursorProviderSnapshot(input) {
77991
78534
  presentation: CURSOR_PRESENTATION,
77992
78535
  enabled: input.cursorSettings.enabled,
77993
78536
  checkedAt: input.checkedAt,
77994
- models: providerModelsFromSettings(input.discoveredModels ?? [], input.cursorSettings.customModels, EMPTY_CAPABILITIES$1),
78537
+ models: providerModelsFromSettings(input.discoveredModels ?? [], input.cursorSettings.customModels, EMPTY_CAPABILITIES$2),
77995
78538
  probe: {
77996
78539
  installed: true,
77997
78540
  version: input.parsed.version,
@@ -78344,7 +78887,7 @@ function applyCursorAcpModelSelection(input) {
78344
78887
  //#endregion
78345
78888
  //#region src/textGeneration/CursorTextGeneration.ts
78346
78889
  const CURSOR_TIMEOUT_MS = 18e4;
78347
- const isTextGenerationError$1 = Schema$1.is(TextGenerationError);
78890
+ const isTextGenerationError$2 = Schema$1.is(TextGenerationError);
78348
78891
  /**
78349
78892
  * Build a Cursor text-generation closure bound to a specific `CursorSettings`
78350
78893
  * payload. See `makeCodexAdapter` for the overall per-instance rationale.
@@ -78395,7 +78938,7 @@ const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(function*
78395
78938
  detail: "Cursor Agent request timed out."
78396
78939
  })),
78397
78940
  onSome: (value) => Effect.succeed(value)
78398
- })), Effect.mapError((cause) => isTextGenerationError$1(cause) ? cause : new TextGenerationError({
78941
+ })), Effect.mapError((cause) => isTextGenerationError$2(cause) ? cause : new TextGenerationError({
78399
78942
  operation,
78400
78943
  detail: "Cursor ACP request failed.",
78401
78944
  cause
@@ -78410,7 +78953,7 @@ const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(function*
78410
78953
  detail: "Cursor Agent returned invalid structured output.",
78411
78954
  cause
78412
78955
  })) }));
78413
- }).pipe(Effect.mapError((cause) => isTextGenerationError$1(cause) ? cause : new TextGenerationError({
78956
+ }).pipe(Effect.mapError((cause) => isTextGenerationError$2(cause) ? cause : new TextGenerationError({
78414
78957
  operation,
78415
78958
  detail: "Cursor ACP text generation failed.",
78416
78959
  cause
@@ -78752,7 +79295,7 @@ const makeAcpNativeLoggerFactory = Effect.fn("makeAcpNativeLoggerFactory")(funct
78752
79295
  * @module CursorAdapterLive
78753
79296
  */
78754
79297
  const encodeUnknownJsonStringExit$1 = Schema$1.encodeUnknownExit(Schema$1.UnknownFromJsonString);
78755
- const PROVIDER$2 = ProviderDriverKind.make("cursor");
79298
+ const PROVIDER$3 = ProviderDriverKind.make("cursor");
78756
79299
  const CURSOR_RESUME_VERSION = 1;
78757
79300
  const ACP_PLAN_MODE_ALIASES = ["plan", "architect"];
78758
79301
  const ACP_IMPLEMENT_MODE_ALIASES = [
@@ -78775,11 +79318,11 @@ function settlePendingUserInputsAsEmptyAnswers(pendingUserInputs) {
78775
79318
  const pendingEntries = Array.from(pendingUserInputs.values());
78776
79319
  return Effect.forEach(pendingEntries, (pending) => Deferred.succeed(pending.answers, {}).pipe(Effect.ignore), { discard: true });
78777
79320
  }
78778
- function isRecord$1(value) {
79321
+ function isRecord$3(value) {
78779
79322
  return typeof value === "object" && value !== null && !Array.isArray(value);
78780
79323
  }
78781
79324
  function parseCursorResume(raw) {
78782
- if (!isRecord$1(raw)) return void 0;
79325
+ if (!isRecord$3(raw)) return void 0;
78783
79326
  if (raw.schemaVersion !== CURSOR_RESUME_VERSION) return void 0;
78784
79327
  if (typeof raw.sessionId !== "string" || !raw.sessionId.trim()) return void 0;
78785
79328
  return { sessionId: raw.sessionId.trim() };
@@ -78861,7 +79404,7 @@ function makeCursorAdapter(cursorSettings, options) {
78861
79404
  const runtimeEventPubSub = yield* PubSub.unbounded();
78862
79405
  const nowIso = Effect.map(DateTime.now, DateTime.formatIso);
78863
79406
  const randomUUIDv4 = crypto.randomUUIDv4.pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
78864
- provider: PROVIDER$2,
79407
+ provider: PROVIDER$3,
78865
79408
  method: "crypto/randomUUIDv4",
78866
79409
  detail: "Failed to generate Cursor runtime identifier.",
78867
79410
  cause
@@ -78896,7 +79439,7 @@ function makeCursorAdapter(cursorSettings, options) {
78896
79439
  event: {
78897
79440
  id: yield* randomUUIDv4,
78898
79441
  kind: "notification",
78899
- provider: PROVIDER$2,
79442
+ provider: PROVIDER$3,
78900
79443
  createdAt: observedAt,
78901
79444
  method,
78902
79445
  threadId,
@@ -78910,7 +79453,7 @@ function makeCursorAdapter(cursorSettings, options) {
78910
79453
  ctx.lastPlanFingerprint = fingerprint;
78911
79454
  yield* offerRuntimeEvent(makeAcpPlanUpdatedEvent({
78912
79455
  stamp: yield* makeEventStamp(),
78913
- provider: PROVIDER$2,
79456
+ provider: PROVIDER$3,
78914
79457
  threadId: ctx.threadId,
78915
79458
  turnId: ctx.activeTurnId,
78916
79459
  payload,
@@ -78922,7 +79465,7 @@ function makeCursorAdapter(cursorSettings, options) {
78922
79465
  const requireSession = (threadId) => {
78923
79466
  const ctx = sessions.get(threadId);
78924
79467
  if (!ctx || ctx.stopped) return Effect.fail(new ProviderAdapterSessionNotFoundError({
78925
- provider: PROVIDER$2,
79468
+ provider: PROVIDER$3,
78926
79469
  threadId
78927
79470
  }));
78928
79471
  return Effect.succeed(ctx);
@@ -78938,19 +79481,19 @@ function makeCursorAdapter(cursorSettings, options) {
78938
79481
  yield* offerRuntimeEvent({
78939
79482
  type: "session.exited",
78940
79483
  ...yield* makeEventStamp(),
78941
- provider: PROVIDER$2,
79484
+ provider: PROVIDER$3,
78942
79485
  threadId: ctx.threadId,
78943
79486
  payload: { exitKind: "graceful" }
78944
79487
  });
78945
79488
  });
78946
79489
  const startSession = (input) => withThreadLock(input.threadId, Effect.gen(function* () {
78947
- if (input.provider !== void 0 && input.provider !== PROVIDER$2) return yield* new ProviderAdapterValidationError({
78948
- provider: PROVIDER$2,
79490
+ if (input.provider !== void 0 && input.provider !== PROVIDER$3) return yield* new ProviderAdapterValidationError({
79491
+ provider: PROVIDER$3,
78949
79492
  operation: "startSession",
78950
- issue: `Expected provider '${PROVIDER$2}' but received '${input.provider}'.`
79493
+ issue: `Expected provider '${PROVIDER$3}' but received '${input.provider}'.`
78951
79494
  });
78952
79495
  if (!input.cwd?.trim()) return yield* new ProviderAdapterValidationError({
78953
- provider: PROVIDER$2,
79496
+ provider: PROVIDER$3,
78954
79497
  operation: "startSession",
78955
79498
  issue: "cwd is required and must be non-empty."
78956
79499
  });
@@ -78967,7 +79510,7 @@ function makeCursorAdapter(cursorSettings, options) {
78967
79510
  const resumeSessionId = parseCursorResume(input.resumeCursor)?.sessionId;
78968
79511
  const acpNativeLoggers = makeAcpNativeLoggers({
78969
79512
  nativeEventLogger,
78970
- provider: PROVIDER$2,
79513
+ provider: PROVIDER$3,
78971
79514
  threadId: input.threadId
78972
79515
  });
78973
79516
  const effectiveCursorSettings = options?.resolveSettings ? yield* options.resolveSettings : cursorSettings;
@@ -78993,7 +79536,7 @@ function makeCursorAdapter(cursorSettings, options) {
78993
79536
  }] } : {},
78994
79537
  ...acpNativeLoggers
78995
79538
  }).pipe(Effect.provideService(Crypto.Crypto, crypto), Effect.provideService(Scope.Scope, sessionScope), Effect.mapError((cause) => new ProviderAdapterProcessError({
78996
- provider: PROVIDER$2,
79539
+ provider: PROVIDER$3,
78997
79540
  threadId: input.threadId,
78998
79541
  detail: cause.message,
78999
79542
  cause
@@ -79008,7 +79551,7 @@ function makeCursorAdapter(cursorSettings, options) {
79008
79551
  yield* offerRuntimeEvent({
79009
79552
  type: "user-input.requested",
79010
79553
  ...yield* makeEventStamp(),
79011
- provider: PROVIDER$2,
79554
+ provider: PROVIDER$3,
79012
79555
  threadId: input.threadId,
79013
79556
  turnId: ctx?.activeTurnId,
79014
79557
  requestId: runtimeRequestId,
@@ -79024,7 +79567,7 @@ function makeCursorAdapter(cursorSettings, options) {
79024
79567
  yield* offerRuntimeEvent({
79025
79568
  type: "user-input.resolved",
79026
79569
  ...yield* makeEventStamp(),
79027
- provider: PROVIDER$2,
79570
+ provider: PROVIDER$3,
79028
79571
  threadId: input.threadId,
79029
79572
  turnId: ctx?.activeTurnId,
79030
79573
  requestId: runtimeRequestId,
@@ -79037,7 +79580,7 @@ function makeCursorAdapter(cursorSettings, options) {
79037
79580
  yield* offerRuntimeEvent({
79038
79581
  type: "turn.proposed.completed",
79039
79582
  ...yield* makeEventStamp(),
79040
- provider: PROVIDER$2,
79583
+ provider: PROVIDER$3,
79041
79584
  threadId: input.threadId,
79042
79585
  turnId: ctx?.activeTurnId,
79043
79586
  payload: { planMarkdown: extractPlanMarkdown(params) },
@@ -79072,7 +79615,7 @@ function makeCursorAdapter(cursorSettings, options) {
79072
79615
  });
79073
79616
  yield* offerRuntimeEvent(makeAcpRequestOpenedEvent({
79074
79617
  stamp: yield* makeEventStamp(),
79075
- provider: PROVIDER$2,
79618
+ provider: PROVIDER$3,
79076
79619
  threadId: input.threadId,
79077
79620
  turnId: ctx?.activeTurnId,
79078
79621
  requestId: runtimeRequestId,
@@ -79087,7 +79630,7 @@ function makeCursorAdapter(cursorSettings, options) {
79087
79630
  pendingApprovals.delete(requestId);
79088
79631
  yield* offerRuntimeEvent(makeAcpRequestResolvedEvent({
79089
79632
  stamp: yield* makeEventStamp(),
79090
- provider: PROVIDER$2,
79633
+ provider: PROVIDER$3,
79091
79634
  threadId: input.threadId,
79092
79635
  turnId: ctx?.activeTurnId,
79093
79636
  requestId: runtimeRequestId,
@@ -79100,17 +79643,17 @@ function makeCursorAdapter(cursorSettings, options) {
79100
79643
  } };
79101
79644
  })));
79102
79645
  return yield* acp.start();
79103
- }).pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$2, input.threadId, "session/start", error)));
79646
+ }).pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$3, input.threadId, "session/start", error)));
79104
79647
  yield* applyRequestedSessionConfiguration({
79105
79648
  runtime: acp,
79106
79649
  runtimeMode: input.runtimeMode,
79107
79650
  interactionMode: void 0,
79108
79651
  modelSelection: cursorModelSelection,
79109
- mapError: ({ cause, method }) => mapAcpToAdapterError(PROVIDER$2, input.threadId, method, cause)
79652
+ mapError: ({ cause, method }) => mapAcpToAdapterError(PROVIDER$3, input.threadId, method, cause)
79110
79653
  });
79111
79654
  const now = yield* nowIso;
79112
79655
  const session = {
79113
- provider: PROVIDER$2,
79656
+ provider: PROVIDER$3,
79114
79657
  providerInstanceId: boundInstanceId,
79115
79658
  status: "ready",
79116
79659
  runtimeMode: input.runtimeMode,
@@ -79147,7 +79690,7 @@ function makeCursorAdapter(cursorSettings, options) {
79147
79690
  case "AssistantItemStarted":
79148
79691
  yield* offerRuntimeEvent(makeAcpAssistantItemEvent({
79149
79692
  stamp: yield* makeEventStamp(),
79150
- provider: PROVIDER$2,
79693
+ provider: PROVIDER$3,
79151
79694
  threadId: ctx.threadId,
79152
79695
  turnId: ctx.activeTurnId,
79153
79696
  itemId: event.itemId,
@@ -79157,7 +79700,7 @@ function makeCursorAdapter(cursorSettings, options) {
79157
79700
  case "AssistantItemCompleted":
79158
79701
  yield* offerRuntimeEvent(makeAcpAssistantItemEvent({
79159
79702
  stamp: yield* makeEventStamp(),
79160
- provider: PROVIDER$2,
79703
+ provider: PROVIDER$3,
79161
79704
  threadId: ctx.threadId,
79162
79705
  turnId: ctx.activeTurnId,
79163
79706
  itemId: event.itemId,
@@ -79172,7 +79715,7 @@ function makeCursorAdapter(cursorSettings, options) {
79172
79715
  yield* logNative(ctx.threadId, "session/update", event.rawPayload, "acp.jsonrpc");
79173
79716
  yield* offerRuntimeEvent(makeAcpToolCallEvent({
79174
79717
  stamp: yield* makeEventStamp(),
79175
- provider: PROVIDER$2,
79718
+ provider: PROVIDER$3,
79176
79719
  threadId: ctx.threadId,
79177
79720
  turnId: ctx.activeTurnId,
79178
79721
  toolCall: event.toolCall,
@@ -79183,7 +79726,7 @@ function makeCursorAdapter(cursorSettings, options) {
79183
79726
  yield* logNative(ctx.threadId, "session/update", event.rawPayload, "acp.jsonrpc");
79184
79727
  yield* offerRuntimeEvent(makeAcpContentDeltaEvent({
79185
79728
  stamp: yield* makeEventStamp(),
79186
- provider: PROVIDER$2,
79729
+ provider: PROVIDER$3,
79187
79730
  threadId: ctx.threadId,
79188
79731
  turnId: ctx.activeTurnId,
79189
79732
  ...event.itemId ? { itemId: event.itemId } : {},
@@ -79199,14 +79742,14 @@ function makeCursorAdapter(cursorSettings, options) {
79199
79742
  yield* offerRuntimeEvent({
79200
79743
  type: "session.started",
79201
79744
  ...yield* makeEventStamp(),
79202
- provider: PROVIDER$2,
79745
+ provider: PROVIDER$3,
79203
79746
  threadId: input.threadId,
79204
79747
  payload: { resume: started.initializeResult }
79205
79748
  });
79206
79749
  yield* offerRuntimeEvent({
79207
79750
  type: "session.state.changed",
79208
79751
  ...yield* makeEventStamp(),
79209
- provider: PROVIDER$2,
79752
+ provider: PROVIDER$3,
79210
79753
  threadId: input.threadId,
79211
79754
  payload: {
79212
79755
  state: "ready",
@@ -79216,7 +79759,7 @@ function makeCursorAdapter(cursorSettings, options) {
79216
79759
  yield* offerRuntimeEvent({
79217
79760
  type: "thread.started",
79218
79761
  ...yield* makeEventStamp(),
79219
- provider: PROVIDER$2,
79762
+ provider: PROVIDER$3,
79220
79763
  threadId: input.threadId,
79221
79764
  payload: { providerThreadId: started.sessionId }
79222
79765
  });
@@ -79239,7 +79782,7 @@ function makeCursorAdapter(cursorSettings, options) {
79239
79782
  model,
79240
79783
  options: turnModelSelection?.options
79241
79784
  },
79242
- mapError: ({ cause, method }) => mapAcpToAdapterError(PROVIDER$2, input.threadId, method, cause)
79785
+ mapError: ({ cause, method }) => mapAcpToAdapterError(PROVIDER$3, input.threadId, method, cause)
79243
79786
  });
79244
79787
  ctx.activeTurnId = turnId;
79245
79788
  if (steeringTurnId === void 0) ctx.lastPlanFingerprint = void 0;
@@ -79251,7 +79794,7 @@ function makeCursorAdapter(cursorSettings, options) {
79251
79794
  if (steeringTurnId === void 0) yield* offerRuntimeEvent({
79252
79795
  type: "turn.started",
79253
79796
  ...yield* makeEventStamp(),
79254
- provider: PROVIDER$2,
79797
+ provider: PROVIDER$3,
79255
79798
  threadId: input.threadId,
79256
79799
  turnId,
79257
79800
  payload: { model: resolvedModel }
@@ -79267,12 +79810,12 @@ function makeCursorAdapter(cursorSettings, options) {
79267
79810
  attachment
79268
79811
  });
79269
79812
  if (!attachmentPath) return yield* new ProviderAdapterRequestError({
79270
- provider: PROVIDER$2,
79813
+ provider: PROVIDER$3,
79271
79814
  method: "session/prompt",
79272
79815
  detail: `Invalid attachment id '${attachment.id}'.`
79273
79816
  });
79274
79817
  const bytes = yield* fileSystem.readFile(attachmentPath).pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
79275
- provider: PROVIDER$2,
79818
+ provider: PROVIDER$3,
79276
79819
  method: "session/prompt",
79277
79820
  detail: cause.message,
79278
79821
  cause
@@ -79284,11 +79827,11 @@ function makeCursorAdapter(cursorSettings, options) {
79284
79827
  });
79285
79828
  }
79286
79829
  if (promptParts.length === 0) return yield* new ProviderAdapterValidationError({
79287
- provider: PROVIDER$2,
79830
+ provider: PROVIDER$3,
79288
79831
  operation: "sendTurn",
79289
79832
  issue: "Turn requires non-empty text or attachments."
79290
79833
  });
79291
- const result = yield* ctx.acp.prompt({ prompt: promptParts }).pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$2, input.threadId, "session/prompt", error)));
79834
+ const result = yield* ctx.acp.prompt({ prompt: promptParts }).pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$3, input.threadId, "session/prompt", error)));
79292
79835
  const turnRecord = ctx.turns.find((turn) => turn.id === turnId);
79293
79836
  if (turnRecord) turnRecord.items.push({
79294
79837
  prompt: promptParts,
@@ -79310,7 +79853,7 @@ function makeCursorAdapter(cursorSettings, options) {
79310
79853
  if (ctx.promptsInFlight === 1) yield* offerRuntimeEvent({
79311
79854
  type: "turn.completed",
79312
79855
  ...yield* makeEventStamp(),
79313
- provider: PROVIDER$2,
79856
+ provider: PROVIDER$3,
79314
79857
  threadId: input.threadId,
79315
79858
  turnId,
79316
79859
  payload: {
@@ -79331,12 +79874,12 @@ function makeCursorAdapter(cursorSettings, options) {
79331
79874
  const ctx = yield* requireSession(threadId);
79332
79875
  yield* settlePendingApprovalsAsCancelled$1(ctx.pendingApprovals);
79333
79876
  yield* settlePendingUserInputsAsEmptyAnswers(ctx.pendingUserInputs);
79334
- yield* Effect.ignore(ctx.acp.cancel.pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$2, threadId, "session/cancel", error))));
79877
+ yield* Effect.ignore(ctx.acp.cancel.pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$3, threadId, "session/cancel", error))));
79335
79878
  });
79336
79879
  const respondToRequest = (threadId, requestId, decision) => Effect.gen(function* () {
79337
79880
  const pending = (yield* requireSession(threadId)).pendingApprovals.get(requestId);
79338
79881
  if (!pending) return yield* new ProviderAdapterRequestError({
79339
- provider: PROVIDER$2,
79882
+ provider: PROVIDER$3,
79340
79883
  method: "session/request_permission",
79341
79884
  detail: `Unknown pending approval request: ${requestId}`
79342
79885
  });
@@ -79345,7 +79888,7 @@ function makeCursorAdapter(cursorSettings, options) {
79345
79888
  const respondToUserInput = (threadId, requestId, answers) => Effect.gen(function* () {
79346
79889
  const pending = (yield* requireSession(threadId)).pendingUserInputs.get(requestId);
79347
79890
  if (!pending) return yield* new ProviderAdapterRequestError({
79348
- provider: PROVIDER$2,
79891
+ provider: PROVIDER$3,
79349
79892
  method: "cursor/ask_question",
79350
79893
  detail: `Unknown pending user-input request: ${requestId}`
79351
79894
  });
@@ -79360,7 +79903,7 @@ function makeCursorAdapter(cursorSettings, options) {
79360
79903
  const rollbackThread = (threadId, numTurns) => Effect.gen(function* () {
79361
79904
  const ctx = yield* requireSession(threadId);
79362
79905
  if (!Number.isInteger(numTurns) || numTurns < 1) return yield* new ProviderAdapterValidationError({
79363
- provider: PROVIDER$2,
79906
+ provider: PROVIDER$3,
79364
79907
  operation: "rollbackThread",
79365
79908
  issue: "numTurns must be an integer >= 1."
79366
79909
  });
@@ -79384,7 +79927,7 @@ function makeCursorAdapter(cursorSettings, options) {
79384
79927
  yield* Effect.addFinalizer(() => Effect.forEach(sessions.values(), stopSessionInternal, { discard: true }).pipe(Effect.catch((cause) => Effect.logError("Failed to emit Cursor session shutdown event.", { cause })), Effect.tap(() => PubSub.shutdown(runtimeEventPubSub)), Effect.tap(() => managedNativeEventLogger?.close() ?? Effect.void)));
79385
79928
  const streamEvents = Stream.fromPubSub(runtimeEventPubSub);
79386
79929
  return {
79387
- provider: PROVIDER$2,
79930
+ provider: PROVIDER$3,
79388
79931
  capabilities: { sessionModelSwitch: "in-session" },
79389
79932
  startSession,
79390
79933
  sendTurn,
@@ -79417,25 +79960,25 @@ function makeCursorAdapter(cursorSettings, options) {
79417
79960
  * @module provider/Drivers/CursorDriver
79418
79961
  */
79419
79962
  const decodeCursorSettings = Schema$1.decodeSync(CursorSettings);
79420
- const DRIVER_KIND$2 = ProviderDriverKind.make("cursor");
79421
- const SNAPSHOT_REFRESH_INTERVAL$2 = Duration.minutes(5);
79422
- const UPDATE$2 = { resolve: (options) => makeProviderMaintenanceCapabilities({
79423
- provider: DRIVER_KIND$2,
79963
+ const DRIVER_KIND$3 = ProviderDriverKind.make("cursor");
79964
+ const SNAPSHOT_REFRESH_INTERVAL$3 = Duration.minutes(5);
79965
+ const UPDATE$3 = { resolve: (options) => makeProviderMaintenanceCapabilities({
79966
+ provider: DRIVER_KIND$3,
79424
79967
  packageName: null,
79425
79968
  updateExecutable: options?.binaryPath?.trim() || "cursor-agent",
79426
79969
  updateArgs: ["update"],
79427
79970
  updateLockKey: "cursor-agent"
79428
79971
  }) };
79429
- const withInstanceIdentity$2 = (input) => (snapshot) => ({
79972
+ const withInstanceIdentity$3 = (input) => (snapshot) => ({
79430
79973
  ...snapshot,
79431
79974
  instanceId: input.instanceId,
79432
- driver: DRIVER_KIND$2,
79975
+ driver: DRIVER_KIND$3,
79433
79976
  ...input.displayName ? { displayName: input.displayName } : {},
79434
79977
  ...input.accentColor ? { accentColor: input.accentColor } : {},
79435
79978
  continuation: { groupKey: input.continuationGroupKey }
79436
79979
  });
79437
79980
  const CursorDriver = {
79438
- driverKind: DRIVER_KIND$2,
79981
+ driverKind: DRIVER_KIND$3,
79439
79982
  metadata: {
79440
79983
  displayName: "Cursor",
79441
79984
  supportsMultipleInstances: true
@@ -79452,10 +79995,10 @@ const CursorDriver = {
79452
79995
  const eventLoggers = yield* ProviderEventLoggers;
79453
79996
  const processEnv = mergeProviderInstanceEnvironment(environment);
79454
79997
  const continuationIdentity = defaultProviderContinuationIdentity({
79455
- driverKind: DRIVER_KIND$2,
79998
+ driverKind: DRIVER_KIND$3,
79456
79999
  instanceId
79457
80000
  });
79458
- const stampIdentity = withInstanceIdentity$2({
80001
+ const stampIdentity = withInstanceIdentity$3({
79459
80002
  instanceId,
79460
80003
  displayName,
79461
80004
  accentColor,
@@ -79465,7 +80008,7 @@ const CursorDriver = {
79465
80008
  ...config,
79466
80009
  enabled
79467
80010
  };
79468
- const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$2, {
80011
+ const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$3, {
79469
80012
  binaryPath: effectiveConfig.binaryPath,
79470
80013
  env: processEnv
79471
80014
  });
@@ -79493,16 +80036,16 @@ const CursorDriver = {
79493
80036
  stampIdentity,
79494
80037
  httpClient
79495
80038
  }),
79496
- refreshInterval: SNAPSHOT_REFRESH_INTERVAL$2
80039
+ refreshInterval: SNAPSHOT_REFRESH_INTERVAL$3
79497
80040
  }).pipe(Effect.mapError((cause) => new ProviderDriverError({
79498
- driver: DRIVER_KIND$2,
80041
+ driver: DRIVER_KIND$3,
79499
80042
  instanceId,
79500
80043
  detail: `Failed to build Cursor snapshot: ${cause.message ?? String(cause)}`,
79501
80044
  cause
79502
80045
  })));
79503
80046
  return {
79504
80047
  instanceId,
79505
- driverKind: DRIVER_KIND$2,
80048
+ driverKind: DRIVER_KIND$3,
79506
80049
  continuationIdentity,
79507
80050
  displayName,
79508
80051
  accentColor,
@@ -79767,7 +80310,7 @@ function applyGrokAcpModelSelection(input) {
79767
80310
  //#endregion
79768
80311
  //#region src/textGeneration/GrokTextGeneration.ts
79769
80312
  const GROK_TIMEOUT_MS = 18e4;
79770
- const isTextGenerationError = Schema$1.is(TextGenerationError);
80313
+ const isTextGenerationError$1 = Schema$1.is(TextGenerationError);
79771
80314
  const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(function* (grokSettings, environment = process.env) {
79772
80315
  const crypto = yield* Crypto.Crypto;
79773
80316
  const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
@@ -79813,7 +80356,7 @@ const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(function* (gr
79813
80356
  detail: "Grok ACP request timed out."
79814
80357
  })),
79815
80358
  onSome: (value) => Effect.succeed(value)
79816
- })), Effect.mapError((cause) => isTextGenerationError(cause) ? cause : new TextGenerationError({
80359
+ })), Effect.mapError((cause) => isTextGenerationError$1(cause) ? cause : new TextGenerationError({
79817
80360
  operation,
79818
80361
  detail: "Grok ACP request failed.",
79819
80362
  cause
@@ -79828,7 +80371,7 @@ const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(function* (gr
79828
80371
  detail: "Grok Agent returned invalid structured output.",
79829
80372
  cause
79830
80373
  })) }));
79831
- }).pipe(Effect.mapError((cause) => isTextGenerationError(cause) ? cause : new TextGenerationError({
80374
+ }).pipe(Effect.mapError((cause) => isTextGenerationError$1(cause) ? cause : new TextGenerationError({
79832
80375
  operation,
79833
80376
  detail: "Grok ACP text generation failed.",
79834
80377
  cause
@@ -79908,7 +80451,7 @@ const makeGrokTextGeneration = Effect.fn("makeGrokTextGeneration")(function* (gr
79908
80451
  //#endregion
79909
80452
  //#region src/provider/Layers/GrokAdapter.ts
79910
80453
  const encodeUnknownJsonStringExit = Schema$1.encodeUnknownExit(Schema$1.UnknownFromJsonString);
79911
- const PROVIDER$1 = ProviderDriverKind.make("grok");
80454
+ const PROVIDER$2 = ProviderDriverKind.make("grok");
79912
80455
  const GROK_RESUME_VERSION = 1;
79913
80456
  function encodeJsonStringForDiagnostics(input) {
79914
80457
  const result = encodeUnknownJsonStringExit(input);
@@ -79935,7 +80478,7 @@ function appendPromptResultToTurn(ctx, turnId, promptParts, result) {
79935
80478
  }]
79936
80479
  }];
79937
80480
  }
79938
- function isRecord(value) {
80481
+ function isRecord$2(value) {
79939
80482
  return typeof value === "object" && value !== null && !Array.isArray(value);
79940
80483
  }
79941
80484
  const resolveNotificationTurnId = (ctx) => ctx.activeTurnId;
@@ -79945,7 +80488,7 @@ const resolveSessionCallbackTurnId = (sessions, threadId) => {
79945
80488
  return ctx ? resolveCallbackTurnId(ctx) : void 0;
79946
80489
  };
79947
80490
  function parseGrokResume(raw) {
79948
- if (!isRecord(raw)) return void 0;
80491
+ if (!isRecord$2(raw)) return void 0;
79949
80492
  if (raw.schemaVersion !== GROK_RESUME_VERSION) return void 0;
79950
80493
  if (typeof raw.sessionId !== "string" || !raw.sessionId.trim()) return void 0;
79951
80494
  return { sessionId: raw.sessionId.trim() };
@@ -79980,7 +80523,7 @@ function makeGrokAdapter(grokSettings, options) {
79980
80523
  const runtimeEventPubSub = yield* PubSub.unbounded();
79981
80524
  const nowIso = Effect.map(DateTime.now, DateTime.formatIso);
79982
80525
  const randomUUIDv4 = crypto.randomUUIDv4.pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
79983
- provider: PROVIDER$1,
80526
+ provider: PROVIDER$2,
79984
80527
  method: "crypto/randomUUIDv4",
79985
80528
  detail: "Failed to generate Grok runtime identifier.",
79986
80529
  cause
@@ -80022,7 +80565,7 @@ function makeGrokAdapter(grokSettings, options) {
80022
80565
  if (options?.errorMessage !== void 0) yield* offerRuntimeEvent({
80023
80566
  type: "turn.completed",
80024
80567
  ...yield* makeEventStamp(),
80025
- provider: PROVIDER$1,
80568
+ provider: PROVIDER$2,
80026
80569
  threadId,
80027
80570
  turnId,
80028
80571
  payload: {
@@ -80033,7 +80576,7 @@ function makeGrokAdapter(grokSettings, options) {
80033
80576
  else if (options?.completedStopReason !== void 0) yield* offerRuntimeEvent({
80034
80577
  type: "turn.completed",
80035
80578
  ...yield* makeEventStamp(),
80036
- provider: PROVIDER$1,
80579
+ provider: PROVIDER$2,
80037
80580
  threadId,
80038
80581
  turnId,
80039
80582
  payload: {
@@ -80087,7 +80630,7 @@ function makeGrokAdapter(grokSettings, options) {
80087
80630
  if (shouldEmitFailedTurn) yield* offerRuntimeEvent({
80088
80631
  type: "turn.completed",
80089
80632
  ...yield* makeEventStamp(),
80090
- provider: PROVIDER$1,
80633
+ provider: PROVIDER$2,
80091
80634
  threadId,
80092
80635
  turnId: settleTurnId,
80093
80636
  payload: {
@@ -80098,7 +80641,7 @@ function makeGrokAdapter(grokSettings, options) {
80098
80641
  else if (shouldEmitCompletedTurn) yield* offerRuntimeEvent({
80099
80642
  type: "turn.completed",
80100
80643
  ...yield* makeEventStamp(),
80101
- provider: PROVIDER$1,
80644
+ provider: PROVIDER$2,
80102
80645
  threadId,
80103
80646
  turnId: settleTurnId,
80104
80647
  payload: {
@@ -80115,7 +80658,7 @@ function makeGrokAdapter(grokSettings, options) {
80115
80658
  event: {
80116
80659
  id: yield* randomUUIDv4,
80117
80660
  kind: "notification",
80118
- provider: PROVIDER$1,
80661
+ provider: PROVIDER$2,
80119
80662
  createdAt: observedAt,
80120
80663
  method,
80121
80664
  threadId,
@@ -80133,7 +80676,7 @@ function makeGrokAdapter(grokSettings, options) {
80133
80676
  ctx.lastPlanFingerprint = fingerprint;
80134
80677
  yield* offerRuntimeEvent(makeAcpPlanUpdatedEvent({
80135
80678
  stamp,
80136
- provider: PROVIDER$1,
80679
+ provider: PROVIDER$2,
80137
80680
  threadId: ctx.threadId,
80138
80681
  turnId,
80139
80682
  payload,
@@ -80145,7 +80688,7 @@ function makeGrokAdapter(grokSettings, options) {
80145
80688
  const requireSession = (threadId) => {
80146
80689
  const ctx = sessions.get(threadId);
80147
80690
  if (!ctx || ctx.stopped) return Effect.fail(new ProviderAdapterSessionNotFoundError({
80148
- provider: PROVIDER$1,
80691
+ provider: PROVIDER$2,
80149
80692
  threadId
80150
80693
  }));
80151
80694
  return Effect.succeed(ctx);
@@ -80161,19 +80704,19 @@ function makeGrokAdapter(grokSettings, options) {
80161
80704
  yield* offerRuntimeEvent({
80162
80705
  type: "session.exited",
80163
80706
  ...yield* makeEventStamp(),
80164
- provider: PROVIDER$1,
80707
+ provider: PROVIDER$2,
80165
80708
  threadId: ctx.threadId,
80166
80709
  payload: { exitKind: "graceful" }
80167
80710
  });
80168
80711
  });
80169
80712
  const startSession = (input) => withThreadLock(input.threadId, Effect.gen(function* () {
80170
- if (input.provider !== void 0 && input.provider !== PROVIDER$1) return yield* new ProviderAdapterValidationError({
80171
- provider: PROVIDER$1,
80713
+ if (input.provider !== void 0 && input.provider !== PROVIDER$2) return yield* new ProviderAdapterValidationError({
80714
+ provider: PROVIDER$2,
80172
80715
  operation: "startSession",
80173
- issue: `Expected provider '${PROVIDER$1}' but received '${input.provider}'.`
80716
+ issue: `Expected provider '${PROVIDER$2}' but received '${input.provider}'.`
80174
80717
  });
80175
80718
  if (!input.cwd?.trim()) return yield* new ProviderAdapterValidationError({
80176
- provider: PROVIDER$1,
80719
+ provider: PROVIDER$2,
80177
80720
  operation: "startSession",
80178
80721
  issue: "cwd is required and must be non-empty."
80179
80722
  });
@@ -80189,7 +80732,7 @@ function makeGrokAdapter(grokSettings, options) {
80189
80732
  const resumeSessionId = parseGrokResume(input.resumeCursor)?.sessionId;
80190
80733
  const acpNativeLoggers = makeAcpNativeLoggers({
80191
80734
  nativeEventLogger,
80192
- provider: PROVIDER$1,
80735
+ provider: PROVIDER$2,
80193
80736
  threadId: input.threadId
80194
80737
  });
80195
80738
  const mcpSession = readMcpProviderSession(input.threadId);
@@ -80214,7 +80757,7 @@ function makeGrokAdapter(grokSettings, options) {
80214
80757
  }] } : {},
80215
80758
  ...acpNativeLoggers
80216
80759
  }).pipe(Effect.provideService(Crypto.Crypto, crypto), Effect.provideService(Scope.Scope, sessionScope), Effect.mapError((cause) => new ProviderAdapterProcessError({
80217
- provider: PROVIDER$1,
80760
+ provider: PROVIDER$2,
80218
80761
  threadId: input.threadId,
80219
80762
  detail: cause.message,
80220
80763
  cause
@@ -80230,7 +80773,7 @@ function makeGrokAdapter(grokSettings, options) {
80230
80773
  yield* offerRuntimeEvent({
80231
80774
  type: "user-input.requested",
80232
80775
  ...yield* makeEventStamp(),
80233
- provider: PROVIDER$1,
80776
+ provider: PROVIDER$2,
80234
80777
  threadId: input.threadId,
80235
80778
  turnId,
80236
80779
  requestId: runtimeRequestId,
@@ -80247,7 +80790,7 @@ function makeGrokAdapter(grokSettings, options) {
80247
80790
  yield* offerRuntimeEvent({
80248
80791
  type: "user-input.resolved",
80249
80792
  ...yield* makeEventStamp(),
80250
- provider: PROVIDER$1,
80793
+ provider: PROVIDER$2,
80251
80794
  threadId: input.threadId,
80252
80795
  turnId,
80253
80796
  requestId: runtimeRequestId,
@@ -80280,7 +80823,7 @@ function makeGrokAdapter(grokSettings, options) {
80280
80823
  pendingApprovals.set(requestId, { decision });
80281
80824
  yield* offerRuntimeEvent(makeAcpRequestOpenedEvent({
80282
80825
  stamp: yield* makeEventStamp(),
80283
- provider: PROVIDER$1,
80826
+ provider: PROVIDER$2,
80284
80827
  threadId: input.threadId,
80285
80828
  turnId,
80286
80829
  requestId: runtimeRequestId,
@@ -80295,7 +80838,7 @@ function makeGrokAdapter(grokSettings, options) {
80295
80838
  pendingApprovals.delete(requestId);
80296
80839
  yield* offerRuntimeEvent(makeAcpRequestResolvedEvent({
80297
80840
  stamp: yield* makeEventStamp(),
80298
- provider: PROVIDER$1,
80841
+ provider: PROVIDER$2,
80299
80842
  threadId: input.threadId,
80300
80843
  turnId,
80301
80844
  requestId: runtimeRequestId,
@@ -80309,17 +80852,17 @@ function makeGrokAdapter(grokSettings, options) {
80309
80852
  } : { outcome: "cancelled" } };
80310
80853
  })));
80311
80854
  return yield* acp.start();
80312
- }).pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$1, input.threadId, "session/start", error)));
80855
+ }).pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$2, input.threadId, "session/start", error)));
80313
80856
  const requestedStartModelId = grokModelSelection?.model ? resolveGrokAcpBaseModelId(grokModelSelection.model) : void 0;
80314
80857
  const boundModelId = yield* applyGrokAcpModelSelection({
80315
80858
  runtime: acp,
80316
80859
  currentModelId: currentGrokModelIdFromSessionSetup(started.sessionSetupResult),
80317
80860
  requestedModelId: requestedStartModelId,
80318
- mapError: (cause) => mapAcpToAdapterError(PROVIDER$1, input.threadId, "session/set_model", cause)
80861
+ mapError: (cause) => mapAcpToAdapterError(PROVIDER$2, input.threadId, "session/set_model", cause)
80319
80862
  });
80320
80863
  const now = yield* nowIso;
80321
80864
  const session = {
80322
- provider: PROVIDER$1,
80865
+ provider: PROVIDER$2,
80323
80866
  providerInstanceId: boundInstanceId,
80324
80867
  status: "ready",
80325
80868
  runtimeMode: input.runtimeMode,
@@ -80364,7 +80907,7 @@ function makeGrokAdapter(grokSettings, options) {
80364
80907
  case "AssistantItemStarted":
80365
80908
  yield* offerRuntimeEvent(makeAcpAssistantItemEvent({
80366
80909
  stamp,
80367
- provider: PROVIDER$1,
80910
+ provider: PROVIDER$2,
80368
80911
  threadId: ctx.threadId,
80369
80912
  turnId: notificationTurnId,
80370
80913
  itemId: event.itemId,
@@ -80374,7 +80917,7 @@ function makeGrokAdapter(grokSettings, options) {
80374
80917
  case "AssistantItemCompleted":
80375
80918
  yield* offerRuntimeEvent(makeAcpAssistantItemEvent({
80376
80919
  stamp,
80377
- provider: PROVIDER$1,
80920
+ provider: PROVIDER$2,
80378
80921
  threadId: ctx.threadId,
80379
80922
  turnId: notificationTurnId,
80380
80923
  itemId: event.itemId,
@@ -80387,7 +80930,7 @@ function makeGrokAdapter(grokSettings, options) {
80387
80930
  case "ToolCallUpdated":
80388
80931
  yield* offerRuntimeEvent(makeAcpToolCallEvent({
80389
80932
  stamp,
80390
- provider: PROVIDER$1,
80933
+ provider: PROVIDER$2,
80391
80934
  threadId: ctx.threadId,
80392
80935
  turnId: notificationTurnId,
80393
80936
  toolCall: event.toolCall,
@@ -80397,7 +80940,7 @@ function makeGrokAdapter(grokSettings, options) {
80397
80940
  case "ContentDelta":
80398
80941
  yield* offerRuntimeEvent(makeAcpContentDeltaEvent({
80399
80942
  stamp,
80400
- provider: PROVIDER$1,
80943
+ provider: PROVIDER$2,
80401
80944
  threadId: ctx.threadId,
80402
80945
  turnId: notificationTurnId,
80403
80946
  ...event.itemId ? { itemId: event.itemId } : {},
@@ -80412,14 +80955,14 @@ function makeGrokAdapter(grokSettings, options) {
80412
80955
  yield* offerRuntimeEvent({
80413
80956
  type: "session.started",
80414
80957
  ...yield* makeEventStamp(),
80415
- provider: PROVIDER$1,
80958
+ provider: PROVIDER$2,
80416
80959
  threadId: input.threadId,
80417
80960
  payload: { resume: started.initializeResult }
80418
80961
  });
80419
80962
  yield* offerRuntimeEvent({
80420
80963
  type: "session.state.changed",
80421
80964
  ...yield* makeEventStamp(),
80422
- provider: PROVIDER$1,
80965
+ provider: PROVIDER$2,
80423
80966
  threadId: input.threadId,
80424
80967
  payload: {
80425
80968
  state: "ready",
@@ -80429,7 +80972,7 @@ function makeGrokAdapter(grokSettings, options) {
80429
80972
  yield* offerRuntimeEvent({
80430
80973
  type: "thread.started",
80431
80974
  ...yield* makeEventStamp(),
80432
- provider: PROVIDER$1,
80975
+ provider: PROVIDER$2,
80433
80976
  threadId: input.threadId,
80434
80977
  payload: { providerThreadId: started.sessionId }
80435
80978
  });
@@ -80455,7 +80998,7 @@ function makeGrokAdapter(grokSettings, options) {
80455
80998
  runtime: ctx.acp,
80456
80999
  currentModelId: ctx.currentModelId,
80457
81000
  requestedModelId: requestedTurnModelId,
80458
- mapError: (cause) => mapAcpToAdapterError(PROVIDER$1, input.threadId, "session/set_model", cause)
81001
+ mapError: (cause) => mapAcpToAdapterError(PROVIDER$2, input.threadId, "session/set_model", cause)
80459
81002
  });
80460
81003
  const text = input.input?.trim();
80461
81004
  const imagePromptParts = yield* Effect.forEach(input.attachments ?? [], (attachment) => Effect.gen(function* () {
@@ -80464,12 +81007,12 @@ function makeGrokAdapter(grokSettings, options) {
80464
81007
  attachment
80465
81008
  });
80466
81009
  if (!attachmentPath) return yield* new ProviderAdapterRequestError({
80467
- provider: PROVIDER$1,
81010
+ provider: PROVIDER$2,
80468
81011
  method: "session/prompt",
80469
81012
  detail: `Invalid attachment id '${attachment.id}'.`
80470
81013
  });
80471
81014
  const bytes = yield* fileSystem.readFile(attachmentPath).pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
80472
- provider: PROVIDER$1,
81015
+ provider: PROVIDER$2,
80473
81016
  method: "session/prompt",
80474
81017
  detail: cause.message,
80475
81018
  cause
@@ -80485,7 +81028,7 @@ function makeGrokAdapter(grokSettings, options) {
80485
81028
  text
80486
81029
  }] : [], ...imagePromptParts];
80487
81030
  if (promptParts.length === 0) return yield* new ProviderAdapterValidationError({
80488
- provider: PROVIDER$1,
81031
+ provider: PROVIDER$2,
80489
81032
  operation: "sendTurn",
80490
81033
  issue: "Turn requires non-empty text or attachments."
80491
81034
  });
@@ -80499,7 +81042,7 @@ function makeGrokAdapter(grokSettings, options) {
80499
81042
  settleAllPrompts: true
80500
81043
  });
80501
81044
  return yield* new ProviderAdapterRequestError({
80502
- provider: PROVIDER$1,
81045
+ provider: PROVIDER$2,
80503
81046
  method: "session/prompt",
80504
81047
  detail: "Grok prompt was interrupted during preparation."
80505
81048
  });
@@ -80515,7 +81058,7 @@ function makeGrokAdapter(grokSettings, options) {
80515
81058
  if (steeringTurnId === void 0) yield* offerRuntimeEvent({
80516
81059
  type: "turn.started",
80517
81060
  ...yield* makeEventStamp(),
80518
- provider: PROVIDER$1,
81061
+ provider: PROVIDER$2,
80519
81062
  threadId: input.threadId,
80520
81063
  turnId,
80521
81064
  payload: displayModel ? { model: displayModel } : {}
@@ -80541,7 +81084,7 @@ function makeGrokAdapter(grokSettings, options) {
80541
81084
  const promptResultRef = yield* Ref.make(void 0);
80542
81085
  const promptFailureMessageRef = yield* Ref.make(void 0);
80543
81086
  return yield* Effect.gen(function* () {
80544
- const result = yield* prepared.acp.prompt({ prompt: prepared.promptParts }).pipe(Effect.tap((promptResult) => Effect.all([Ref.set(promptRpcSucceeded, true), Ref.set(promptResultRef, promptResult)])), Effect.tapError((error) => Ref.set(promptFailureMessageRef, mapAcpToAdapterError(PROVIDER$1, input.threadId, "session/prompt", error).message).pipe(Effect.andThen(prepared.acp.drainEvents))), Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$1, input.threadId, "session/prompt", error)));
81087
+ const result = yield* prepared.acp.prompt({ prompt: prepared.promptParts }).pipe(Effect.tap((promptResult) => Effect.all([Ref.set(promptRpcSucceeded, true), Ref.set(promptResultRef, promptResult)])), Effect.tapError((error) => Ref.set(promptFailureMessageRef, mapAcpToAdapterError(PROVIDER$2, input.threadId, "session/prompt", error).message).pipe(Effect.andThen(prepared.acp.drainEvents))), Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$2, input.threadId, "session/prompt", error)));
80545
81088
  return yield* withThreadLock(input.threadId, Effect.gen(function* () {
80546
81089
  const ctx = yield* requireSession(input.threadId);
80547
81090
  if (ctx.acpSessionId !== prepared.acpSessionId) {
@@ -80551,7 +81094,7 @@ function makeGrokAdapter(grokSettings, options) {
80551
81094
  });
80552
81095
  yield* Ref.set(promptSettled, true);
80553
81096
  return yield* new ProviderAdapterRequestError({
80554
- provider: PROVIDER$1,
81097
+ provider: PROVIDER$2,
80555
81098
  method: "session/prompt",
80556
81099
  detail: "Grok session changed before the turn completed."
80557
81100
  });
@@ -80606,7 +81149,7 @@ function makeGrokAdapter(grokSettings, options) {
80606
81149
  yield* offerRuntimeEvent({
80607
81150
  type: "turn.completed",
80608
81151
  ...yield* makeEventStamp(),
80609
- provider: PROVIDER$1,
81152
+ provider: PROVIDER$2,
80610
81153
  threadId: input.threadId,
80611
81154
  turnId: prepared.turnId,
80612
81155
  payload: {
@@ -80676,7 +81219,7 @@ function makeGrokAdapter(grokSettings, options) {
80676
81219
  const interruptedTurnId = observed.interruptedTurnId ?? turnId ?? activeTurnId ?? ctx.session.activeTurnId;
80677
81220
  yield* settlePendingApprovalsAsCancelled(ctx.pendingApprovals);
80678
81221
  yield* settlePendingUserInputsAsCancelled(ctx.pendingUserInputs);
80679
- yield* Effect.ignore(ctx.acp.cancel.pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$1, threadId, "session/cancel", error))));
81222
+ yield* Effect.ignore(ctx.acp.cancel.pipe(Effect.mapError((error) => mapAcpToAdapterError(PROVIDER$2, threadId, "session/cancel", error))));
80680
81223
  if (interruptedTurnId) {
80681
81224
  ctx.interruptedTurnIds.add(interruptedTurnId);
80682
81225
  yield* settlePromptInFlight(threadId, interruptedTurnId, ctx.acpSessionId, {
@@ -80699,7 +81242,7 @@ function makeGrokAdapter(grokSettings, options) {
80699
81242
  const respondToRequest = (threadId, requestId, decision) => Effect.gen(function* () {
80700
81243
  const pending = (yield* requireSession(threadId)).pendingApprovals.get(requestId);
80701
81244
  if (!pending) return yield* new ProviderAdapterRequestError({
80702
- provider: PROVIDER$1,
81245
+ provider: PROVIDER$2,
80703
81246
  method: "session/request_permission",
80704
81247
  detail: `Unknown pending approval request: ${requestId}`
80705
81248
  });
@@ -80708,7 +81251,7 @@ function makeGrokAdapter(grokSettings, options) {
80708
81251
  const respondToUserInput = (threadId, requestId, answers) => Effect.gen(function* () {
80709
81252
  const pending = (yield* requireSession(threadId)).pendingUserInputs.get(requestId);
80710
81253
  if (!pending) return yield* new ProviderAdapterRequestError({
80711
- provider: PROVIDER$1,
81254
+ provider: PROVIDER$2,
80712
81255
  method: "_x.ai/ask_user_question",
80713
81256
  detail: `Unknown pending user-input request: ${requestId}`
80714
81257
  });
@@ -80726,12 +81269,12 @@ function makeGrokAdapter(grokSettings, options) {
80726
81269
  const rollbackThread = (threadId, numTurns) => Effect.gen(function* () {
80727
81270
  yield* requireSession(threadId);
80728
81271
  if (!Number.isInteger(numTurns) || numTurns < 1) return yield* new ProviderAdapterValidationError({
80729
- provider: PROVIDER$1,
81272
+ provider: PROVIDER$2,
80730
81273
  operation: "rollbackThread",
80731
81274
  issue: "numTurns must be an integer >= 1."
80732
81275
  });
80733
81276
  return yield* new ProviderAdapterRequestError({
80734
- provider: PROVIDER$1,
81277
+ provider: PROVIDER$2,
80735
81278
  method: "thread/rollback",
80736
81279
  detail: "Grok ACP sessions do not support provider-side rollback yet."
80737
81280
  });
@@ -80749,7 +81292,7 @@ function makeGrokAdapter(grokSettings, options) {
80749
81292
  yield* Effect.addFinalizer(() => Effect.ignore(stopAll()).pipe(Effect.tap(() => PubSub.shutdown(runtimeEventPubSub)), Effect.tap(() => managedNativeEventLogger?.close() ?? Effect.void)));
80750
81293
  const streamEvents = Stream.fromPubSub(runtimeEventPubSub);
80751
81294
  return {
80752
- provider: PROVIDER$1,
81295
+ provider: PROVIDER$2,
80753
81296
  capabilities: { sessionModelSwitch: "in-session" },
80754
81297
  startSession,
80755
81298
  sendTurn,
@@ -80774,14 +81317,14 @@ const GROK_PRESENTATION = {
80774
81317
  showInteractionModeToggle: false,
80775
81318
  requiresNewThreadForModelChange: true
80776
81319
  };
80777
- const EMPTY_CAPABILITIES = createModelCapabilities({ optionDescriptors: [] });
80778
- const VERSION_PROBE_TIMEOUT_MS = 4e3;
81320
+ const EMPTY_CAPABILITIES$1 = createModelCapabilities({ optionDescriptors: [] });
81321
+ const VERSION_PROBE_TIMEOUT_MS$1 = 4e3;
80779
81322
  const GROK_ACP_MODEL_DISCOVERY_TIMEOUT_MS = 15e3;
80780
81323
  const GROK_BUILT_IN_MODELS = [{
80781
81324
  slug: "grok-build",
80782
81325
  name: "Grok Build",
80783
81326
  isCustom: false,
80784
- capabilities: EMPTY_CAPABILITIES
81327
+ capabilities: EMPTY_CAPABILITIES$1
80785
81328
  }];
80786
81329
  function buildInitialGrokProviderSnapshot(grokSettings) {
80787
81330
  return Effect.gen(function* () {
@@ -80816,7 +81359,7 @@ function buildInitialGrokProviderSnapshot(grokSettings) {
80816
81359
  });
80817
81360
  }
80818
81361
  function grokModelsFromSettings(customModels, builtInModels = GROK_BUILT_IN_MODELS) {
80819
- return providerModelsFromSettings(builtInModels, customModels ?? [], EMPTY_CAPABILITIES);
81362
+ return providerModelsFromSettings(builtInModels, customModels ?? [], EMPTY_CAPABILITIES$1);
80820
81363
  }
80821
81364
  function buildGrokDiscoveredModelsFromSessionModelState(modelState) {
80822
81365
  if (!modelState || modelState.availableModels.length === 0) return [];
@@ -80829,7 +81372,7 @@ function buildGrokDiscoveredModelsFromSessionModelState(modelState) {
80829
81372
  slug,
80830
81373
  name: model.name.trim() || slug,
80831
81374
  isCustom: false,
80832
- capabilities: EMPTY_CAPABILITIES
81375
+ capabilities: EMPTY_CAPABILITIES$1
80833
81376
  };
80834
81377
  }).filter((model) => model !== void 0);
80835
81378
  }
@@ -80869,7 +81412,7 @@ const checkGrokProviderStatus = Effect.fn("checkGrokProviderStatus")(function* (
80869
81412
  message: "Grok is disabled in P4Code settings."
80870
81413
  }
80871
81414
  });
80872
- const versionResult = yield* runGrokVersionCommand(grokSettings, environment).pipe(Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS), Effect.result);
81415
+ const versionResult = yield* runGrokVersionCommand(grokSettings, environment).pipe(Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS$1), Effect.result);
80873
81416
  if (Result.isFailure(versionResult)) {
80874
81417
  const error = versionResult.failure;
80875
81418
  const missing = isCommandMissingCause(error);
@@ -80978,22 +81521,22 @@ const enrichGrokSnapshot = (input) => {
80978
81521
  //#endregion
80979
81522
  //#region src/provider/Drivers/GrokDriver.ts
80980
81523
  const decodeGrokSettings = Schema$1.decodeSync(GrokSettings);
80981
- const DRIVER_KIND$1 = ProviderDriverKind.make("grok");
80982
- const SNAPSHOT_REFRESH_INTERVAL$1 = Duration.minutes(5);
80983
- const UPDATE$1 = makeStaticProviderMaintenanceResolver(makeManualOnlyProviderMaintenanceCapabilities({
80984
- provider: DRIVER_KIND$1,
81524
+ const DRIVER_KIND$2 = ProviderDriverKind.make("grok");
81525
+ const SNAPSHOT_REFRESH_INTERVAL$2 = Duration.minutes(5);
81526
+ const UPDATE$2 = makeStaticProviderMaintenanceResolver(makeManualOnlyProviderMaintenanceCapabilities({
81527
+ provider: DRIVER_KIND$2,
80985
81528
  packageName: null
80986
81529
  }));
80987
- const withInstanceIdentity$1 = (input) => (snapshot) => ({
81530
+ const withInstanceIdentity$2 = (input) => (snapshot) => ({
80988
81531
  ...snapshot,
80989
81532
  instanceId: input.instanceId,
80990
- driver: DRIVER_KIND$1,
81533
+ driver: DRIVER_KIND$2,
80991
81534
  ...input.displayName ? { displayName: input.displayName } : {},
80992
81535
  ...input.accentColor ? { accentColor: input.accentColor } : {},
80993
81536
  continuation: { groupKey: input.continuationGroupKey }
80994
81537
  });
80995
81538
  const GrokDriver = {
80996
- driverKind: DRIVER_KIND$1,
81539
+ driverKind: DRIVER_KIND$2,
80997
81540
  metadata: {
80998
81541
  displayName: "Grok",
80999
81542
  supportsMultipleInstances: true
@@ -81008,10 +81551,10 @@ const GrokDriver = {
81008
81551
  const eventLoggers = yield* ProviderEventLoggers;
81009
81552
  const processEnv = mergeProviderInstanceEnvironment(environment);
81010
81553
  const continuationIdentity = defaultProviderContinuationIdentity({
81011
- driverKind: DRIVER_KIND$1,
81554
+ driverKind: DRIVER_KIND$2,
81012
81555
  instanceId
81013
81556
  });
81014
- const stampIdentity = withInstanceIdentity$1({
81557
+ const stampIdentity = withInstanceIdentity$2({
81015
81558
  instanceId,
81016
81559
  displayName,
81017
81560
  accentColor,
@@ -81021,7 +81564,7 @@ const GrokDriver = {
81021
81564
  ...config,
81022
81565
  enabled
81023
81566
  };
81024
- const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$1, {
81567
+ const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$2, {
81025
81568
  binaryPath: effectiveConfig.binaryPath,
81026
81569
  env: processEnv
81027
81570
  });
@@ -81047,11 +81590,1467 @@ const GrokDriver = {
81047
81590
  publishSnapshot,
81048
81591
  httpClient
81049
81592
  }),
81593
+ refreshInterval: SNAPSHOT_REFRESH_INTERVAL$2
81594
+ }).pipe(Effect.mapError((cause) => new ProviderDriverError({
81595
+ driver: DRIVER_KIND$2,
81596
+ instanceId,
81597
+ detail: `Failed to build Grok snapshot: ${cause.message ?? String(cause)}`,
81598
+ cause
81599
+ })));
81600
+ return {
81601
+ instanceId,
81602
+ driverKind: DRIVER_KIND$2,
81603
+ continuationIdentity,
81604
+ displayName,
81605
+ accentColor,
81606
+ enabled,
81607
+ snapshot,
81608
+ adapter,
81609
+ textGeneration
81610
+ };
81611
+ })
81612
+ };
81613
+ /**
81614
+ * Build the argument vector for one turn.
81615
+ *
81616
+ * Approval policy is the load-bearing decision here. A headless Muse run has
81617
+ * no channel to answer an approval prompt — the CLI only offers
81618
+ * `--disable-approval` (keep the OS sandbox) and `--yolo` (drop approval and
81619
+ * the sandbox, and trust the workspace). P4Code owns the user-facing runtime
81620
+ * mode, so it maps onto those two postures:
81621
+ *
81622
+ * - `full-access` → `--yolo`
81623
+ * - everything else → `--disable-approval --trust-workspace`, leaving the
81624
+ * sandbox to contain what runs.
81625
+ *
81626
+ * `approval-required` cannot be honoured; the adapter emits a
81627
+ * `config.warning` for it rather than silently pretending otherwise.
81628
+ */
81629
+ function buildMuseExecArgs(input) {
81630
+ const args = [
81631
+ "exec",
81632
+ "--json",
81633
+ "--session-id",
81634
+ input.sessionId
81635
+ ];
81636
+ if (input.model) args.push("--model", input.model);
81637
+ if (input.reasoningEffort) args.push("--reasoning-effort", input.reasoningEffort);
81638
+ if (input.baseUrl) args.push("--base-url", input.baseUrl);
81639
+ if (input.runtimeMode === "full-access") args.push("--yolo");
81640
+ else {
81641
+ args.push("--disable-approval", "--trust-workspace");
81642
+ switch (input.sandboxMode) {
81643
+ case "danger-full-access":
81644
+ args.push("--disable-sandbox");
81645
+ break;
81646
+ case "read-only":
81647
+ args.push("--disable-write", "--disable-shell");
81648
+ break;
81649
+ default: break;
81650
+ }
81651
+ }
81652
+ for (const imagePath of input.imagePaths ?? []) args.push("--image", imagePath);
81653
+ args.push(input.prompt);
81654
+ return args;
81655
+ }
81656
+ /** `muse --version` argv, used by the provider status probe. */
81657
+ const MUSE_VERSION_ARGS = ["--version"];
81658
+ /**
81659
+ * Whether a runtime mode asks for interactive approvals that Muse Code
81660
+ * cannot deliver headlessly.
81661
+ */
81662
+ function museApprovalsUnsupported(runtimeMode) {
81663
+ return runtimeMode === "approval-required";
81664
+ }
81665
+ //#endregion
81666
+ //#region src/provider/muse/MuseExecEvents.ts
81667
+ /**
81668
+ * MuseExecEvents — pure translation of `muse exec --json` JSONL records into
81669
+ * canonical `ProviderRuntimeEvent`s.
81670
+ *
81671
+ * Muse Code has no ACP or app-server surface (verified against CLI
81672
+ * 0.1.0-R708.1): the only scriptable path is `muse exec --json`, which runs
81673
+ * one prompt to completion and prints one JSON object per line. Multi-turn
81674
+ * threads are rebuilt by re-invoking with `--session-id`.
81675
+ *
81676
+ * Everything here is a pure function over a caller-owned state record so the
81677
+ * mapping can be tested against captured CLI output without spawning a
81678
+ * process. Process ownership lives in `MuseExecRuntime`.
81679
+ *
81680
+ * @module provider/muse/MuseExecEvents
81681
+ */
81682
+ /** Longest tool result text carried on an `item.completed` detail. */
81683
+ const MAX_TOOL_DETAIL_CHARS = 2e3;
81684
+ function makeMuseExecTurnState() {
81685
+ return {
81686
+ modelId: void 0,
81687
+ assistantItemStarted: false,
81688
+ assistantText: "",
81689
+ toolNameByTaskId: /* @__PURE__ */ new Map(),
81690
+ taskIdByCallId: /* @__PURE__ */ new Map(),
81691
+ settledToolTaskIds: /* @__PURE__ */ new Set(),
81692
+ terminal: void 0
81693
+ };
81694
+ }
81695
+ /**
81696
+ * Decode one line of `muse exec --json`. Returns `undefined` for blank lines
81697
+ * and for anything that is not a JSON object with a string `payload_type`, so
81698
+ * a stray line can never abort a turn.
81699
+ */
81700
+ function parseMuseExecLine(line) {
81701
+ const trimmed = line.trim();
81702
+ if (trimmed.length === 0) return void 0;
81703
+ let decoded;
81704
+ try {
81705
+ decoded = JSON.parse(trimmed);
81706
+ } catch {
81707
+ return;
81708
+ }
81709
+ if (!isRecord$1(decoded)) return void 0;
81710
+ const payloadType = decoded["payload_type"];
81711
+ if (typeof payloadType !== "string") return void 0;
81712
+ const payload = isRecord$1(decoded["payload"]) ? decoded["payload"] : {};
81713
+ const stream = isRecord$1(decoded["stream"]) ? decoded["stream"] : void 0;
81714
+ const streamId = stream?.["id"];
81715
+ const sequence = decoded["sequence"];
81716
+ return {
81717
+ payloadType,
81718
+ payload,
81719
+ sequence: typeof sequence === "number" ? sequence : void 0,
81720
+ sessionId: stream?.["kind"] === "session" && typeof streamId === "string" ? streamId : void 0
81721
+ };
81722
+ }
81723
+ /**
81724
+ * Map one CLI record onto zero or more event drafts, mutating `state`.
81725
+ *
81726
+ * The CLI stream is deliberately lossy compared with the persisted session
81727
+ * log: tool call *arguments* and token usage never appear on stdout. Those
81728
+ * are recovered separately from `session.jsonl` (see `MuseSessionLog`).
81729
+ */
81730
+ function mapMuseExecRecord(input) {
81731
+ const { record, state, context } = input;
81732
+ const payload = record.payload;
81733
+ switch (record.payloadType) {
81734
+ case "run.model.configured": {
81735
+ const modelId = stringField(payload, "model_id");
81736
+ if (modelId) state.modelId = modelId;
81737
+ return [(stamp) => ({
81738
+ type: "session.configured",
81739
+ ...stamp,
81740
+ ...base(context),
81741
+ payload: { config: payload },
81742
+ raw: rawFrom(record)
81743
+ })];
81744
+ }
81745
+ case "run.lifecycle.started": return [(stamp) => ({
81746
+ type: "turn.started",
81747
+ ...stamp,
81748
+ ...base(context),
81749
+ payload: state.modelId ? { model: state.modelId } : {},
81750
+ raw: rawFrom(record)
81751
+ })];
81752
+ case "run.output.delta": {
81753
+ const text = stringField(payload, "text");
81754
+ if (text === void 0 || text.length === 0) return [];
81755
+ return appendAssistantText({
81756
+ text,
81757
+ state,
81758
+ context,
81759
+ record
81760
+ });
81761
+ }
81762
+ case "task.lifecycle.proposed": {
81763
+ const event = eventField(payload);
81764
+ const taskId = stringField(event, "task_id");
81765
+ const toolName = toolNameFromTaskKind(stringField(event, "task_kind"));
81766
+ if (!taskId || !toolName) return [];
81767
+ state.toolNameByTaskId.set(taskId, toolName);
81768
+ return [(stamp) => ({
81769
+ type: "item.started",
81770
+ ...stamp,
81771
+ ...base(context),
81772
+ itemId: RuntimeItemId.make(taskId),
81773
+ payload: {
81774
+ itemType: itemTypeForToolName(toolName),
81775
+ status: "inProgress",
81776
+ title: toolName
81777
+ },
81778
+ raw: rawFrom(record)
81779
+ })];
81780
+ }
81781
+ case "task.lifecycle.side_effect_intent": {
81782
+ const event = eventField(payload);
81783
+ const taskId = stringField(event, "task_id");
81784
+ const callId = toolCallIdFromIdempotencyKey(stringField(event, "idempotency_key"));
81785
+ if (taskId && callId) state.taskIdByCallId.set(callId, taskId);
81786
+ return [];
81787
+ }
81788
+ case "task.lifecycle.output": {
81789
+ const event = eventField(payload);
81790
+ const taskId = stringField(event, "task_id");
81791
+ const chunk = stringField(event, "chunk");
81792
+ if (!taskId || !chunk) return [];
81793
+ const toolName = state.toolNameByTaskId.get(taskId);
81794
+ if (!toolName) return [];
81795
+ const streamKind = itemTypeForToolName(toolName) === "command_execution" ? "command_output" : "file_change_output";
81796
+ return [(stamp) => ({
81797
+ type: "content.delta",
81798
+ ...stamp,
81799
+ ...base(context),
81800
+ itemId: RuntimeItemId.make(taskId),
81801
+ payload: {
81802
+ streamKind,
81803
+ delta: chunk
81804
+ },
81805
+ raw: rawFrom(record)
81806
+ })];
81807
+ }
81808
+ case "tool.result": {
81809
+ const callId = stringField(payload, "call_id");
81810
+ const taskId = callId ? state.taskIdByCallId.get(callId) : void 0;
81811
+ if (!taskId) return [];
81812
+ const toolName = state.toolNameByTaskId.get(taskId);
81813
+ state.settledToolTaskIds.add(taskId);
81814
+ const failed = stringField(recordField(payload, "correlation_facts"), "outcome") === "error";
81815
+ const detail = truncate(stringField(payload, "text"), MAX_TOOL_DETAIL_CHARS);
81816
+ const editFacts = recordField(payload, "edit_facts");
81817
+ return [(stamp) => ({
81818
+ type: "item.completed",
81819
+ ...stamp,
81820
+ ...base(context),
81821
+ itemId: RuntimeItemId.make(taskId),
81822
+ payload: {
81823
+ itemType: itemTypeForToolName(toolName),
81824
+ status: failed ? "failed" : "completed",
81825
+ ...toolName ? { title: toolName } : {},
81826
+ ...detail ? { detail } : {},
81827
+ ...editFacts ? { data: editFacts } : {}
81828
+ },
81829
+ raw: rawFrom(record)
81830
+ })];
81831
+ }
81832
+ case "task.lifecycle.failed": {
81833
+ const event = eventField(payload);
81834
+ const taskId = stringField(event, "task_id");
81835
+ if (!taskId) return [];
81836
+ const toolName = state.toolNameByTaskId.get(taskId);
81837
+ if (!toolName || state.settledToolTaskIds.has(taskId)) return [];
81838
+ state.settledToolTaskIds.add(taskId);
81839
+ const detail = truncate(stringField(event, "reason"), MAX_TOOL_DETAIL_CHARS);
81840
+ return [(stamp) => ({
81841
+ type: "item.completed",
81842
+ ...stamp,
81843
+ ...base(context),
81844
+ itemId: RuntimeItemId.make(taskId),
81845
+ payload: {
81846
+ itemType: itemTypeForToolName(toolName),
81847
+ status: "failed",
81848
+ title: toolName,
81849
+ ...detail ? { detail } : {}
81850
+ },
81851
+ raw: rawFrom(record)
81852
+ })];
81853
+ }
81854
+ default: break;
81855
+ }
81856
+ if (record.payloadType.startsWith("run.terminal.")) return mapTerminalRecord({
81857
+ record,
81858
+ state,
81859
+ context
81860
+ });
81861
+ return [];
81862
+ }
81863
+ /**
81864
+ * Terminal record handling. The final `text` is the authoritative assistant
81865
+ * message and is a superset of the streamed deltas (Muse streams the visible
81866
+ * prefix only), so any remainder is flushed as one last delta before the
81867
+ * assistant item closes.
81868
+ */
81869
+ function mapTerminalRecord(input) {
81870
+ const { record, state, context } = input;
81871
+ const terminalState = turnStateFromTerminal(stringField(record.payload, "terminal") ?? record.payloadType.slice(13));
81872
+ state.terminal = terminalState;
81873
+ const drafts = [];
81874
+ const remainder = assistantTextRemainder(state.assistantText, stringField(record.payload, "text"));
81875
+ if (remainder) drafts.push(...appendAssistantText({
81876
+ text: remainder,
81877
+ state,
81878
+ context,
81879
+ record
81880
+ }));
81881
+ if (state.assistantItemStarted) drafts.push((stamp) => ({
81882
+ type: "item.completed",
81883
+ ...stamp,
81884
+ ...base(context),
81885
+ itemId: RuntimeItemId.make(context.assistantItemId),
81886
+ payload: {
81887
+ itemType: "assistant_message",
81888
+ status: "completed"
81889
+ }
81890
+ }));
81891
+ const reason = stringField(record.payload, "reason");
81892
+ drafts.push((stamp) => ({
81893
+ type: "turn.completed",
81894
+ ...stamp,
81895
+ ...base(context),
81896
+ payload: {
81897
+ state: terminalState,
81898
+ ...reason ? { stopReason: reason } : {},
81899
+ ...terminalState === "failed" && reason ? { errorMessage: reason } : {}
81900
+ },
81901
+ raw: rawFrom(record)
81902
+ }));
81903
+ return drafts;
81904
+ }
81905
+ function appendAssistantText(input) {
81906
+ const { text, state, context, record } = input;
81907
+ const drafts = [];
81908
+ if (!state.assistantItemStarted) {
81909
+ state.assistantItemStarted = true;
81910
+ drafts.push((stamp) => ({
81911
+ type: "item.started",
81912
+ ...stamp,
81913
+ ...base(context),
81914
+ itemId: RuntimeItemId.make(context.assistantItemId),
81915
+ payload: {
81916
+ itemType: "assistant_message",
81917
+ status: "inProgress"
81918
+ }
81919
+ }));
81920
+ }
81921
+ state.assistantText += text;
81922
+ drafts.push((stamp) => ({
81923
+ type: "content.delta",
81924
+ ...stamp,
81925
+ ...base(context),
81926
+ itemId: RuntimeItemId.make(context.assistantItemId),
81927
+ payload: {
81928
+ streamKind: "assistant_text",
81929
+ delta: text
81930
+ },
81931
+ raw: rawFrom(record)
81932
+ }));
81933
+ return drafts;
81934
+ }
81935
+ /**
81936
+ * The tail of `finalText` that was never streamed. Returns `undefined` when
81937
+ * the streamed text already covers it, or when the two diverge — a divergent
81938
+ * final text is dropped rather than duplicated into the transcript.
81939
+ */
81940
+ function assistantTextRemainder(streamed, finalText) {
81941
+ if (finalText === void 0 || finalText.length === 0) return void 0;
81942
+ if (streamed.length === 0) return finalText;
81943
+ if (!finalText.startsWith(streamed)) return void 0;
81944
+ const remainder = finalText.slice(streamed.length);
81945
+ return remainder.length > 0 ? remainder : void 0;
81946
+ }
81947
+ function turnStateFromTerminal(terminal) {
81948
+ switch (terminal) {
81949
+ case "completed": return "completed";
81950
+ case "cancelled":
81951
+ case "canceled": return "cancelled";
81952
+ case "interrupted": return "interrupted";
81953
+ default: return "failed";
81954
+ }
81955
+ }
81956
+ /** `tool.write_file` → `write_file`; anything else is not a tool task. */
81957
+ function toolNameFromTaskKind(taskKind) {
81958
+ if (!taskKind || !taskKind.startsWith("tool.")) return void 0;
81959
+ const name = taskKind.slice(5).trim();
81960
+ return name.length > 0 ? name : void 0;
81961
+ }
81962
+ /** `tool:call_019f…` → `call_019f…`. */
81963
+ function toolCallIdFromIdempotencyKey(key) {
81964
+ if (!key || !key.startsWith("tool:")) return void 0;
81965
+ const callId = key.slice(5).trim();
81966
+ return callId.length > 0 ? callId : void 0;
81967
+ }
81968
+ function itemTypeForToolName(toolName) {
81969
+ switch (toolName) {
81970
+ case "bash":
81971
+ case "shell":
81972
+ case "run_command":
81973
+ case "unified_exec": return "command_execution";
81974
+ case "write_file":
81975
+ case "edit_file":
81976
+ case "multi_edit":
81977
+ case "apply_patch":
81978
+ case "delete_file":
81979
+ case "move_file": return "file_change";
81980
+ case "web_search":
81981
+ case "web_fetch": return "web_search";
81982
+ case "view_image": return "image_view";
81983
+ default:
81984
+ if (toolName?.startsWith("subagent_")) return "collab_agent_tool_call";
81985
+ if (toolName?.startsWith("mcp__")) return "mcp_tool_call";
81986
+ return "dynamic_tool_call";
81987
+ }
81988
+ }
81989
+ function base(context) {
81990
+ return {
81991
+ provider: context.provider,
81992
+ ...context.providerInstanceId ? { providerInstanceId: context.providerInstanceId } : {},
81993
+ threadId: context.threadId,
81994
+ turnId: context.turnId
81995
+ };
81996
+ }
81997
+ function rawFrom(record) {
81998
+ return {
81999
+ source: "muse.exec.jsonl",
82000
+ method: record.payloadType,
82001
+ payload: record.payload
82002
+ };
82003
+ }
82004
+ function isRecord$1(value) {
82005
+ return typeof value === "object" && value !== null && !Array.isArray(value);
82006
+ }
82007
+ function stringField(source, key) {
82008
+ const value = source?.[key];
82009
+ return typeof value === "string" && value.length > 0 ? value : void 0;
82010
+ }
82011
+ function recordField(source, key) {
82012
+ const value = source?.[key];
82013
+ return isRecord$1(value) ? value : void 0;
82014
+ }
82015
+ function eventField(payload) {
82016
+ return recordField(payload, "event");
82017
+ }
82018
+ function truncate(value, max) {
82019
+ if (value === void 0) return void 0;
82020
+ const trimmed = value.trim();
82021
+ if (trimmed.length === 0) return void 0;
82022
+ return trimmed.length <= max ? trimmed : `${trimmed.slice(0, max)}…`;
82023
+ }
82024
+ //#endregion
82025
+ //#region src/textGeneration/MuseTextGeneration.ts
82026
+ /**
82027
+ * MuseTextGeneration — commit messages, PR text, branch names and thread
82028
+ * titles through Muse Code.
82029
+ *
82030
+ * Muse has no lightweight completion endpoint behind the CLI, so each request
82031
+ * is one headless `muse exec --json` run with the session log disabled: a
82032
+ * throwaway agent turn whose final text we parse as JSON. Reasoning effort is
82033
+ * pinned low because these are short structured-output tasks and Muse Spark
82034
+ * bills reasoning as output tokens.
82035
+ *
82036
+ * @module textGeneration/MuseTextGeneration
82037
+ */
82038
+ const MUSE_TIMEOUT_MS = 18e4;
82039
+ const MUSE_TEXT_REASONING_EFFORT = "low";
82040
+ /** A structured-output turn should never need to loop; cap it cheaply. */
82041
+ const MUSE_TEXT_MAX_MODEL_STEPS = "8";
82042
+ const isTextGenerationError = Schema$1.is(TextGenerationError);
82043
+ /** Final assistant text from a `muse exec --json` stdout stream. */
82044
+ function museTerminalTextFromJsonl(stdout) {
82045
+ let terminalText;
82046
+ let streamed = "";
82047
+ for (const line of stdout.split("\n")) {
82048
+ const record = parseMuseExecLine(line);
82049
+ if (!record) continue;
82050
+ if (record.payloadType === "run.output.delta") {
82051
+ const delta = record.payload["text"];
82052
+ if (typeof delta === "string") streamed += delta;
82053
+ continue;
82054
+ }
82055
+ if (record.payloadType.startsWith("run.terminal.")) {
82056
+ const text = record.payload["text"];
82057
+ if (typeof text === "string" && text.length > 0) terminalText = text;
82058
+ }
82059
+ }
82060
+ const resolved = terminalText ?? streamed;
82061
+ return resolved.trim().length > 0 ? resolved : void 0;
82062
+ }
82063
+ const makeMuseTextGeneration = (museSettings, environment = process.env) => Effect.sync(() => {
82064
+ const runMuseJson = ({ operation, cwd, prompt, outputSchemaJson, modelSelection }) => Effect.gen(function* () {
82065
+ const binaryPath = museSettings.binaryPath || "muse";
82066
+ const spawnCommand = yield* resolveSpawnCommand(binaryPath, [
82067
+ "exec",
82068
+ "--json",
82069
+ "--no-session-log",
82070
+ "--reasoning-effort",
82071
+ MUSE_TEXT_REASONING_EFFORT,
82072
+ "--max-model-steps",
82073
+ MUSE_TEXT_MAX_MODEL_STEPS,
82074
+ "--disable-approval",
82075
+ "--disable-write",
82076
+ "--disable-shell",
82077
+ ...modelSelection.model ? ["--model", modelSelection.model] : [],
82078
+ ...museSettings.baseUrl ? ["--base-url", museSettings.baseUrl] : [],
82079
+ prompt
82080
+ ], { env: environment });
82081
+ const result = yield* spawnAndCollect(binaryPath, ChildProcess.make(spawnCommand.command, spawnCommand.args, {
82082
+ cwd,
82083
+ env: environment,
82084
+ shell: spawnCommand.shell
82085
+ })).pipe(Effect.timeoutOption(MUSE_TIMEOUT_MS), Effect.flatMap(Option.match({
82086
+ onNone: () => Effect.fail(new TextGenerationError({
82087
+ operation,
82088
+ detail: "Muse Code request timed out."
82089
+ })),
82090
+ onSome: Effect.succeed
82091
+ })), Effect.mapError((cause) => isTextGenerationError(cause) ? cause : new TextGenerationError({
82092
+ operation,
82093
+ detail: "Muse Code request failed.",
82094
+ cause
82095
+ })));
82096
+ const output = museTerminalTextFromJsonl(result.stdout);
82097
+ if (!output) return yield* new TextGenerationError({
82098
+ operation,
82099
+ detail: result.code === 0 ? "Muse Code returned empty output." : `Muse Code exited with code ${result.code}.`
82100
+ });
82101
+ return yield* Schema$1.decodeEffect(Schema$1.fromJsonString(outputSchemaJson))(extractJsonObject(output)).pipe(Effect.catchTags({ SchemaError: (cause) => Effect.fail(new TextGenerationError({
82102
+ operation,
82103
+ detail: "Muse Code returned invalid structured output.",
82104
+ cause
82105
+ })) }));
82106
+ }).pipe(Effect.mapError((cause) => isTextGenerationError(cause) ? cause : new TextGenerationError({
82107
+ operation,
82108
+ detail: "Muse Code text generation failed.",
82109
+ cause
82110
+ })));
82111
+ return {
82112
+ generateCommitMessage: Effect.fn("MuseTextGeneration.generateCommitMessage")(function* (input) {
82113
+ const { prompt, outputSchema } = buildCommitMessagePrompt({
82114
+ branch: input.branch,
82115
+ stagedSummary: input.stagedSummary,
82116
+ stagedPatch: input.stagedPatch,
82117
+ includeBranch: input.includeBranch === true,
82118
+ policy: input.policy
82119
+ });
82120
+ const generated = yield* runMuseJson({
82121
+ operation: "generateCommitMessage",
82122
+ cwd: input.cwd,
82123
+ prompt,
82124
+ outputSchemaJson: outputSchema,
82125
+ modelSelection: input.modelSelection
82126
+ });
82127
+ return {
82128
+ subject: sanitizeCommitSubject(generated.subject),
82129
+ body: generated.body.trim(),
82130
+ ..."branch" in generated && typeof generated.branch === "string" ? { branch: sanitizeFeatureBranchName(generated.branch) } : {}
82131
+ };
82132
+ }),
82133
+ generatePrContent: Effect.fn("MuseTextGeneration.generatePrContent")(function* (input) {
82134
+ const { prompt, outputSchema } = buildPrContentPrompt({
82135
+ baseBranch: input.baseBranch,
82136
+ headBranch: input.headBranch,
82137
+ commitSummary: input.commitSummary,
82138
+ diffSummary: input.diffSummary,
82139
+ diffPatch: input.diffPatch,
82140
+ policy: input.policy,
82141
+ changeRequestTemplate: input.changeRequestTemplate
82142
+ });
82143
+ const generated = yield* runMuseJson({
82144
+ operation: "generatePrContent",
82145
+ cwd: input.cwd,
82146
+ prompt,
82147
+ outputSchemaJson: outputSchema,
82148
+ modelSelection: input.modelSelection
82149
+ });
82150
+ return {
82151
+ title: sanitizePrTitle(generated.title),
82152
+ body: generated.body.trim()
82153
+ };
82154
+ }),
82155
+ generateBranchName: Effect.fn("MuseTextGeneration.generateBranchName")(function* (input) {
82156
+ const { prompt, outputSchema } = buildBranchNamePrompt({
82157
+ message: input.message,
82158
+ attachments: input.attachments
82159
+ });
82160
+ return { branch: sanitizeBranchFragment((yield* runMuseJson({
82161
+ operation: "generateBranchName",
82162
+ cwd: input.cwd,
82163
+ prompt,
82164
+ outputSchemaJson: outputSchema,
82165
+ modelSelection: input.modelSelection
82166
+ })).branch) };
82167
+ }),
82168
+ generateThreadTitle: Effect.fn("MuseTextGeneration.generateThreadTitle")(function* (input) {
82169
+ const { prompt, outputSchema } = buildThreadTitlePrompt({
82170
+ message: input.message,
82171
+ attachments: input.attachments
82172
+ });
82173
+ return { title: sanitizeThreadTitle((yield* runMuseJson({
82174
+ operation: "generateThreadTitle",
82175
+ cwd: input.cwd,
82176
+ prompt,
82177
+ outputSchemaJson: outputSchema,
82178
+ modelSelection: input.modelSelection
82179
+ })).title) };
82180
+ })
82181
+ };
82182
+ });
82183
+ //#endregion
82184
+ //#region src/provider/muse/MuseExecRuntime.ts
82185
+ /**
82186
+ * MuseExecRuntime — one `muse exec --json` child process per turn.
82187
+ *
82188
+ * Muse Code has no long-lived protocol surface: a turn is a process, and the
82189
+ * thread is rebuilt from the CLI's own event-sourced session log when the
82190
+ * next turn passes `--session-id`. This module owns spawning, line framing,
82191
+ * interruption, and exit classification; it knows nothing about canonical
82192
+ * runtime events.
82193
+ *
82194
+ * @module provider/muse/MuseExecRuntime
82195
+ */
82196
+ /** Exit code Muse uses for a turn that failed or was cancelled. */
82197
+ const MUSE_EXIT_FAILED = 1;
82198
+ /** Exit codes produced by SIGINT / SIGTERM. */
82199
+ const MUSE_EXIT_SIGINT = 130;
82200
+ const MUSE_EXIT_SIGTERM = 143;
82201
+ /**
82202
+ * Spawn one turn. The child is bound to the caller's scope, so closing the
82203
+ * scope kills it; `awaitOutcome` is how a caller waits for a clean end.
82204
+ */
82205
+ const runMuseExec = Effect.fn("runMuseExec")(function* (input) {
82206
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
82207
+ const runScope = yield* Scope.Scope;
82208
+ const spawnCommand = yield* resolveSpawnCommand(input.binaryPath, [...input.args], { env: input.environment }).pipe(Effect.mapError((cause) => new ProviderAdapterProcessError({
82209
+ provider: "muse",
82210
+ threadId: input.threadId,
82211
+ detail: `Failed to resolve the Muse Code binary (${input.binaryPath}).`,
82212
+ cause
82213
+ })));
82214
+ const child = yield* spawner.spawn(ChildProcess.make(spawnCommand.command, spawnCommand.args, {
82215
+ cwd: input.cwd,
82216
+ env: input.environment,
82217
+ shell: spawnCommand.shell
82218
+ })).pipe(Effect.provideService(Scope.Scope, runScope), Effect.mapError((cause) => new ProviderAdapterProcessError({
82219
+ provider: "muse",
82220
+ threadId: input.threadId,
82221
+ detail: "Failed to spawn `muse exec`.",
82222
+ cause
82223
+ })));
82224
+ const stderrRef = yield* Ref.make("");
82225
+ const interruptedRef = yield* Ref.make(false);
82226
+ const stdoutFiber = yield* child.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach(input.onLine), Effect.ignore, Effect.forkIn(runScope));
82227
+ const stderrFiber = yield* child.stderr.pipe(Stream.decodeText(), Stream.runForEach((chunk) => Ref.update(stderrRef, (stderr) => `${stderr}${chunk}`.slice(-4e3))), Effect.ignore, Effect.forkIn(runScope));
82228
+ return {
82229
+ awaitOutcome: Effect.gen(function* () {
82230
+ const code = yield* child.exitCode.pipe(Effect.orElseSucceed(() => MUSE_EXIT_FAILED));
82231
+ yield* Fiber.await(stdoutFiber).pipe(Effect.ignore);
82232
+ yield* Fiber.await(stderrFiber).pipe(Effect.ignore);
82233
+ const exitCode = Number(code);
82234
+ const interrupted = yield* Ref.get(interruptedRef);
82235
+ if (exitCode === 0) return { kind: "completed" };
82236
+ if (interrupted || exitCode === MUSE_EXIT_SIGINT || exitCode === MUSE_EXIT_SIGTERM) return { kind: "interrupted" };
82237
+ return {
82238
+ kind: "failed",
82239
+ exitCode,
82240
+ stderr: (yield* Ref.get(stderrRef)).trim()
82241
+ };
82242
+ }),
82243
+ interrupt: Ref.set(interruptedRef, true).pipe(Effect.andThen(child.kill({
82244
+ killSignal: "SIGINT",
82245
+ forceKillAfter: "5 seconds"
82246
+ }).pipe(Effect.ignore)), Effect.asVoid)
82247
+ };
82248
+ });
82249
+ //#endregion
82250
+ //#region src/provider/muse/MuseSessionLog.ts
82251
+ /** Root directory holding Muse Code's per-session event logs. */
82252
+ const museDataRoot = Effect.fn("museDataRoot")(function* (environment = process.env) {
82253
+ const path = yield* Path.Path;
82254
+ const xdgDataHome = environment["XDG_DATA_HOME"]?.trim();
82255
+ const base = xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : path.join(NodeOS.homedir(), ".local", "share");
82256
+ return path.join(base, "muse");
82257
+ });
82258
+ /**
82259
+ * Locate a session log by id. The CLI files logs under the date the session
82260
+ * was created, which we do not know for a resumed session, so the year /
82261
+ * month / day levels are walked. Returns `undefined` when the session has no
82262
+ * log yet (a `--no-session-log` run, or a run that died before its first
82263
+ * flush).
82264
+ */
82265
+ const findMuseSessionLog = Effect.fn("findMuseSessionLog")(function* (input) {
82266
+ const fileSystem = yield* FileSystem.FileSystem;
82267
+ const path = yield* Path.Path;
82268
+ const sessionsRoot = path.join(yield* museDataRoot(input.environment ?? process.env), "sessions");
82269
+ const listing = (directory) => fileSystem.readDirectory(directory).pipe(Effect.orElseSucceed(() => []));
82270
+ const descending = (entries) => [...entries].sort().reverse();
82271
+ for (const year of descending(yield* listing(sessionsRoot))) {
82272
+ const yearPath = path.join(sessionsRoot, year);
82273
+ for (const month of descending(yield* listing(yearPath))) {
82274
+ const monthPath = path.join(yearPath, month);
82275
+ for (const day of descending(yield* listing(monthPath))) {
82276
+ const candidate = path.join(monthPath, day, input.sessionId, "session.jsonl");
82277
+ if (yield* fileSystem.exists(candidate).pipe(Effect.orElseSucceed(() => false))) return candidate;
82278
+ }
82279
+ }
82280
+ }
82281
+ });
82282
+ /**
82283
+ * Sum the token usage recorded in a session log.
82284
+ *
82285
+ * Muse attributes usage per model call (`goal_usage_attribution`), including
82286
+ * the background observer agents, so the totals here cover everything the
82287
+ * session spent — which is what a user reading a token counter expects.
82288
+ */
82289
+ function parseMuseTokenUsage(contents) {
82290
+ let total = {
82291
+ inputTokens: 0,
82292
+ outputTokens: 0,
82293
+ cachedTokens: 0,
82294
+ reasoningTokens: 0
82295
+ };
82296
+ let last;
82297
+ let seen = false;
82298
+ for (const line of contents.split("\n")) {
82299
+ const quantity = usageQuantityFromLine(line);
82300
+ if (!quantity) continue;
82301
+ seen = true;
82302
+ last = quantity;
82303
+ total = {
82304
+ inputTokens: total.inputTokens + quantity.inputTokens,
82305
+ outputTokens: total.outputTokens + quantity.outputTokens,
82306
+ cachedTokens: total.cachedTokens + quantity.cachedTokens,
82307
+ reasoningTokens: total.reasoningTokens + quantity.reasoningTokens
82308
+ };
82309
+ }
82310
+ if (!seen) return void 0;
82311
+ return {
82312
+ usedTokens: total.inputTokens + total.outputTokens,
82313
+ inputTokens: total.inputTokens,
82314
+ cachedInputTokens: total.cachedTokens,
82315
+ outputTokens: total.outputTokens,
82316
+ reasoningOutputTokens: total.reasoningTokens,
82317
+ ...last ? {
82318
+ lastUsedTokens: last.inputTokens + last.outputTokens,
82319
+ lastInputTokens: last.inputTokens,
82320
+ lastCachedInputTokens: last.cachedTokens,
82321
+ lastOutputTokens: last.outputTokens,
82322
+ lastReasoningOutputTokens: last.reasoningTokens
82323
+ } : {},
82324
+ compactsAutomatically: true
82325
+ };
82326
+ }
82327
+ function usageQuantityFromLine(line) {
82328
+ const trimmed = line.trim();
82329
+ if (trimmed.length === 0 || !trimmed.includes("goal_usage_attribution")) return void 0;
82330
+ let decoded;
82331
+ try {
82332
+ decoded = JSON.parse(trimmed);
82333
+ } catch {
82334
+ return;
82335
+ }
82336
+ const quantity = readPath(decoded, [
82337
+ "payload",
82338
+ "event",
82339
+ "record",
82340
+ "quantity"
82341
+ ]);
82342
+ if (!isRecord(quantity)) return void 0;
82343
+ return {
82344
+ inputTokens: nonNegativeInt(quantity["input_tokens"]),
82345
+ outputTokens: nonNegativeInt(quantity["output_tokens"]),
82346
+ cachedTokens: nonNegativeInt(quantity["cached_tokens"]),
82347
+ reasoningTokens: nonNegativeInt(quantity["reasoning_tokens"])
82348
+ };
82349
+ }
82350
+ /** Read a session's cumulative usage, or `undefined` when unavailable. */
82351
+ const readMuseSessionUsage = Effect.fn("readMuseSessionUsage")(function* (input) {
82352
+ const fileSystem = yield* FileSystem.FileSystem;
82353
+ const logPath = yield* findMuseSessionLog(input);
82354
+ if (logPath === void 0) return void 0;
82355
+ const contents = yield* fileSystem.readFileString(logPath).pipe(Effect.orElseSucceed(() => void 0));
82356
+ return contents === void 0 ? void 0 : parseMuseTokenUsage(contents);
82357
+ });
82358
+ /**
82359
+ * Parse one `model-catalog/*.json` document. Hidden rows are dropped: the CLI
82360
+ * marks a row `visibility: "visible"` when it should appear in `/models`.
82361
+ */
82362
+ function parseMuseModelCatalog(contents) {
82363
+ let decoded;
82364
+ try {
82365
+ decoded = JSON.parse(contents);
82366
+ } catch {
82367
+ return [];
82368
+ }
82369
+ const rows = isRecord(decoded) ? decoded["rows"] : void 0;
82370
+ if (!Array.isArray(rows)) return [];
82371
+ const models = [];
82372
+ for (const row of rows) {
82373
+ if (!isRecord(row)) continue;
82374
+ const slug = typeof row["model_id"] === "string" ? row["model_id"].trim() : "";
82375
+ if (slug.length === 0) continue;
82376
+ if (typeof row["visibility"] === "string" && row["visibility"] !== "visible") continue;
82377
+ const label = typeof row["display_label"] === "string" ? row["display_label"].trim() : "";
82378
+ const contextLimit = row["context_limit"];
82379
+ models.push({
82380
+ slug,
82381
+ name: label.length > 0 ? label : slug,
82382
+ contextLimit: typeof contextLimit === "number" && contextLimit > 0 ? contextLimit : void 0,
82383
+ isDefault: row["is_default"] === true
82384
+ });
82385
+ }
82386
+ return models;
82387
+ }
82388
+ /** Read every model row the CLI has cached on disk. */
82389
+ const readMuseModelCatalog = Effect.fn("readMuseModelCatalog")(function* (environment = process.env) {
82390
+ const fileSystem = yield* FileSystem.FileSystem;
82391
+ const path = yield* Path.Path;
82392
+ const catalogRoot = path.join(yield* museDataRoot(environment), "model-catalog");
82393
+ const entries = yield* fileSystem.readDirectory(catalogRoot).pipe(Effect.orElseSucceed(() => []));
82394
+ const bySlug = /* @__PURE__ */ new Map();
82395
+ for (const entry of [...entries].sort()) {
82396
+ if (!entry.endsWith(".json")) continue;
82397
+ const contents = yield* fileSystem.readFileString(path.join(catalogRoot, entry)).pipe(Effect.orElseSucceed(() => void 0));
82398
+ if (contents === void 0) continue;
82399
+ for (const model of parseMuseModelCatalog(contents)) if (!bySlug.has(model.slug)) bySlug.set(model.slug, model);
82400
+ }
82401
+ return [...bySlug.values()];
82402
+ });
82403
+ function readPath(source, keys) {
82404
+ let current = source;
82405
+ for (const key of keys) {
82406
+ if (!isRecord(current)) return void 0;
82407
+ current = current[key];
82408
+ }
82409
+ return current;
82410
+ }
82411
+ function isRecord(value) {
82412
+ return typeof value === "object" && value !== null && !Array.isArray(value);
82413
+ }
82414
+ function nonNegativeInt(value) {
82415
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : 0;
82416
+ }
82417
+ //#endregion
82418
+ //#region src/provider/Layers/MuseAdapter.ts
82419
+ /**
82420
+ * MuseAdapter — Meta Muse Code as a P4Code provider.
82421
+ *
82422
+ * Muse Code (beta, CLI 0.1.0) exposes no ACP or app-server protocol; the only
82423
+ * scriptable surface is `muse exec --json`, which runs one prompt to
82424
+ * completion and streams JSONL events on stdout. A P4Code thread therefore
82425
+ * maps onto a Muse *session id*: every turn spawns a fresh `muse exec` with
82426
+ * `--session-id`, and Muse replays its own event-sourced session log to
82427
+ * recover the conversation.
82428
+ *
82429
+ * Consequences that are visible to users, and deliberate:
82430
+ *
82431
+ * - **No interactive approvals.** Headless Muse has no channel to answer an
82432
+ * approval prompt, so the adapter runs with approval disabled and lets
82433
+ * Muse's OS sandbox do the containing. `respondToRequest` fails rather
82434
+ * than pretending to route a decision, and `approval-required` threads get
82435
+ * a `config.warning`.
82436
+ * - **No provider-side rollback.** Muse can fork a session interactively but
82437
+ * exposes nothing headless.
82438
+ * - **Tool arguments are not streamed.** They exist only in the on-disk
82439
+ * session log; items carry the tool name, its result text, and Muse's
82440
+ * `edit_facts`.
82441
+ *
82442
+ * @module provider/Layers/MuseAdapter
82443
+ */
82444
+ const PROVIDER$1 = ProviderDriverKind.make("muse");
82445
+ const MUSE_RESUME_VERSION = 1;
82446
+ function museResumeCursor(museSessionId) {
82447
+ return {
82448
+ version: MUSE_RESUME_VERSION,
82449
+ sessionId: museSessionId
82450
+ };
82451
+ }
82452
+ /** Recover a Muse session id from a persisted resume cursor. */
82453
+ function parseMuseResume(raw) {
82454
+ if (typeof raw !== "object" || raw === null) return void 0;
82455
+ const candidate = raw;
82456
+ if (candidate.version !== MUSE_RESUME_VERSION) return void 0;
82457
+ return typeof candidate.sessionId === "string" && candidate.sessionId.length > 0 ? { sessionId: candidate.sessionId } : void 0;
82458
+ }
82459
+ function makeMuseAdapter(museSettings, options) {
82460
+ return Effect.gen(function* () {
82461
+ const boundInstanceId = options?.instanceId ?? ProviderInstanceId.make("muse");
82462
+ const environment = options?.environment ?? process.env;
82463
+ const crypto = yield* Crypto.Crypto;
82464
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
82465
+ const fileSystem = yield* FileSystem.FileSystem;
82466
+ const path = yield* Path.Path;
82467
+ const serverConfig = yield* Effect.service(ServerConfig$1);
82468
+ const sessions = /* @__PURE__ */ new Map();
82469
+ const runtimeEventPubSub = yield* PubSub.unbounded();
82470
+ const nowIso = Effect.map(DateTime.now, DateTime.formatIso);
82471
+ const randomUUIDv4 = crypto.randomUUIDv4.pipe(Effect.mapError((cause) => new ProviderAdapterRequestError({
82472
+ provider: PROVIDER$1,
82473
+ method: "crypto/randomUUIDv4",
82474
+ detail: "Failed to generate a Muse runtime identifier.",
82475
+ cause
82476
+ })));
82477
+ const makeEventStamp = () => Effect.all({
82478
+ eventId: Effect.map(randomUUIDv4, EventId.make),
82479
+ createdAt: nowIso
82480
+ });
82481
+ const publish = (event) => PubSub.publish(runtimeEventPubSub, event).pipe(Effect.asVoid);
82482
+ const requireSession = (threadId) => Effect.suspend(() => {
82483
+ const ctx = sessions.get(threadId);
82484
+ return ctx === void 0 || ctx.stopped ? Effect.fail(new ProviderAdapterSessionNotFoundError({
82485
+ provider: PROVIDER$1,
82486
+ threadId
82487
+ })) : Effect.succeed(ctx);
82488
+ });
82489
+ const startSession = (input) => Effect.gen(function* () {
82490
+ const existing = sessions.get(input.threadId);
82491
+ if (existing && !existing.stopped) return { ...existing.session };
82492
+ const resumed = parseMuseResume(input.resumeCursor);
82493
+ const museSessionId = resumed?.sessionId ?? (yield* randomUUIDv4);
82494
+ const cwd = input.cwd ?? process.cwd();
82495
+ const createdAt = yield* nowIso;
82496
+ const session = {
82497
+ provider: PROVIDER$1,
82498
+ providerInstanceId: boundInstanceId,
82499
+ status: "ready",
82500
+ runtimeMode: input.runtimeMode,
82501
+ cwd,
82502
+ ...input.modelSelection?.model ? { model: input.modelSelection.model } : {},
82503
+ threadId: input.threadId,
82504
+ resumeCursor: museResumeCursor(museSessionId),
82505
+ createdAt,
82506
+ updatedAt: createdAt
82507
+ };
82508
+ const ctx = {
82509
+ threadId: input.threadId,
82510
+ museSessionId,
82511
+ cwd,
82512
+ session,
82513
+ activeTurn: void 0,
82514
+ turns: [],
82515
+ stopped: false
82516
+ };
82517
+ sessions.set(input.threadId, ctx);
82518
+ yield* publish({
82519
+ type: "session.started",
82520
+ ...yield* makeEventStamp(),
82521
+ provider: PROVIDER$1,
82522
+ providerInstanceId: boundInstanceId,
82523
+ threadId: input.threadId,
82524
+ payload: resumed ? { resume: input.resumeCursor } : {}
82525
+ });
82526
+ yield* publish({
82527
+ type: "thread.started",
82528
+ ...yield* makeEventStamp(),
82529
+ provider: PROVIDER$1,
82530
+ providerInstanceId: boundInstanceId,
82531
+ threadId: input.threadId,
82532
+ payload: { providerThreadId: museSessionId }
82533
+ });
82534
+ if (museApprovalsUnsupported(input.runtimeMode)) yield* publish({
82535
+ type: "config.warning",
82536
+ ...yield* makeEventStamp(),
82537
+ provider: PROVIDER$1,
82538
+ providerInstanceId: boundInstanceId,
82539
+ threadId: input.threadId,
82540
+ payload: {
82541
+ summary: "Muse Code cannot ask for approvals in headless runs.",
82542
+ details: "This thread runs with approvals disabled and Muse's OS sandbox enabled; `muse exec` has no channel to answer an approval prompt."
82543
+ }
82544
+ });
82545
+ return { ...session };
82546
+ });
82547
+ const sendTurn = (input) => Effect.gen(function* () {
82548
+ const ctx = yield* requireSession(input.threadId);
82549
+ if (ctx.activeTurn) return yield* new ProviderAdapterRequestError({
82550
+ provider: PROVIDER$1,
82551
+ method: "muse/exec",
82552
+ detail: "A Muse turn is already running on this thread. `muse exec` runs one prompt per process, so turns cannot overlap."
82553
+ });
82554
+ const prompt = input.input?.trim();
82555
+ if (!prompt) return yield* new ProviderAdapterValidationError({
82556
+ provider: PROVIDER$1,
82557
+ operation: "sendTurn",
82558
+ issue: "Muse Code requires prompt text; attachments alone cannot start a turn."
82559
+ });
82560
+ const imagePaths = [];
82561
+ for (const attachment of input.attachments ?? []) {
82562
+ const attachmentPath = resolveAttachmentPath({
82563
+ attachmentsDir: serverConfig.attachmentsDir,
82564
+ attachment
82565
+ });
82566
+ if (!attachmentPath) return yield* new ProviderAdapterRequestError({
82567
+ provider: PROVIDER$1,
82568
+ method: "muse/exec",
82569
+ detail: `Invalid attachment id '${attachment.id}'.`
82570
+ });
82571
+ imagePaths.push(attachmentPath);
82572
+ }
82573
+ const turnId = TurnId.make(yield* randomUUIDv4);
82574
+ const model = input.modelSelection?.model ?? ctx.session.model;
82575
+ const args = buildMuseExecArgs({
82576
+ sessionId: ctx.museSessionId,
82577
+ prompt,
82578
+ model,
82579
+ baseUrl: museSettings.baseUrl || void 0,
82580
+ runtimeMode: ctx.session.runtimeMode,
82581
+ imagePaths
82582
+ });
82583
+ const state = makeMuseExecTurnState();
82584
+ const mappingContext = {
82585
+ provider: PROVIDER$1,
82586
+ providerInstanceId: boundInstanceId,
82587
+ threadId: input.threadId,
82588
+ turnId,
82589
+ assistantItemId: `${turnId}:assistant`
82590
+ };
82591
+ const handleLine = (line) => Effect.gen(function* () {
82592
+ const record = parseMuseExecLine(line);
82593
+ if (!record) return;
82594
+ const drafts = mapMuseExecRecord({
82595
+ record,
82596
+ state,
82597
+ context: mappingContext
82598
+ });
82599
+ for (const draft of drafts) yield* publish(draft(yield* makeEventStamp()));
82600
+ }).pipe(Effect.orElseSucceed(() => void 0));
82601
+ ctx.turns.push({
82602
+ id: turnId,
82603
+ items: []
82604
+ });
82605
+ ctx.session = {
82606
+ ...ctx.session,
82607
+ status: "running",
82608
+ activeTurnId: turnId,
82609
+ updatedAt: yield* nowIso,
82610
+ ...model ? { model } : {}
82611
+ };
82612
+ const turnScope = yield* Scope.make();
82613
+ const run = yield* runMuseExec({
82614
+ threadId: input.threadId,
82615
+ binaryPath: museSettings.binaryPath || "muse",
82616
+ args,
82617
+ cwd: ctx.cwd,
82618
+ environment,
82619
+ onLine: handleLine
82620
+ }).pipe(Effect.provideService(Scope.Scope, turnScope), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.tapError(() => Scope.close(turnScope, Exit.void)));
82621
+ ctx.activeTurn = {
82622
+ turnId,
82623
+ run,
82624
+ state
82625
+ };
82626
+ const outcome = yield* run.awaitOutcome;
82627
+ yield* Scope.close(turnScope, Exit.void);
82628
+ ctx.activeTurn = void 0;
82629
+ if (state.terminal === void 0) if (outcome.kind === "interrupted") yield* publish({
82630
+ type: "turn.aborted",
82631
+ ...yield* makeEventStamp(),
82632
+ provider: PROVIDER$1,
82633
+ providerInstanceId: boundInstanceId,
82634
+ threadId: input.threadId,
82635
+ turnId,
82636
+ payload: { reason: "interrupted" }
82637
+ });
82638
+ else {
82639
+ const detail = outcome.kind === "failed" ? outcome.stderr || `\`muse exec\` exited with code ${outcome.exitCode}.` : "`muse exec` ended without a terminal event.";
82640
+ yield* publish({
82641
+ type: "turn.completed",
82642
+ ...yield* makeEventStamp(),
82643
+ provider: PROVIDER$1,
82644
+ providerInstanceId: boundInstanceId,
82645
+ threadId: input.threadId,
82646
+ turnId,
82647
+ payload: {
82648
+ state: "failed",
82649
+ errorMessage: detail
82650
+ }
82651
+ });
82652
+ }
82653
+ yield* publishTokenUsage(ctx, turnId);
82654
+ const updatedAt = yield* nowIso;
82655
+ const { activeTurnId: _activeTurnId, ...readySession } = ctx.session;
82656
+ ctx.session = {
82657
+ ...readySession,
82658
+ status: "ready",
82659
+ updatedAt
82660
+ };
82661
+ return {
82662
+ threadId: input.threadId,
82663
+ turnId,
82664
+ resumeCursor: museResumeCursor(ctx.museSessionId)
82665
+ };
82666
+ });
82667
+ /**
82668
+ * Token usage never reaches stdout; it is written to the session log. One
82669
+ * read after the turn keeps the counter honest without tailing the file.
82670
+ */
82671
+ const publishTokenUsage = (ctx, turnId) => Effect.gen(function* () {
82672
+ const usage = yield* readMuseSessionUsage({
82673
+ sessionId: ctx.museSessionId,
82674
+ environment
82675
+ }).pipe(Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path), Effect.orElseSucceed(() => void 0));
82676
+ if (!usage) return;
82677
+ yield* publish({
82678
+ type: "thread.token-usage.updated",
82679
+ ...yield* makeEventStamp(),
82680
+ provider: PROVIDER$1,
82681
+ providerInstanceId: boundInstanceId,
82682
+ threadId: ctx.threadId,
82683
+ turnId,
82684
+ payload: { usage }
82685
+ });
82686
+ }).pipe(Effect.orElseSucceed(() => void 0));
82687
+ const interruptTurn = (threadId, turnId) => Effect.gen(function* () {
82688
+ const active = (yield* requireSession(threadId)).activeTurn;
82689
+ if (!active) return;
82690
+ if (turnId !== void 0 && turnId !== active.turnId) return;
82691
+ yield* active.run.interrupt;
82692
+ });
82693
+ const respondToRequest = (threadId) => Effect.gen(function* () {
82694
+ yield* requireSession(threadId);
82695
+ return yield* new ProviderAdapterRequestError({
82696
+ provider: PROVIDER$1,
82697
+ method: "muse/approval",
82698
+ detail: "Muse Code has no approval channel in headless runs, so it never opens an approval request."
82699
+ });
82700
+ });
82701
+ const respondToUserInput = (threadId) => Effect.gen(function* () {
82702
+ yield* requireSession(threadId);
82703
+ return yield* new ProviderAdapterRequestError({
82704
+ provider: PROVIDER$1,
82705
+ method: "muse/user-input",
82706
+ detail: "Muse Code does not ask structured questions in headless runs."
82707
+ });
82708
+ });
82709
+ const readThread = (threadId) => Effect.gen(function* () {
82710
+ return {
82711
+ threadId,
82712
+ turns: (yield* requireSession(threadId)).turns
82713
+ };
82714
+ });
82715
+ const rollbackThread = (threadId, numTurns) => Effect.gen(function* () {
82716
+ yield* requireSession(threadId);
82717
+ if (!Number.isInteger(numTurns) || numTurns < 1) return yield* new ProviderAdapterValidationError({
82718
+ provider: PROVIDER$1,
82719
+ operation: "rollbackThread",
82720
+ issue: "numTurns must be an integer >= 1."
82721
+ });
82722
+ return yield* new ProviderAdapterRequestError({
82723
+ provider: PROVIDER$1,
82724
+ method: "muse/rollback",
82725
+ detail: "Muse Code exposes no headless rollback for a session."
82726
+ });
82727
+ });
82728
+ const stopSessionInternal = (ctx) => Effect.gen(function* () {
82729
+ if (ctx.stopped) return;
82730
+ ctx.stopped = true;
82731
+ if (ctx.activeTurn) {
82732
+ yield* ctx.activeTurn.run.interrupt.pipe(Effect.ignore);
82733
+ ctx.activeTurn = void 0;
82734
+ }
82735
+ const updatedAt = yield* nowIso;
82736
+ ctx.session = {
82737
+ ...ctx.session,
82738
+ status: "closed",
82739
+ updatedAt
82740
+ };
82741
+ sessions.delete(ctx.threadId);
82742
+ yield* publish({
82743
+ type: "session.exited",
82744
+ ...yield* makeEventStamp(),
82745
+ provider: PROVIDER$1,
82746
+ providerInstanceId: boundInstanceId,
82747
+ threadId: ctx.threadId,
82748
+ payload: {
82749
+ reason: "stopped",
82750
+ exitKind: "graceful"
82751
+ }
82752
+ });
82753
+ });
82754
+ const stopSession = (threadId) => Effect.flatMap(requireSession(threadId), stopSessionInternal);
82755
+ const listSessions = () => Effect.sync(() => Array.from(sessions.values(), (ctx) => ({ ...ctx.session })));
82756
+ const hasSession = (threadId) => Effect.sync(() => {
82757
+ const ctx = sessions.get(threadId);
82758
+ return ctx !== void 0 && !ctx.stopped;
82759
+ });
82760
+ const stopAll = () => Effect.forEach(Array.from(sessions.values()), stopSessionInternal, { discard: true });
82761
+ yield* Effect.addFinalizer(() => Effect.ignore(stopAll()).pipe(Effect.tap(() => PubSub.shutdown(runtimeEventPubSub))));
82762
+ return {
82763
+ provider: PROVIDER$1,
82764
+ capabilities: { sessionModelSwitch: "in-session" },
82765
+ startSession,
82766
+ sendTurn,
82767
+ interruptTurn,
82768
+ readThread,
82769
+ rollbackThread,
82770
+ respondToRequest,
82771
+ respondToUserInput,
82772
+ stopSession,
82773
+ listSessions,
82774
+ hasSession,
82775
+ stopAll,
82776
+ streamEvents: Stream.fromPubSub(runtimeEventPubSub)
82777
+ };
82778
+ });
82779
+ }
82780
+ //#endregion
82781
+ //#region src/provider/Layers/MuseProvider.ts
82782
+ const MUSE_PRESENTATION = {
82783
+ displayName: "Muse Code",
82784
+ badgeLabel: "Early Access",
82785
+ showInteractionModeToggle: false,
82786
+ requiresNewThreadForModelChange: false,
82787
+ supportedRuntimeModes: ["auto", "full-access"]
82788
+ };
82789
+ const EMPTY_CAPABILITIES = createModelCapabilities({ optionDescriptors: [] });
82790
+ const VERSION_PROBE_TIMEOUT_MS = 4e3;
82791
+ /** Models Meta documents for Muse Code; used until the CLI caches a catalog. */
82792
+ const MUSE_BUILT_IN_MODELS = [{
82793
+ slug: "muse-spark-1.2",
82794
+ name: "Muse Spark 1.2",
82795
+ isCustom: false,
82796
+ capabilities: EMPTY_CAPABILITIES
82797
+ }, {
82798
+ slug: "muse-spark-1.2-contributor",
82799
+ name: "Muse Spark 1.2 (contributor)",
82800
+ isCustom: false,
82801
+ isDefault: true,
82802
+ capabilities: EMPTY_CAPABILITIES
82803
+ }];
82804
+ function museModelsFromSettings(customModels, builtInModels = MUSE_BUILT_IN_MODELS) {
82805
+ return providerModelsFromSettings(builtInModels, customModels ?? [], EMPTY_CAPABILITIES);
82806
+ }
82807
+ const discoverMuseModels = Effect.fn("discoverMuseModels")(function* (environment) {
82808
+ return (yield* readMuseModelCatalog(environment)).map((model) => ({
82809
+ slug: model.slug,
82810
+ name: model.name,
82811
+ isCustom: false,
82812
+ ...model.isDefault ? { isDefault: true } : {},
82813
+ capabilities: EMPTY_CAPABILITIES
82814
+ }));
82815
+ });
82816
+ /**
82817
+ * What P4Code can tell about Muse credentials without running the CLI.
82818
+ *
82819
+ * `META_API_KEY` takes priority inside Muse itself, then a stored key or
82820
+ * browser session in `~/.config/muse/auth.json`. Neither says whether the
82821
+ * credential is still valid, so a present credential reports
82822
+ * `authenticated` with the source as its label and a missing one reports
82823
+ * `unauthenticated`.
82824
+ */
82825
+ const checkMuseAuth = Effect.fn("checkMuseAuth")(function* (environment) {
82826
+ if (environment["META_API_KEY"]?.trim()) return {
82827
+ status: "authenticated",
82828
+ type: "api-key",
82829
+ label: "META_API_KEY"
82830
+ };
82831
+ const fileSystem = yield* FileSystem.FileSystem;
82832
+ const path = yield* Path.Path;
82833
+ const configHome = environment["XDG_CONFIG_HOME"]?.trim();
82834
+ const authPath = path.join(configHome && configHome.length > 0 ? configHome : path.join(NodeOS.homedir(), ".config"), "muse", "auth.json");
82835
+ return (yield* fileSystem.exists(authPath).pipe(Effect.orElseSucceed(() => false))) ? {
82836
+ status: "authenticated",
82837
+ type: "cli",
82838
+ label: "muse login"
82839
+ } : { status: "unauthenticated" };
82840
+ });
82841
+ function buildInitialMuseProviderSnapshot(museSettings) {
82842
+ return Effect.gen(function* () {
82843
+ const checkedAt = yield* Effect.map(DateTime.now, DateTime.formatIso);
82844
+ const models = museModelsFromSettings(museSettings.customModels);
82845
+ return buildServerProvider({
82846
+ presentation: MUSE_PRESENTATION,
82847
+ enabled: museSettings.enabled,
82848
+ checkedAt,
82849
+ models,
82850
+ probe: museSettings.enabled ? {
82851
+ installed: true,
82852
+ version: null,
82853
+ status: "warning",
82854
+ auth: { status: "unknown" },
82855
+ message: "Checking Muse Code CLI availability..."
82856
+ } : {
82857
+ installed: false,
82858
+ version: null,
82859
+ status: "warning",
82860
+ auth: { status: "unknown" },
82861
+ message: "Muse Code is disabled in P4Code settings."
82862
+ }
82863
+ });
82864
+ });
82865
+ }
82866
+ const runMuseVersionCommand = (museSettings, environment) => Effect.gen(function* () {
82867
+ const command = museSettings.binaryPath || "muse";
82868
+ const spawnCommand = yield* resolveSpawnCommand(command, [...MUSE_VERSION_ARGS], { env: environment });
82869
+ return yield* spawnAndCollect(command, ChildProcess.make(spawnCommand.command, spawnCommand.args, {
82870
+ env: environment,
82871
+ shell: spawnCommand.shell
82872
+ }));
82873
+ });
82874
+ const checkMuseProviderStatus = Effect.fn("checkMuseProviderStatus")(function* (museSettings, environment = process.env) {
82875
+ const checkedAt = DateTime.formatIso(yield* DateTime.now);
82876
+ const fallbackModels = museModelsFromSettings(museSettings.customModels);
82877
+ if (!museSettings.enabled) return buildServerProvider({
82878
+ presentation: MUSE_PRESENTATION,
82879
+ enabled: false,
82880
+ checkedAt,
82881
+ models: fallbackModels,
82882
+ probe: {
82883
+ installed: false,
82884
+ version: null,
82885
+ status: "warning",
82886
+ auth: { status: "unknown" },
82887
+ message: "Muse Code is disabled in P4Code settings."
82888
+ }
82889
+ });
82890
+ const versionResult = yield* runMuseVersionCommand(museSettings, environment).pipe(Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS), Effect.result);
82891
+ if (Result.isFailure(versionResult)) {
82892
+ const error = versionResult.failure;
82893
+ const missing = isCommandMissingCause(error);
82894
+ yield* (missing ? Effect.logDebug : Effect.logWarning)("Muse Code CLI health check failed.", { errorTag: error._tag });
82895
+ return buildServerProvider({
82896
+ presentation: MUSE_PRESENTATION,
82897
+ enabled: true,
82898
+ checkedAt,
82899
+ models: fallbackModels,
82900
+ probe: {
82901
+ installed: !missing,
82902
+ version: null,
82903
+ status: "error",
82904
+ auth: { status: "unknown" },
82905
+ message: missing ? "Muse Code CLI (`muse`) is not installed or not on PATH. Install it with `curl -fsSL https://dev.meta.ai/install.sh | sh`." : "Failed to execute the Muse Code CLI health check."
82906
+ }
82907
+ });
82908
+ }
82909
+ if (Option.isNone(versionResult.success)) return buildServerProvider({
82910
+ presentation: MUSE_PRESENTATION,
82911
+ enabled: true,
82912
+ checkedAt,
82913
+ models: fallbackModels,
82914
+ probe: {
82915
+ installed: true,
82916
+ version: null,
82917
+ status: "error",
82918
+ auth: { status: "unknown" },
82919
+ message: "Muse Code CLI is installed but timed out while running `muse --version`."
82920
+ }
82921
+ });
82922
+ const versionOutput = versionResult.success.value;
82923
+ const version = parseGenericCliVersion(`${versionOutput.stdout}\n${versionOutput.stderr}`);
82924
+ const auth = yield* checkMuseAuth(environment);
82925
+ if (versionOutput.code !== 0) {
82926
+ yield* Effect.logWarning("Muse Code CLI version probe exited with a non-zero status.", {
82927
+ exitCode: versionOutput.code,
82928
+ stdoutLength: versionOutput.stdout.length,
82929
+ stderrLength: versionOutput.stderr.length
82930
+ });
82931
+ return buildServerProvider({
82932
+ presentation: MUSE_PRESENTATION,
82933
+ enabled: true,
82934
+ checkedAt,
82935
+ models: fallbackModels,
82936
+ probe: {
82937
+ installed: true,
82938
+ version,
82939
+ status: "error",
82940
+ auth,
82941
+ message: "Muse Code CLI is installed but failed to run."
82942
+ }
82943
+ });
82944
+ }
82945
+ const discovered = yield* discoverMuseModels(environment);
82946
+ const models = discovered.length > 0 ? museModelsFromSettings(museSettings.customModels, discovered) : fallbackModels;
82947
+ if (auth.status !== "authenticated") return buildServerProvider({
82948
+ presentation: MUSE_PRESENTATION,
82949
+ enabled: true,
82950
+ checkedAt,
82951
+ models,
82952
+ probe: {
82953
+ installed: true,
82954
+ version,
82955
+ status: "warning",
82956
+ auth,
82957
+ message: "Muse Code is installed but not signed in. Run `muse login`, or set META_API_KEY."
82958
+ }
82959
+ });
82960
+ return buildServerProvider({
82961
+ presentation: MUSE_PRESENTATION,
82962
+ enabled: true,
82963
+ checkedAt,
82964
+ models,
82965
+ probe: {
82966
+ installed: true,
82967
+ version,
82968
+ status: "ready",
82969
+ auth
82970
+ }
82971
+ });
82972
+ });
82973
+ const enrichMuseSnapshot = (input) => enrichProviderSnapshotWithVersionAdvisory(input.snapshot, input.maintenanceCapabilities, { enableProviderUpdateChecks: input.enableProviderUpdateChecks }).pipe(Effect.provideService(HttpClient.HttpClient, input.httpClient), Effect.flatMap((enrichedSnapshot) => input.publishSnapshot(enrichedSnapshot)), Effect.catchCause((cause) => Effect.logWarning("Muse version advisory enrichment failed", { errorTag: causeErrorTag(cause) })), Effect.asVoid);
82974
+ //#endregion
82975
+ //#region src/provider/Drivers/MuseDriver.ts
82976
+ /**
82977
+ * MuseDriver — first-party driver for Meta's Muse Code CLI.
82978
+ *
82979
+ * @module provider/Drivers/MuseDriver
82980
+ */
82981
+ const decodeMuseSettings = Schema$1.decodeSync(MuseSettings);
82982
+ const DRIVER_KIND$1 = ProviderDriverKind.make("muse");
82983
+ const SNAPSHOT_REFRESH_INTERVAL$1 = Duration.minutes(5);
82984
+ const UPDATE$1 = makeStaticProviderMaintenanceResolver(makeManualOnlyProviderMaintenanceCapabilities({
82985
+ provider: DRIVER_KIND$1,
82986
+ packageName: null
82987
+ }));
82988
+ const withInstanceIdentity$1 = (input) => (snapshot) => ({
82989
+ ...snapshot,
82990
+ instanceId: input.instanceId,
82991
+ driver: DRIVER_KIND$1,
82992
+ ...input.displayName ? { displayName: input.displayName } : {},
82993
+ ...input.accentColor ? { accentColor: input.accentColor } : {},
82994
+ continuation: { groupKey: input.continuationGroupKey }
82995
+ });
82996
+ const MuseDriver = {
82997
+ driverKind: DRIVER_KIND$1,
82998
+ metadata: {
82999
+ displayName: "Muse Code",
83000
+ supportsMultipleInstances: true
83001
+ },
83002
+ configSchema: MuseSettings,
83003
+ defaultConfig: () => decodeMuseSettings({}),
83004
+ create: ({ instanceId, displayName, accentColor, environment, enabled, config }) => Effect.gen(function* () {
83005
+ const httpClient = yield* HttpClient.HttpClient;
83006
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
83007
+ const fileSystem = yield* FileSystem.FileSystem;
83008
+ const path = yield* Path.Path;
83009
+ const serverSettings = yield* ServerSettingsService;
83010
+ const processEnv = mergeProviderInstanceEnvironment(environment);
83011
+ const continuationIdentity = defaultProviderContinuationIdentity({
83012
+ driverKind: DRIVER_KIND$1,
83013
+ instanceId
83014
+ });
83015
+ const stampIdentity = withInstanceIdentity$1({
83016
+ instanceId,
83017
+ displayName,
83018
+ accentColor,
83019
+ continuationGroupKey: continuationIdentity.continuationKey
83020
+ });
83021
+ const effectiveConfig = {
83022
+ ...config,
83023
+ enabled
83024
+ };
83025
+ const maintenanceCapabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(UPDATE$1, {
83026
+ binaryPath: effectiveConfig.binaryPath,
83027
+ env: processEnv
83028
+ });
83029
+ const adapter = yield* makeMuseAdapter(effectiveConfig, {
83030
+ environment: processEnv,
83031
+ instanceId
83032
+ });
83033
+ const textGeneration = yield* makeMuseTextGeneration(effectiveConfig, processEnv);
83034
+ const snapshotSettings = makeProviderSnapshotSettingsSource(effectiveConfig, serverSettings);
83035
+ const snapshot = yield* makeManagedServerProvider({
83036
+ maintenanceCapabilities,
83037
+ getSettings: snapshotSettings.getSettings,
83038
+ streamSettings: snapshotSettings.streamSettings,
83039
+ haveSettingsChanged: haveProviderSnapshotSettingsChanged,
83040
+ initialSnapshot: (settings) => buildInitialMuseProviderSnapshot(settings.provider).pipe(Effect.map(stampIdentity)),
83041
+ checkProvider: checkMuseProviderStatus(effectiveConfig, processEnv).pipe(Effect.map(stampIdentity), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner), Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path)),
83042
+ enrichSnapshot: ({ settings, snapshot: currentSnapshot, publishSnapshot }) => enrichMuseSnapshot({
83043
+ snapshot: currentSnapshot,
83044
+ maintenanceCapabilities,
83045
+ enableProviderUpdateChecks: settings.enableProviderUpdateChecks,
83046
+ publishSnapshot,
83047
+ httpClient
83048
+ }),
81050
83049
  refreshInterval: SNAPSHOT_REFRESH_INTERVAL$1
81051
83050
  }).pipe(Effect.mapError((cause) => new ProviderDriverError({
81052
83051
  driver: DRIVER_KIND$1,
81053
83052
  instanceId,
81054
- detail: `Failed to build Grok snapshot: ${cause.message ?? String(cause)}`,
83053
+ detail: `Failed to build Muse snapshot: ${cause.message ?? String(cause)}`,
81055
83054
  cause
81056
83055
  })));
81057
83056
  return {
@@ -82737,6 +84736,7 @@ const BUILT_IN_DRIVERS = [
82737
84736
  ClaudeDriver,
82738
84737
  CursorDriver,
82739
84738
  GrokDriver,
84739
+ MuseDriver,
82740
84740
  {
82741
84741
  driverKind: DRIVER_KIND,
82742
84742
  metadata: {
@@ -84135,6 +86135,24 @@ function runtimeEventToActivities(event, taskTitle) {
84135
86135
  turnId: toTurnId$1(event.turnId) ?? null,
84136
86136
  ...maybeSequence
84137
86137
  }];
86138
+ case "code.published": {
86139
+ const label = event.payload.repo ? event.payload.identifier ? `${event.payload.repo}#${event.payload.identifier}` : event.payload.repo : event.payload.url;
86140
+ return [{
86141
+ id: event.eventId,
86142
+ createdAt: event.createdAt,
86143
+ tone: "info",
86144
+ kind: "code.published",
86145
+ summary: `Published ${label}`,
86146
+ payload: {
86147
+ hostingProvider: event.payload.hostingProvider,
86148
+ url: event.payload.url,
86149
+ ...event.payload.repo ? { repo: event.payload.repo } : {},
86150
+ ...event.payload.identifier ? { identifier: event.payload.identifier } : {}
86151
+ },
86152
+ turnId: toTurnId$1(event.turnId) ?? null,
86153
+ ...maybeSequence
86154
+ }];
86155
+ }
84138
86156
  case "turn.plan.updated": return [{
84139
86157
  id: event.eventId,
84140
86158
  createdAt: event.createdAt,
@@ -87266,6 +89284,7 @@ const reportUpdateAvailable = Effect.gen(function* () {
87266
89284
  const makeCli = () => Command.make("p4c", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server."), Command.withHandler((flags) => runServerCommand(flags)), Command.withSubcommands([
87267
89285
  startCommand,
87268
89286
  serveCommand,
89287
+ agentsCommand,
87269
89288
  authCommand,
87270
89289
  hubCommand,
87271
89290
  mcpCommand,