@p4code/cli 0.1.11 → 0.1.13

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 (87) hide show
  1. package/dist/bin.mjs +410 -30
  2. package/dist/client/assets/{DiffPanel-1GboPEhP.js → DiffPanel-Bpvhj9Zk.js} +3 -3
  3. package/dist/client/assets/{FilePreviewPanel-BZACyKlO.js → FilePreviewPanel-C2_gi2li.js} +5 -5
  4. package/dist/client/assets/PreviewPanel-CXrvKPAn.js +2 -0
  5. package/dist/client/assets/{angular-html-DWf2nx2U.js → angular-html-tWdnCR5u.js} +2 -2
  6. package/dist/client/assets/{angular-ts-CIx5TGhT.js → angular-ts-DHHrhqEn.js} +2 -2
  7. package/dist/client/assets/{apl-DafQ1-an.js → apl-Dttzd1My.js} +2 -2
  8. package/dist/client/assets/arrow-right-DL8xTI3l.js +2 -0
  9. package/dist/client/assets/{astro-Bep3tY5t.js → astro-BhhLcbHg.js} +2 -2
  10. package/dist/client/assets/{blade-DCuMesAS.js → blade-D1XdhGNZ.js} +2 -2
  11. package/dist/client/assets/{c-DZs6Etpe.js → c-DU3so7RH.js} +2 -2
  12. package/dist/client/assets/{cobol-DFZb1h1z.js → cobol-C5SwCVtJ.js} +2 -2
  13. package/dist/client/assets/{coffee-CR0gjEco.js → coffee-D8JHirJ4.js} +2 -2
  14. package/dist/client/assets/{cpp-U48aiClT.js → cpp-BrxgqiPv.js} +2 -2
  15. package/dist/client/assets/{crystal-CNaWREX9.js → crystal-LnjbHrAj.js} +2 -2
  16. package/dist/client/assets/{css-DQTD4ObL.js → css-BhvHnfwC.js} +2 -2
  17. package/dist/client/assets/{edge-CGgCvH7u.js → edge-BIAZ2O1m.js} +2 -2
  18. package/dist/client/assets/{elixir-QEF-Vb-O.js → elixir-C7fzptdf.js} +2 -2
  19. package/dist/client/assets/{elm-UIYYfgyY.js → elm-24neygAB.js} +2 -2
  20. package/dist/client/assets/{erb-CObSr7xt.js → erb-DpLDFI3P.js} +2 -2
  21. package/dist/client/assets/{fileCommentAnnotations-BQPQAflx.js → fileCommentAnnotations-D9LoOqKz.js} +2 -2
  22. package/dist/client/assets/{git-rebase-D-Kfui1X.js → git-rebase-nk76LFrn.js} +2 -2
  23. package/dist/client/assets/{glimmer-js-Bj7zsPRR.js → glimmer-js-D4faXOGy.js} +2 -2
  24. package/dist/client/assets/{glimmer-ts-BsEDRgeG.js → glimmer-ts-CUIVPmuw.js} +2 -2
  25. package/dist/client/assets/{glsl-D98j42v3.js → glsl-CHEysBk5.js} +2 -2
  26. package/dist/client/assets/{graphql-B1Bl3yQr.js → graphql-DxDXWgtu.js} +2 -2
  27. package/dist/client/assets/{hack-C5SdJhmY.js → hack-SE0rPM7F.js} +2 -2
  28. package/dist/client/assets/{haml-fOHEdRRk.js → haml-CZNVJ1t_.js} +2 -2
  29. package/dist/client/assets/{handlebars-BprpyHwi.js → handlebars-D3H0z0i1.js} +2 -2
  30. package/dist/client/assets/{html-DY94fJQ8.js → html-BXh14Kiu.js} +2 -2
  31. package/dist/client/assets/{html-derivative-BijLMkmB.js → html-derivative-Dcx75xJi.js} +2 -2
  32. package/dist/client/assets/{http-DgLF_F-Y.js → http-CHN_K5kg.js} +2 -2
  33. package/dist/client/assets/{hurl-Lf_gtANJ.js → hurl-DcyaHxXE.js} +2 -2
  34. package/dist/client/assets/{index-nkPMSYxq.css → index-D7hXE3Wh.css} +1 -1
  35. package/dist/client/assets/index-DesIBOH0.js +660 -0
  36. package/dist/client/assets/{java-CvbaU0rW.js → java-CibfJb97.js} +2 -2
  37. package/dist/client/assets/{javascript-Y_90CTbK.js → javascript-CGKYJrgO.js} +2 -2
  38. package/dist/client/assets/{jinja-Dz3cSyss.js → jinja-hMi6h2V1.js} +2 -2
  39. package/dist/client/assets/{jison-Cy5HwlPH.js → jison-D5hwL1Vj.js} +2 -2
  40. package/dist/client/assets/{json-BX9adxsl.js → json-DBBzorBt.js} +2 -2
  41. package/dist/client/assets/{jsx-uMzR21MU.js → jsx-CfjpnlWf.js} +2 -2
  42. package/dist/client/assets/{julia-BfKnOvts.js → julia-DY-wGzwr.js} +2 -2
  43. package/dist/client/assets/{just-gPqomEDo.js → just-Aiaxo0L3.js} +2 -2
  44. package/dist/client/assets/{latex-HAmg84zi.js → latex-Cl7y6v9p.js} +2 -2
  45. package/dist/client/assets/{liquid-CAfKVpt2.js → liquid-tjIYQaDR.js} +2 -2
  46. package/dist/client/assets/{lua-MJ-soRMY.js → lua-DeDHmNSA.js} +2 -2
  47. package/dist/client/assets/{marko-Bk2APM9P.js → marko-BLEE3RS_.js} +2 -2
  48. package/dist/client/assets/{mdc-D-ETA9xK.js → mdc-DBLy0ju2.js} +2 -2
  49. package/dist/client/assets/{nginx-NwHNwVvi.js → nginx-BpS56zJM.js} +2 -2
  50. package/dist/client/assets/{nim-uboMGtnG.js → nim-BP_5ZWs4.js} +2 -2
  51. package/dist/client/assets/{perl-DZO_qrRW.js → perl-BNoghH8w.js} +2 -2
  52. package/dist/client/assets/{php-BudgHX29.js → php-fikhFdsH.js} +2 -2
  53. package/dist/client/assets/{pug-1FhoiZN2.js → pug-BmML_p4L.js} +2 -2
  54. package/dist/client/assets/{qml-B6ycgh-7.js → qml-WOQTdjfD.js} +2 -2
  55. package/dist/client/assets/{r-M2HClZBy.js → r-BuLVFJ9C.js} +2 -2
  56. package/dist/client/assets/{razor-EiO_nOGU.js → razor-CsZ5mXvp.js} +2 -2
  57. package/dist/client/assets/{regexp-BF12zF9R.js → regexp-BbB_Z0k0.js} +2 -2
  58. package/dist/client/assets/{rst-BW8dKb0T.js → rst-CGogIoWE.js} +2 -2
  59. package/dist/client/assets/{ruby-BcJiTtn_.js → ruby-Drt9dpIY.js} +2 -2
  60. package/dist/client/assets/{sas--CMYy3z3.js → sas-mvidrzzg.js} +2 -2
  61. package/dist/client/assets/{scss-CBaO992p.js → scss-DcqXsy4k.js} +2 -2
  62. package/dist/client/assets/{shellscript-IGSv-HCQ.js → shellscript-C6nla6y6.js} +2 -2
  63. package/dist/client/assets/{shellsession-tY9I_iRt.js → shellsession-Dhkmvk-h.js} +2 -2
  64. package/dist/client/assets/{soy-BvSCSsmo.js → soy-CA1GOdLw.js} +2 -2
  65. package/dist/client/assets/{sql-BuK6MJNF.js → sql-CaDtCgQd.js} +2 -2
  66. package/dist/client/assets/{stata-VS9vYyft.js → stata-r5dYDO1a.js} +2 -2
  67. package/dist/client/assets/{surrealql-D4pAe4SW.js → surrealql-CreiDVJS.js} +2 -2
  68. package/dist/client/assets/{svelte-05AEGqMV.js → svelte-LQf52vP7.js} +2 -2
  69. package/dist/client/assets/{templ-amlaVpnD.js → templ-BAiCCrhW.js} +2 -2
  70. package/dist/client/assets/{tex-B8w-z73a.js → tex-Bi4veNnI.js} +2 -2
  71. package/dist/client/assets/textarea-8UeQ85tZ.js +46 -0
  72. package/dist/client/assets/{ts-tags-CWOgRloL.js → ts-tags-CmONaW11.js} +2 -2
  73. package/dist/client/assets/{tsx-DcSMCm_G.js → tsx-DEGaq1SP.js} +2 -2
  74. package/dist/client/assets/{twig-BoFkWRc3.js → twig-DR3myS6w.js} +2 -2
  75. package/dist/client/assets/{typescript-CnosOGRY.js → typescript-pTX3WTUF.js} +2 -2
  76. package/dist/client/assets/{vue-BkQYyvUc.js → vue-_Gh228sM.js} +2 -2
  77. package/dist/client/assets/{vue-html-DQkUheyK.js → vue-html-DqI2SuCG.js} +2 -2
  78. package/dist/client/assets/{vue-vine-PP4GiTEY.js → vue-vine-DJ2u5TuR.js} +2 -2
  79. package/dist/client/assets/{xml-B3yPYALE.js → xml-DtWHD1Mk.js} +2 -2
  80. package/dist/client/assets/{xsl-Cgr4RWex.js → xsl--uIbb82K.js} +2 -2
  81. package/dist/client/assets/{yaml-B7fPykX3.js → yaml-BYZt09An.js} +2 -2
  82. package/dist/client/index.html +3 -3
  83. package/package.json +1 -1
  84. package/dist/client/assets/PreviewPanel-By-_LFU1.js +0 -2
  85. package/dist/client/assets/arrow-right-qu8MQub2.js +0 -2
  86. package/dist/client/assets/index-BWiBk__A.js +0 -660
  87. package/dist/client/assets/textarea-sGc0UkUx.js +0 -46
package/dist/bin.mjs CHANGED
@@ -233,7 +233,7 @@ const make$73 = () => {
233
233
  const layer$69 = Layer.sync(NetService, make$73);
234
234
  //#endregion
235
235
  //#region package.json
236
- var version = "0.1.11";
236
+ var version = "0.1.13";
237
237
  //#endregion
238
238
  //#region src/config.ts
239
239
  /**
@@ -1651,6 +1651,13 @@ const RuntimeMode = Schema$1.Literals([
1651
1651
  const DEFAULT_RUNTIME_MODE$2 = "full-access";
1652
1652
  const ProviderInteractionMode = Schema$1.Literals(["default", "plan"]);
1653
1653
  const DEFAULT_PROVIDER_INTERACTION_MODE = "default";
1654
+ const CompressMode = Schema$1.Literals([
1655
+ "off",
1656
+ "lite",
1657
+ "full",
1658
+ "ultra"
1659
+ ]);
1660
+ const DEFAULT_COMPRESS_MODE = "full";
1654
1661
  const ProviderRequestKind = Schema$1.Literals([
1655
1662
  "command",
1656
1663
  "file-read",
@@ -1827,6 +1834,7 @@ const OrchestrationThread = Schema$1.Struct({
1827
1834
  modelSelection: ModelSelection,
1828
1835
  runtimeMode: RuntimeMode,
1829
1836
  interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
1837
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
1830
1838
  branch: Schema$1.NullOr(TrimmedNonEmptyString),
1831
1839
  worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
1832
1840
  latestTurn: Schema$1.NullOr(OrchestrationLatestTurn),
@@ -1867,6 +1875,7 @@ const OrchestrationThreadShell = Schema$1.Struct({
1867
1875
  modelSelection: ModelSelection,
1868
1876
  runtimeMode: RuntimeMode,
1869
1877
  interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
1878
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
1870
1879
  branch: Schema$1.NullOr(TrimmedNonEmptyString),
1871
1880
  worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
1872
1881
  latestTurn: Schema$1.NullOr(OrchestrationLatestTurn),
@@ -1989,6 +1998,7 @@ const ThreadCreateCommand = Schema$1.Struct({
1989
1998
  modelSelection: ModelSelection,
1990
1999
  runtimeMode: RuntimeMode,
1991
2000
  interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
2001
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
1992
2002
  branch: Schema$1.NullOr(TrimmedNonEmptyString),
1993
2003
  worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
1994
2004
  createdAt: IsoDateTime
@@ -2055,12 +2065,20 @@ const ThreadInteractionModeSetCommand = Schema$1.Struct({
2055
2065
  interactionMode: ProviderInteractionMode,
2056
2066
  createdAt: IsoDateTime
2057
2067
  });
2068
+ const ThreadCompressModeSetCommand = Schema$1.Struct({
2069
+ type: Schema$1.Literal("thread.compress-mode.set"),
2070
+ commandId: CommandId,
2071
+ threadId: ThreadId,
2072
+ compressMode: CompressMode,
2073
+ createdAt: IsoDateTime
2074
+ });
2058
2075
  const ThreadTurnStartBootstrapCreateThread = Schema$1.Struct({
2059
2076
  projectId: ProjectId,
2060
2077
  title: TrimmedNonEmptyString,
2061
2078
  modelSelection: ModelSelection,
2062
2079
  runtimeMode: RuntimeMode,
2063
2080
  interactionMode: ProviderInteractionMode,
2081
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
2064
2082
  branch: Schema$1.NullOr(TrimmedNonEmptyString),
2065
2083
  worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
2066
2084
  createdAt: IsoDateTime
@@ -2090,6 +2108,7 @@ const ThreadTurnStartCommand = Schema$1.Struct({
2090
2108
  titleSeed: Schema$1.optional(TrimmedNonEmptyString),
2091
2109
  runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
2092
2110
  interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
2111
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
2093
2112
  bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
2094
2113
  sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
2095
2114
  createdAt: IsoDateTime
@@ -2108,6 +2127,7 @@ const ClientThreadTurnStartCommand = Schema$1.Struct({
2108
2127
  titleSeed: Schema$1.optional(TrimmedNonEmptyString),
2109
2128
  runtimeMode: RuntimeMode,
2110
2129
  interactionMode: ProviderInteractionMode,
2130
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
2111
2131
  bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
2112
2132
  sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
2113
2133
  createdAt: IsoDateTime
@@ -2163,6 +2183,7 @@ const DispatchableClientOrchestrationCommand = Schema$1.Union([
2163
2183
  ThreadMetaUpdateCommand,
2164
2184
  ThreadRuntimeModeSetCommand,
2165
2185
  ThreadInteractionModeSetCommand,
2186
+ ThreadCompressModeSetCommand,
2166
2187
  ThreadTurnStartCommand,
2167
2188
  ThreadTurnInterruptCommand,
2168
2189
  ThreadApprovalRespondCommand,
@@ -2185,6 +2206,7 @@ const ClientOrchestrationCommand = Schema$1.Union([
2185
2206
  ThreadMetaUpdateCommand,
2186
2207
  ThreadRuntimeModeSetCommand,
2187
2208
  ThreadInteractionModeSetCommand,
2209
+ ThreadCompressModeSetCommand,
2188
2210
  ClientThreadTurnStartCommand,
2189
2211
  ThreadTurnInterruptCommand,
2190
2212
  ThreadApprovalRespondCommand,
@@ -2275,6 +2297,7 @@ const OrchestrationEventType = Schema$1.Literals([
2275
2297
  "thread.meta-updated",
2276
2298
  "thread.runtime-mode-set",
2277
2299
  "thread.interaction-mode-set",
2300
+ "thread.compress-mode-set",
2278
2301
  "thread.message-sent",
2279
2302
  "thread.turn-start-requested",
2280
2303
  "thread.turn-interrupt-requested",
@@ -2324,6 +2347,7 @@ const ThreadCreatedPayload$1 = Schema$1.Struct({
2324
2347
  modelSelection: ModelSelection,
2325
2348
  runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
2326
2349
  interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
2350
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
2327
2351
  branch: Schema$1.NullOr(TrimmedNonEmptyString),
2328
2352
  worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
2329
2353
  createdAt: IsoDateTime,
@@ -2381,6 +2405,11 @@ const ThreadInteractionModeSetPayload$1 = Schema$1.Struct({
2381
2405
  interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
2382
2406
  updatedAt: IsoDateTime
2383
2407
  });
2408
+ const ThreadCompressModeSetPayload$1 = Schema$1.Struct({
2409
+ threadId: ThreadId,
2410
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
2411
+ updatedAt: IsoDateTime
2412
+ });
2384
2413
  const ThreadMessageSentPayload = Schema$1.Struct({
2385
2414
  threadId: ThreadId,
2386
2415
  messageId: MessageId,
@@ -2399,6 +2428,7 @@ const ThreadTurnStartRequestedPayload = Schema$1.Struct({
2399
2428
  titleSeed: Schema$1.optional(TrimmedNonEmptyString),
2400
2429
  runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
2401
2430
  interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
2431
+ compressMode: CompressMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_COMPRESS_MODE))),
2402
2432
  sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
2403
2433
  createdAt: IsoDateTime
2404
2434
  });
@@ -2543,6 +2573,11 @@ const OrchestrationEvent = Schema$1.Union([
2543
2573
  type: Schema$1.Literal("thread.interaction-mode-set"),
2544
2574
  payload: ThreadInteractionModeSetPayload$1
2545
2575
  }),
2576
+ Schema$1.Struct({
2577
+ ...EventBaseFields,
2578
+ type: Schema$1.Literal("thread.compress-mode-set"),
2579
+ payload: ThreadCompressModeSetPayload$1
2580
+ }),
2546
2581
  Schema$1.Struct({
2547
2582
  ...EventBaseFields,
2548
2583
  type: Schema$1.Literal("thread.message-sent"),
@@ -4518,14 +4553,16 @@ const ProviderSessionStartInput = Schema$1.Struct({
4518
4553
  resumeCursor: Schema$1.optional(Schema$1.Unknown),
4519
4554
  approvalPolicy: Schema$1.optional(ProviderApprovalPolicy),
4520
4555
  sandboxMode: Schema$1.optional(ProviderSandboxMode),
4521
- runtimeMode: RuntimeMode
4556
+ runtimeMode: RuntimeMode,
4557
+ compressMode: Schema$1.optional(CompressMode)
4522
4558
  });
4523
4559
  const ProviderSendTurnInput = Schema$1.Struct({
4524
4560
  threadId: ThreadId,
4525
4561
  input: Schema$1.optional(TrimmedNonEmptyString.check(Schema$1.isMaxLength(PROVIDER_SEND_TURN_MAX_INPUT_CHARS))),
4526
4562
  attachments: Schema$1.optional(Schema$1.Array(ChatAttachment).check(Schema$1.isMaxLength(8))),
4527
4563
  modelSelection: Schema$1.optional(ModelSelection),
4528
- interactionMode: Schema$1.optional(ProviderInteractionMode)
4564
+ interactionMode: Schema$1.optional(ProviderInteractionMode),
4565
+ compressMode: Schema$1.optional(CompressMode)
4529
4566
  });
4530
4567
  Schema$1.Struct({
4531
4568
  threadId: ThreadId,
@@ -7615,6 +7652,57 @@ const ThreadControlToolError = Schema$1.Union([
7615
7652
  ThreadRenameRejectedError,
7616
7653
  MemoryAppendFailedError
7617
7654
  ]);
7655
+ const ThreadWatchEventsInput = Schema$1.Struct({
7656
+ threadId: ThreadId.annotate({ description: "The watched thread to read events from. Must be explicitly granted." }),
7657
+ afterSequence: Schema$1.optional(NonNegativeInt.annotate({ description: "Exclusive sequence cursor. Events with a higher sequence are returned. Omit to read from the beginning." })),
7658
+ limit: Schema$1.optional(NonNegativeInt.check(Schema$1.isLessThanOrEqualTo(200)).annotate({ description: `Maximum events to return (default 50, max 200).` }))
7659
+ });
7660
+ const ThreadWatchEventsResult = Schema$1.Struct({
7661
+ threadId: ThreadId,
7662
+ /** Ordered by sequence ascending; resume with the last event's sequence. */
7663
+ events: Schema$1.Array(OrchestrationEvent),
7664
+ /**
7665
+ * The engine's latest persisted sequence at read time. Equal to the last
7666
+ * returned event's sequence when the watcher is caught up.
7667
+ */
7668
+ headSequence: NonNegativeInt,
7669
+ /** True when more events for this thread exist past the returned page. */
7670
+ hasMore: Schema$1.Boolean
7671
+ });
7672
+ var WatchToolUnavailableError = class extends Schema$1.TaggedErrorClass()("WatchToolUnavailableError", {
7673
+ capability: Schema$1.Literal("watch"),
7674
+ environmentId: EnvironmentId,
7675
+ threadId: ThreadId,
7676
+ providerSessionId: TrimmedNonEmptyString,
7677
+ providerInstanceId: ProviderInstanceId
7678
+ }) {
7679
+ get message() {
7680
+ return `MCP credential does not grant the ${this.capability} capability.`;
7681
+ }
7682
+ };
7683
+ /**
7684
+ * The capability is present but the requested thread is not in the granted
7685
+ * set. Separate from {@link WatchToolUnavailableError} so a watcher can tell
7686
+ * "you cannot watch at all" apart from "not this thread".
7687
+ */
7688
+ var ThreadWatchNotPermittedError = class extends Schema$1.TaggedErrorClass()("ThreadWatchNotPermittedError", { threadId: ThreadId }) {
7689
+ get message() {
7690
+ return `This session was not granted watch access to thread ${this.threadId}.`;
7691
+ }
7692
+ };
7693
+ var ThreadWatchFailedError = class extends Schema$1.TaggedErrorClass()("ThreadWatchFailedError", {
7694
+ threadId: ThreadId,
7695
+ detail: Schema$1.String
7696
+ }) {
7697
+ get message() {
7698
+ return `Reading events for thread ${this.threadId} failed: ${this.detail}`;
7699
+ }
7700
+ };
7701
+ const ThreadWatchToolError = Schema$1.Union([
7702
+ WatchToolUnavailableError,
7703
+ ThreadWatchNotPermittedError,
7704
+ ThreadWatchFailedError
7705
+ ]);
7618
7706
  //#endregion
7619
7707
  //#region ../../packages/contracts/src/agentAsset.ts
7620
7708
  /**
@@ -12225,6 +12313,14 @@ var _038_TaskOrderKeys_default = Effect.gen(function* () {
12225
12313
  yield* (yield* SqlClient.SqlClient)`ALTER TABLE tasks ADD COLUMN order_key TEXT`;
12226
12314
  });
12227
12315
  //#endregion
12316
+ //#region src/persistence/Migrations/039_ProjectionThreadsCompressMode.ts
12317
+ var _039_ProjectionThreadsCompressMode_default = Effect.gen(function* () {
12318
+ yield* (yield* SqlClient.SqlClient)`
12319
+ ALTER TABLE projection_threads
12320
+ ADD COLUMN compress_mode TEXT NOT NULL DEFAULT 'off'
12321
+ `;
12322
+ });
12323
+ //#endregion
12228
12324
  //#region src/persistence/Migrations.ts
12229
12325
  /**
12230
12326
  * MigrationsLive - Migration runner with inline loader
@@ -12435,6 +12531,11 @@ const migrationEntries = [
12435
12531
  38,
12436
12532
  "TaskOrderKeys",
12437
12533
  _038_TaskOrderKeys_default
12534
+ ],
12535
+ [
12536
+ 39,
12537
+ "ProjectionThreadsCompressMode",
12538
+ _039_ProjectionThreadsCompressMode_default
12438
12539
  ]
12439
12540
  ];
12440
12541
  const makeMigrationLoader = (throughId) => Migrator.fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
@@ -18131,6 +18232,7 @@ const ThreadSettledPayload = ThreadSettledPayload$1;
18131
18232
  const ThreadMetaUpdatedPayload = ThreadMetaUpdatedPayload$1;
18132
18233
  const ThreadRuntimeModeSetPayload = ThreadRuntimeModeSetPayload$1;
18133
18234
  const ThreadInteractionModeSetPayload = ThreadInteractionModeSetPayload$1;
18235
+ const ThreadCompressModeSetPayload = ThreadCompressModeSetPayload$1;
18134
18236
  const ThreadDeletedPayload = ThreadDeletedPayload$1;
18135
18237
  const ThreadUnarchivedPayload = ThreadUnarchivedPayload$1;
18136
18238
  const ThreadUnsettledPayload = ThreadUnsettledPayload$1;
@@ -18270,6 +18372,7 @@ function projectEvent(model, event) {
18270
18372
  modelSelection: payload.modelSelection,
18271
18373
  runtimeMode: payload.runtimeMode,
18272
18374
  interactionMode: payload.interactionMode,
18375
+ compressMode: payload.compressMode,
18273
18376
  branch: payload.branch,
18274
18377
  worktreePath: payload.worktreePath,
18275
18378
  latestTurn: null,
@@ -18369,6 +18472,13 @@ function projectEvent(model, event) {
18369
18472
  updatedAt: payload.updatedAt
18370
18473
  })
18371
18474
  })));
18475
+ case "thread.compress-mode-set": return decodeForEvent(ThreadCompressModeSetPayload, event.payload, event.type, "payload").pipe(Effect.map((payload) => ({
18476
+ ...nextBase,
18477
+ threads: updateThread(nextBase.threads, payload.threadId, {
18478
+ compressMode: payload.compressMode,
18479
+ updatedAt: payload.updatedAt
18480
+ })
18481
+ })));
18372
18482
  case "thread.message-sent": return Effect.gen(function* () {
18373
18483
  const payload = yield* decodeForEvent(MessageSentPayloadSchema, event.payload, event.type, "payload");
18374
18484
  const thread = nextBase.threads.find((entry) => entry.id === payload.threadId);
@@ -18734,6 +18844,7 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
18734
18844
  modelSelection: command.modelSelection,
18735
18845
  runtimeMode: command.runtimeMode,
18736
18846
  interactionMode: command.interactionMode,
18847
+ compressMode: command.compressMode,
18737
18848
  branch: command.branch,
18738
18849
  worktreePath: command.worktreePath,
18739
18850
  createdAt: command.createdAt,
@@ -18991,6 +19102,28 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
18991
19102
  }
18992
19103
  };
18993
19104
  }
19105
+ case "thread.compress-mode.set": {
19106
+ yield* requireThread({
19107
+ readModel,
19108
+ command,
19109
+ threadId: command.threadId
19110
+ });
19111
+ const occurredAt = yield* nowIso$8;
19112
+ return {
19113
+ ...yield* withEventBase({
19114
+ aggregateKind: "thread",
19115
+ aggregateId: command.threadId,
19116
+ occurredAt,
19117
+ commandId: command.commandId
19118
+ }),
19119
+ type: "thread.compress-mode-set",
19120
+ payload: {
19121
+ threadId: command.threadId,
19122
+ compressMode: command.compressMode,
19123
+ updatedAt: occurredAt
19124
+ }
19125
+ };
19126
+ }
18994
19127
  case "thread.turn.start": {
18995
19128
  const targetThread = yield* requireThread({
18996
19129
  readModel,
@@ -19048,6 +19181,7 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
19048
19181
  ...command.titleSeed !== void 0 ? { titleSeed: command.titleSeed } : {},
19049
19182
  runtimeMode: targetThread.runtimeMode,
19050
19183
  interactionMode: targetThread.interactionMode,
19184
+ compressMode: targetThread.compressMode,
19051
19185
  ...sourceProposedPlan !== void 0 ? { sourceProposedPlan } : {},
19052
19186
  createdAt: command.createdAt
19053
19187
  }
@@ -19813,6 +19947,7 @@ const ProjectionThread = Schema$1.Struct({
19813
19947
  modelSelection: ModelSelection,
19814
19948
  runtimeMode: RuntimeMode,
19815
19949
  interactionMode: ProviderInteractionMode,
19950
+ compressMode: CompressMode,
19816
19951
  branch: Schema$1.NullOr(Schema$1.String),
19817
19952
  worktreePath: Schema$1.NullOr(Schema$1.String),
19818
19953
  latestTurnId: Schema$1.NullOr(TurnId),
@@ -20700,6 +20835,7 @@ const makeProjectionThreadRepository = Effect.gen(function* () {
20700
20835
  model_selection_json,
20701
20836
  runtime_mode,
20702
20837
  interaction_mode,
20838
+ compress_mode,
20703
20839
  branch,
20704
20840
  worktree_path,
20705
20841
  latest_turn_id,
@@ -20723,6 +20859,7 @@ const makeProjectionThreadRepository = Effect.gen(function* () {
20723
20859
  ${JSON.stringify(row.modelSelection)},
20724
20860
  ${row.runtimeMode},
20725
20861
  ${row.interactionMode},
20862
+ ${row.compressMode},
20726
20863
  ${row.branch},
20727
20864
  ${row.worktreePath},
20728
20865
  ${row.latestTurnId},
@@ -20746,6 +20883,7 @@ const makeProjectionThreadRepository = Effect.gen(function* () {
20746
20883
  model_selection_json = excluded.model_selection_json,
20747
20884
  runtime_mode = excluded.runtime_mode,
20748
20885
  interaction_mode = excluded.interaction_mode,
20886
+ compress_mode = excluded.compress_mode,
20749
20887
  branch = excluded.branch,
20750
20888
  worktree_path = excluded.worktree_path,
20751
20889
  latest_turn_id = excluded.latest_turn_id,
@@ -20774,6 +20912,7 @@ const makeProjectionThreadRepository = Effect.gen(function* () {
20774
20912
  model_selection_json AS "modelSelection",
20775
20913
  runtime_mode AS "runtimeMode",
20776
20914
  interaction_mode AS "interactionMode",
20915
+ compress_mode AS "compressMode",
20777
20916
  branch,
20778
20917
  worktree_path AS "worktreePath",
20779
20918
  latest_turn_id AS "latestTurnId",
@@ -20804,6 +20943,7 @@ const makeProjectionThreadRepository = Effect.gen(function* () {
20804
20943
  model_selection_json AS "modelSelection",
20805
20944
  runtime_mode AS "runtimeMode",
20806
20945
  interaction_mode AS "interactionMode",
20946
+ compress_mode AS "compressMode",
20807
20947
  branch,
20808
20948
  worktree_path AS "worktreePath",
20809
20949
  latest_turn_id AS "latestTurnId",
@@ -21270,6 +21410,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
21270
21410
  modelSelection: event.payload.modelSelection,
21271
21411
  runtimeMode: event.payload.runtimeMode,
21272
21412
  interactionMode: event.payload.interactionMode,
21413
+ compressMode: event.payload.compressMode,
21273
21414
  branch: event.payload.branch,
21274
21415
  worktreePath: event.payload.worktreePath,
21275
21416
  latestTurnId: null,
@@ -21384,6 +21525,16 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
21384
21525
  });
21385
21526
  return;
21386
21527
  }
21528
+ case "thread.compress-mode-set": {
21529
+ const existingRow = yield* projectionThreadRepository.getById({ threadId: event.payload.threadId });
21530
+ if (Option.isNone(existingRow)) return;
21531
+ yield* projectionThreadRepository.upsert({
21532
+ ...existingRow.value,
21533
+ compressMode: event.payload.compressMode,
21534
+ updatedAt: event.payload.updatedAt
21535
+ });
21536
+ return;
21537
+ }
21387
21538
  case "thread.deleted": {
21388
21539
  attachmentSideEffects.deletedThreadIds.add(event.payload.threadId);
21389
21540
  const existingRow = yield* projectionThreadRepository.getById({ threadId: event.payload.threadId });
@@ -22705,6 +22856,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
22705
22856
  model_selection_json AS "modelSelection",
22706
22857
  runtime_mode AS "runtimeMode",
22707
22858
  interaction_mode AS "interactionMode",
22859
+ compress_mode AS "compressMode",
22708
22860
  branch,
22709
22861
  worktree_path AS "worktreePath",
22710
22862
  latest_turn_id AS "latestTurnId",
@@ -22735,6 +22887,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
22735
22887
  model_selection_json AS "modelSelection",
22736
22888
  runtime_mode AS "runtimeMode",
22737
22889
  interaction_mode AS "interactionMode",
22890
+ compress_mode AS "compressMode",
22738
22891
  branch,
22739
22892
  worktree_path AS "worktreePath",
22740
22893
  latest_turn_id AS "latestTurnId",
@@ -22767,6 +22920,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
22767
22920
  model_selection_json AS "modelSelection",
22768
22921
  runtime_mode AS "runtimeMode",
22769
22922
  interaction_mode AS "interactionMode",
22923
+ compress_mode AS "compressMode",
22770
22924
  branch,
22771
22925
  worktree_path AS "worktreePath",
22772
22926
  latest_turn_id AS "latestTurnId",
@@ -23099,6 +23253,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23099
23253
  model_selection_json AS "modelSelection",
23100
23254
  runtime_mode AS "runtimeMode",
23101
23255
  interaction_mode AS "interactionMode",
23256
+ compress_mode AS "compressMode",
23102
23257
  branch,
23103
23258
  worktree_path AS "worktreePath",
23104
23259
  latest_turn_id AS "latestTurnId",
@@ -23400,6 +23555,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23400
23555
  modelSelection: row.modelSelection,
23401
23556
  runtimeMode: row.runtimeMode,
23402
23557
  interactionMode: row.interactionMode,
23558
+ compressMode: row.compressMode,
23403
23559
  branch: row.branch,
23404
23560
  worktreePath: row.worktreePath,
23405
23561
  latestTurn: latestTurnByThread.get(row.threadId) ?? null,
@@ -23511,6 +23667,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23511
23667
  modelSelection: row.modelSelection,
23512
23668
  runtimeMode: row.runtimeMode,
23513
23669
  interactionMode: row.interactionMode,
23670
+ compressMode: row.compressMode,
23514
23671
  branch: row.branch,
23515
23672
  worktreePath: row.worktreePath,
23516
23673
  latestTurn: latestTurnByThread.get(row.threadId) ?? null,
@@ -23569,6 +23726,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23569
23726
  modelSelection: row.modelSelection,
23570
23727
  runtimeMode: row.runtimeMode,
23571
23728
  interactionMode: row.interactionMode,
23729
+ compressMode: row.compressMode,
23572
23730
  branch: row.branch,
23573
23731
  worktreePath: row.worktreePath,
23574
23732
  latestTurn: latestTurnByThread.get(row.threadId) ?? null,
@@ -23623,6 +23781,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23623
23781
  modelSelection: row.modelSelection,
23624
23782
  runtimeMode: row.runtimeMode,
23625
23783
  interactionMode: row.interactionMode,
23784
+ compressMode: row.compressMode,
23626
23785
  branch: row.branch,
23627
23786
  worktreePath: row.worktreePath,
23628
23787
  latestTurn: latestTurnByThread.get(row.threadId) ?? null,
@@ -23713,6 +23872,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23713
23872
  modelSelection: threadRow.value.modelSelection,
23714
23873
  runtimeMode: threadRow.value.runtimeMode,
23715
23874
  interactionMode: threadRow.value.interactionMode,
23875
+ compressMode: threadRow.value.compressMode,
23716
23876
  branch: threadRow.value.branch,
23717
23877
  worktreePath: threadRow.value.worktreePath,
23718
23878
  latestTurn: Option.isSome(latestTurnRow) ? mapLatestTurn(latestTurnRow.value) : null,
@@ -23748,6 +23908,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23748
23908
  modelSelection: threadRow.value.modelSelection,
23749
23909
  runtimeMode: threadRow.value.runtimeMode,
23750
23910
  interactionMode: threadRow.value.interactionMode,
23911
+ compressMode: threadRow.value.compressMode,
23751
23912
  branch: threadRow.value.branch,
23752
23913
  worktreePath: threadRow.value.worktreePath,
23753
23914
  latestTurn: Option.isSome(latestTurnRow) ? mapLatestTurn(latestTurnRow.value) : null,
@@ -23827,11 +23988,66 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
23827
23988
  });
23828
23989
  const OrchestrationProjectionSnapshotQueryLive = Layer.effect(ProjectionSnapshotQuery, makeProjectionSnapshotQuery);
23829
23990
  //#endregion
23991
+ //#region src/orchestration/Services/ThreadEventStream.ts
23992
+ var ThreadEventStreamService = class extends Context.Service()("@p4code/cli/orchestration/Services/ThreadEventStream/ThreadEventStreamService") {};
23993
+ //#endregion
23994
+ //#region src/orchestration/Layers/ThreadEventStream.ts
23995
+ const makeThreadEventStream = Effect.gen(function* () {
23996
+ const engine = yield* OrchestrationEngineService;
23997
+ const isThreadEvent = (threadId) => (event) => event.aggregateKind === "thread" && event.aggregateId === threadId;
23998
+ const watch = (input) => Stream.unwrap(Effect.gen(function* () {
23999
+ const matchesThread = isThreadEvent(input.threadId);
24000
+ const liveBuffer = yield* Queue.unbounded();
24001
+ yield* Effect.forkScoped(engine.streamDomainEvents.pipe(Stream.filter(matchesThread), Stream.runForEach((event) => Queue.offer(liveBuffer, event))), { startImmediately: true });
24002
+ const afterSequence = input.afterSequence ?? 0;
24003
+ const headSequence = yield* engine.latestSequence;
24004
+ const replayGap = headSequence - afterSequence;
24005
+ const catchUp = replayGap > 0 ? engine.readEvents(afterSequence, replayGap).pipe(Stream.filter(matchesThread)) : Stream.empty;
24006
+ const caughtUp = Stream.make({
24007
+ kind: "caught-up",
24008
+ headSequence
24009
+ });
24010
+ const live = Stream.fromQueue(liveBuffer).pipe(Stream.filter((event) => event.sequence > headSequence));
24011
+ return Stream.concat(catchUp.pipe(Stream.map((event) => ({
24012
+ kind: "event",
24013
+ event
24014
+ }))), Stream.concat(caughtUp, live.pipe(Stream.map((event) => ({
24015
+ kind: "event",
24016
+ event
24017
+ })))));
24018
+ }));
24019
+ const read = (input) => Effect.gen(function* () {
24020
+ const matchesThread = isThreadEvent(input.threadId);
24021
+ const afterSequence = input.afterSequence ?? 0;
24022
+ const headSequence = yield* engine.latestSequence;
24023
+ const replayGap = headSequence - afterSequence;
24024
+ if (replayGap <= 0) return {
24025
+ events: [],
24026
+ headSequence,
24027
+ hasMore: false
24028
+ };
24029
+ const collected = yield* engine.readEvents(afterSequence, replayGap).pipe(Stream.filter(matchesThread), Stream.take(input.limit + 1), Stream.runCollect);
24030
+ const events = Array.from(collected);
24031
+ const hasMore = events.length > input.limit;
24032
+ return {
24033
+ events: hasMore ? events.slice(0, input.limit) : events,
24034
+ headSequence,
24035
+ hasMore
24036
+ };
24037
+ });
24038
+ return ThreadEventStreamService.of({
24039
+ watch,
24040
+ read
24041
+ });
24042
+ });
24043
+ const ThreadEventStreamLive = Layer.effect(ThreadEventStreamService, makeThreadEventStream);
24044
+ //#endregion
23830
24045
  //#region src/orchestration/runtimeLayer.ts
23831
24046
  const OrchestrationEventInfrastructureLayerLive = Layer.mergeAll(OrchestrationEventStoreLive, OrchestrationCommandReceiptRepositoryLive);
23832
24047
  const OrchestrationProjectionPipelineLayerLive = OrchestrationProjectionPipelineLive.pipe(Layer.provide(OrchestrationEventStoreLive));
23833
24048
  const OrchestrationInfrastructureLayerLive = Layer.mergeAll(OrchestrationProjectionSnapshotQueryLive, OrchestrationEventInfrastructureLayerLive, OrchestrationProjectionPipelineLayerLive);
23834
- const OrchestrationLayerLive = Layer.mergeAll(OrchestrationInfrastructureLayerLive, OrchestrationEngineLive.pipe(Layer.provide(OrchestrationInfrastructureLayerLive)));
24049
+ const OrchestrationEngineLayerLive = OrchestrationEngineLive.pipe(Layer.provide(OrchestrationInfrastructureLayerLive));
24050
+ const OrchestrationLayerLive = Layer.mergeAll(OrchestrationInfrastructureLayerLive, OrchestrationEngineLayerLive, ThreadEventStreamLive.pipe(Layer.provide(OrchestrationEngineLayerLive)));
23835
24051
  //#endregion
23836
24052
  //#region ../../packages/shared/src/keybindings.ts
23837
24053
  const DEFAULT_KEYBINDINGS = [
@@ -27101,6 +27317,7 @@ const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
27101
27317
  title: "New thread",
27102
27318
  modelSelection: nextProjectDefaultModelSelection,
27103
27319
  interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
27320
+ compressMode: DEFAULT_COMPRESS_MODE,
27104
27321
  runtimeMode: "full-access",
27105
27322
  branch: null,
27106
27323
  worktreePath: null,
@@ -33144,6 +33361,12 @@ const toTaskStoreError = (operation) => (cause) => Effect.logWarning("task store
33144
33361
  /**
33145
33362
  * The `auto` rendering: here is the task, do it.
33146
33363
  *
33364
+ * The prompt carries a reference to the task, not a copy of it. Inlining the
33365
+ * body flattened the row into plain text: labels, project and priority were
33366
+ * lost, and an edit made after the thread started was invisible to an agent
33367
+ * still reading its stale snapshot. The row stays the single source of truth
33368
+ * and the agent reads it live over MCP.
33369
+ *
33147
33370
  * Two instructions carry their weight. The agent is told its thread is already
33148
33371
  * linked to the task, because otherwise its first useful move is to guess which
33149
33372
  * board row it is on. And it is told to leave `status` alone: the server moved
@@ -33152,18 +33375,16 @@ const toTaskStoreError = (operation) => (cause) => Effect.logWarning("task store
33152
33375
  * the reason the board's columns still mean something.
33153
33376
  */
33154
33377
  const buildAutoPrompt = (task) => {
33155
- const body = task.body.trim();
33156
- return `You are picking up a task from the board. Do the work.
33157
-
33158
- ## ${task.title}
33378
+ const reference = task.readableId ?? task.taskId;
33379
+ return `You are picking up task \`${reference}\` from the board: ${task.title}
33159
33380
 
33160
- ${body.length === 0 ? "_The task has no description. Read enough of the repository to work out what it means, and ask if it is genuinely ambiguous._" : body}
33381
+ Start by reading the task itself with \`task_current\` (or \`task_get\` with \`${reference}\`). The body, labels, project and priority live on the row, not in this message, and the row may have been edited since this thread started — what it says now is the source of truth. Re-read it the same way whenever you need the fields again.
33161
33382
 
33162
- This thread is linked to task \`${task.taskId}\`, which is now In progress. \`task_current\` re-reads it if you need the fields again.
33383
+ This thread is already linked to the task, which is now In progress. Do the work.
33163
33384
 
33164
33385
  Record what you find with \`task_update\` as you go — a decision you made, a constraint you hit, something the task turned out to be wrong about. That is what makes the row worth reading afterwards. Leave \`status\` alone: moving work across the board is the user's call.
33165
33386
 
33166
- Start by reading the code the task concerns. If it turns out to be specified too poorly to act on, say so and stop rather than guessing at what was meant.`;
33387
+ After reading the task, read the code it concerns. If it turns out to be specified too poorly to act on, say so and stop rather than guessing at what was meant.`;
33167
33388
  };
33168
33389
  /**
33169
33390
  * Render a task into the prompt that seeds its thread.
@@ -36118,6 +36339,24 @@ const requireTaskCapability = Effect.fn("mcp.requireTaskCapability")(function* (
36118
36339
  });
36119
36340
  return invocation;
36120
36341
  });
36342
+ /**
36343
+ * The watch capability's guard is two checks, not one: the capability must be
36344
+ * present AND the requested thread must be in the explicit grant set. The two
36345
+ * failures are distinct errors so a watcher can tell "this session cannot
36346
+ * watch at all" apart from "not this thread".
36347
+ */
36348
+ const requireWatchCapability = Effect.fn("mcp.requireWatchCapability")(function* (watchedThreadId) {
36349
+ const invocation = yield* McpInvocationContext;
36350
+ if (!invocation.capabilities.has("watch")) return yield* new WatchToolUnavailableError({
36351
+ capability: "watch",
36352
+ environmentId: invocation.environmentId,
36353
+ threadId: invocation.threadId,
36354
+ providerSessionId: invocation.providerSessionId,
36355
+ providerInstanceId: invocation.providerInstanceId
36356
+ });
36357
+ if (!invocation.watchThreadIds?.has(watchedThreadId)) return yield* new ThreadWatchNotPermittedError({ threadId: watchedThreadId });
36358
+ return invocation;
36359
+ });
36121
36360
  /** Third of the trio, for the same reason the second exists. */
36122
36361
  const requireThreadCapability = Effect.fn("mcp.requireThreadCapability")(function* () {
36123
36362
  const invocation = yield* McpInvocationContext;
@@ -43521,6 +43760,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
43521
43760
  modelSelection: bootstrap.createThread.modelSelection,
43522
43761
  runtimeMode: bootstrap.createThread.runtimeMode,
43523
43762
  interactionMode: bootstrap.createThread.interactionMode,
43763
+ compressMode: bootstrap.createThread.compressMode,
43524
43764
  branch: bootstrap.createThread.branch,
43525
43765
  worktreePath: bootstrap.createThread.worktreePath,
43526
43766
  createdAt: bootstrap.createThread.createdAt
@@ -43774,8 +44014,8 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
43774
44014
  mode: "auto",
43775
44015
  task: {
43776
44016
  taskId,
43777
- title: task.title,
43778
- body: task.body
44017
+ readableId: task.readableId,
44018
+ title: task.title
43779
44019
  }
43780
44020
  }),
43781
44021
  attachments: []
@@ -43784,12 +44024,14 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
43784
44024
  titleSeed: threadTitle,
43785
44025
  runtimeMode: DEFAULT_RUNTIME_MODE$2,
43786
44026
  interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
44027
+ compressMode: DEFAULT_COMPRESS_MODE,
43787
44028
  bootstrap: { createThread: {
43788
44029
  projectId: plan.projectId,
43789
44030
  title: threadTitle,
43790
44031
  modelSelection,
43791
44032
  runtimeMode: DEFAULT_RUNTIME_MODE$2,
43792
44033
  interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
44034
+ compressMode: DEFAULT_COMPRESS_MODE,
43793
44035
  branch: null,
43794
44036
  worktreePath: null,
43795
44037
  createdAt
@@ -45073,16 +45315,20 @@ const makeWithOptions = Effect.fn("McpSessionRegistry.make")(function* (options
45073
45315
  const providerSessionId = yield* crypto.randomUUIDv4.pipe(Effect.orDie);
45074
45316
  const rawToken = yield* crypto.randomBytes(32).pipe(Effect.map(tokenFromBytes), Effect.orDie);
45075
45317
  const tokenHash = yield* hashToken(rawToken);
45318
+ const watchThreadIds = new Set((request.watchThreadIds ?? []).map((threadId) => ThreadId.make(threadId)));
45319
+ const capabilities = /* @__PURE__ */ new Set([
45320
+ "preview",
45321
+ "tasks",
45322
+ "threads"
45323
+ ]);
45324
+ if (watchThreadIds.size > 0) capabilities.add("watch");
45076
45325
  const scope = {
45077
45326
  environmentId,
45078
45327
  threadId: ThreadId.make(request.threadId),
45079
45328
  providerSessionId,
45080
45329
  providerInstanceId: ProviderInstanceId.make(request.providerInstanceId),
45081
- capabilities: /* @__PURE__ */ new Set([
45082
- "preview",
45083
- "tasks",
45084
- "threads"
45085
- ]),
45330
+ capabilities,
45331
+ ...watchThreadIds.size > 0 ? { watchThreadIds } : {},
45086
45332
  issuedAt
45087
45333
  };
45088
45334
  yield* SynchronizedRef.update(state, ({ records }) => {
@@ -47857,6 +48103,88 @@ function formatAskUserQuestionAnswers(answers) {
47857
48103
  return formatted;
47858
48104
  }
47859
48105
  //#endregion
48106
+ //#region src/provider/CompressPrompts.ts
48107
+ /**
48108
+ * Caveman-style response compression rulesets, adapted from the caveman
48109
+ * plugin's SKILL.md. Pre-baked per level so injection is a lookup, not a
48110
+ * runtime template. Applies to assistant prose only: code blocks, commits,
48111
+ * PRs, error strings, and safety-critical text stay uncompressed.
48112
+ */
48113
+ const COMPRESS_SHARED_RULES = `Respond terse. All technical substance stays. Only fluff dies.
48114
+
48115
+ ## Persistence
48116
+
48117
+ Active every response. No revert after many turns. No filler drift. Still active if unsure.
48118
+
48119
+ ## Rules
48120
+
48121
+ 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.
48122
+
48123
+ 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.
48124
+
48125
+ 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.
48126
+
48127
+ ## Auto-Clarity
48128
+
48129
+ Drop compression and write normally when:
48130
+ - Security warnings
48131
+ - Irreversible action confirmations
48132
+ - Multi-step sequences where fragment order or omitted conjunctions risk misread
48133
+ - Compression itself creates technical ambiguity
48134
+ - User asks to clarify or repeats a question
48135
+
48136
+ Resume compression after the clear part is done.
48137
+
48138
+ ## Boundaries
48139
+
48140
+ Code, commit messages, and PR descriptions: write normal, uncompressed.`;
48141
+ const COMPRESS_RULESETS = {
48142
+ lite: `## Response compression: lite
48143
+
48144
+ ${COMPRESS_SHARED_RULES}
48145
+
48146
+ ## Intensity: lite
48147
+
48148
+ No filler or hedging. Keep articles and full sentences. Professional but tight.
48149
+
48150
+ Example - "Why does my React component re-render?"
48151
+ "Your component re-renders because you create a new object reference each render. Wrap it in \`useMemo\`."`,
48152
+ full: `## Response compression: full
48153
+
48154
+ ${COMPRESS_SHARED_RULES}
48155
+
48156
+ ## Intensity: full
48157
+
48158
+ Drop articles (a/an/the), fragments OK, short synonyms. Pattern: [thing] [action] [reason]. [next step].
48159
+
48160
+ Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
48161
+ Yes: "Bug in auth middleware. Token expiry check use \`<\` not \`<=\`. Fix:"
48162
+
48163
+ Example - "Why does my React component re-render?"
48164
+ "New object ref each render. Inline object prop = new ref = re-render. Wrap in \`useMemo\`."`,
48165
+ ultra: `## Response compression: ultra
48166
+
48167
+ ${COMPRESS_SHARED_RULES}
48168
+
48169
+ ## Intensity: ultra
48170
+
48171
+ 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.
48172
+
48173
+ Example - "Why does my React component re-render?"
48174
+ "Inline object prop, new ref, re-render. \`useMemo\`."`
48175
+ };
48176
+ const COMPRESS_TURN_REMINDERS = {
48177
+ lite: "[response style: compressed lite - no filler/hedging, full sentences; code/commits/security text normal]",
48178
+ full: "[response style: compressed full - terse fragments, drop articles/filler; code/commits/security text normal]",
48179
+ ultra: "[response style: compressed ultra - maximum terseness, one word when enough; code/commits/security text normal]"
48180
+ };
48181
+ function compressRulesetFor(mode) {
48182
+ return mode === "off" ? void 0 : COMPRESS_RULESETS[mode];
48183
+ }
48184
+ function compressTurnReminderFor(mode) {
48185
+ return mode === "off" ? void 0 : COMPRESS_TURN_REMINDERS[mode];
48186
+ }
48187
+ //#endregion
47860
48188
  //#region src/provider/Layers/ClaudeAdapter.ts
47861
48189
  /**
47862
48190
  * ClaudeAdapterLive - Scoped live implementation for the Claude Agent provider adapter.
@@ -50246,6 +50574,8 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50246
50574
  const mcpSession = readMcpProviderSession(input.threadId);
50247
50575
  const externalMcpServers = options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers;
50248
50576
  const narrateBeforeTools = options?.resolveToolCallNarration === void 0 ? DEFAULT_SERVER_SETTINGS.enableToolCallNarration : yield* options.resolveToolCallNarration;
50577
+ const compressRuleset = compressRulesetFor(input.compressMode ?? "off");
50578
+ const systemPromptAppend = [...narrateBeforeTools ? [NARRATE_BEFORE_TOOLS_PROMPT] : [], ...compressRuleset !== void 0 ? [compressRuleset] : []].join("\n\n");
50249
50579
  const queryOptions = {
50250
50580
  ...input.cwd ? { cwd: input.cwd } : {},
50251
50581
  ...apiModelId ? { model: apiModelId } : {},
@@ -50253,7 +50583,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
50253
50583
  systemPrompt: {
50254
50584
  type: "preset",
50255
50585
  preset: "claude_code",
50256
- ...narrateBeforeTools ? { append: NARRATE_BEFORE_TOOLS_PROMPT } : {}
50586
+ ...systemPromptAppend.length > 0 ? { append: systemPromptAppend } : {}
50257
50587
  },
50258
50588
  settingSources: [...CLAUDE_SETTING_SOURCES],
50259
50589
  ...effectiveEffort ? { effort: effectiveEffort } : {},
@@ -69563,8 +69893,12 @@ ${P4_CODE_BROWSER_TOOL_INSTRUCTIONS}
69563
69893
  function toSingleLine(value) {
69564
69894
  return value.replaceAll(/\s+/g, " ").trim();
69565
69895
  }
69566
- function buildCodexDeveloperInstructions(interactionMode, runtime) {
69567
- return `${interactionMode === "plan" ? CODEX_PLAN_MODE_DEVELOPER_INSTRUCTIONS : CODEX_DEFAULT_MODE_DEVELOPER_INSTRUCTIONS}
69896
+ function buildCodexDeveloperInstructions(interactionMode, runtime, compressMode) {
69897
+ const base = interactionMode === "plan" ? CODEX_PLAN_MODE_DEVELOPER_INSTRUCTIONS : CODEX_DEFAULT_MODE_DEVELOPER_INSTRUCTIONS;
69898
+ const compressRuleset = compressRulesetFor(compressMode ?? "off");
69899
+ return `${base}${compressRuleset === void 0 ? "" : `
69900
+
69901
+ <response_style>${compressRuleset}</response_style>`}
69568
69902
 
69569
69903
  <runtime_info>In case you're asked: you are running in P4Code through the Codex harness, as ${toSingleLine(runtime.model)} with ${toSingleLine(runtime.reasoningEffort)} reasoning effort. No need to mention this otherwise.</runtime_info>`;
69570
69904
  }
@@ -69682,7 +70016,7 @@ function buildCodexCollaborationMode(input) {
69682
70016
  developer_instructions: buildCodexDeveloperInstructions(input.interactionMode, {
69683
70017
  model,
69684
70018
  reasoningEffort
69685
- })
70019
+ }, input.compressMode)
69686
70020
  }
69687
70021
  };
69688
70022
  }
@@ -69696,6 +70030,7 @@ function buildTurnStartParams(input) {
69696
70030
  const config = runtimeModeToThreadConfig(input.runtimeMode);
69697
70031
  const collaborationMode = buildCodexCollaborationMode({
69698
70032
  ...input.interactionMode ? { interactionMode: input.interactionMode } : {},
70033
+ ...input.compressMode ? { compressMode: input.compressMode } : {},
69699
70034
  ...input.model ? { model: input.model } : {},
69700
70035
  ...input.effort ? { effort: input.effort } : {}
69701
70036
  });
@@ -70234,7 +70569,8 @@ const makeCodexSessionRuntime = (options) => Effect.gen(function* () {
70234
70569
  ...normalizedModel ? { model: normalizedModel } : {},
70235
70570
  ...input.serviceTier ? { serviceTier: input.serviceTier } : {},
70236
70571
  ...input.effort ? { effort: input.effort } : {},
70237
- ...input.interactionMode ? { interactionMode: input.interactionMode } : {}
70572
+ ...input.interactionMode ? { interactionMode: input.interactionMode } : {},
70573
+ ...input.compressMode ? { compressMode: input.compressMode } : {}
70238
70574
  });
70239
70575
  const rawResponse = yield* client.raw.request("turn/start", params);
70240
70576
  const response = yield* decodeV2TurnStartResponse(rawResponse).pipe(Effect.mapError((error) => CodexAppServerProtocolParseError.fromSchemaError("decode-response-payload", error, { method: "turn/start" })));
@@ -71226,6 +71562,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
71226
71562
  ...reasoningEffort ? { effort: reasoningEffort } : {},
71227
71563
  ...serviceTier ? { serviceTier } : {},
71228
71564
  ...input.interactionMode !== void 0 ? { interactionMode: input.interactionMode } : {},
71565
+ ...input.compressMode !== void 0 ? { compressMode: input.compressMode } : {},
71229
71566
  ...codexAttachments.length > 0 ? { attachments: codexAttachments } : {}
71230
71567
  }).pipe(Effect.mapError((cause) => mapCodexRuntimeError(input.threadId, "turn/start", cause)));
71231
71568
  });
@@ -82105,7 +82442,7 @@ const invokeTargeted = (operation, input, timeoutMs) => {
82105
82442
  const { tabId, ...operationInput } = input;
82106
82443
  return invoke(operation, operationInput, timeoutMs, tabId);
82107
82444
  };
82108
- const handlers$2 = {
82445
+ const handlers$3 = {
82109
82446
  preview_status: (input) => invokeTargeted("status", input ?? {}),
82110
82447
  preview_open: (input) => invokeTargeted("open", normalizePreviewOpenInput(input)),
82111
82448
  preview_navigate: (input) => invokeTargeted("navigate", input, input.timeoutMs),
@@ -82121,10 +82458,10 @@ const handlers$2 = {
82121
82458
  preview_recording_start: (input) => invokeTargeted("recordingStart", input ?? {}),
82122
82459
  preview_recording_stop: (input) => invokeTargeted("recordingStop", input ?? {})
82123
82460
  };
82124
- const { preview_snapshot, ...standardHandlers } = handlers$2;
82461
+ const { preview_snapshot, ...standardHandlers } = handlers$3;
82125
82462
  const PreviewStandardToolkitHandlersLive = PreviewStandardToolkit.toLayer(standardHandlers);
82126
82463
  const PreviewSnapshotToolkitHandlersLive = PreviewSnapshotToolkit.toLayer({ preview_snapshot });
82127
- PreviewToolkit.toLayer(handlers$2);
82464
+ PreviewToolkit.toLayer(handlers$3);
82128
82465
  //#endregion
82129
82466
  //#region src/mcp/toolkits/tasks/tools.ts
82130
82467
  const dependencies = [McpInvocationContext, TaskRepository];
@@ -82357,6 +82694,41 @@ const ThreadToolkitHandlersLive = ThreadToolkit.toLayer({
82357
82694
  })
82358
82695
  });
82359
82696
  //#endregion
82697
+ //#region src/mcp/toolkits/watch/tools.ts
82698
+ /**
82699
+ * Cross-thread by design, which is exactly why it is the most guarded tool in
82700
+ * the registry: the handler admits only threads in the session's explicit
82701
+ * `watchThreadIds` grant, never the token's whole reach. The read is a cursor
82702
+ * poll because MCP tools are request/response; a watcher advances
82703
+ * `afterSequence` with each page and knows it is caught up when `hasMore` is
82704
+ * false and the last sequence equals `headSequence`.
82705
+ */
82706
+ const ThreadWatchEventsTool = Tool.make("thread_watch_events", {
82707
+ description: "Read a watched thread's orchestration events after a sequence cursor. Returns an ordered page plus the head sequence; pass the last event's sequence back as afterSequence to poll forward. Only threads this session was explicitly granted are readable.",
82708
+ parameters: ThreadWatchEventsInput,
82709
+ success: ThreadWatchEventsResult,
82710
+ failure: ThreadWatchToolError,
82711
+ dependencies: [McpInvocationContext, ThreadEventStreamService]
82712
+ }).annotate(Tool.Title, "Read watched thread events").annotate(Tool.Readonly, true).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, true);
82713
+ const WatchToolkit = Toolkit.make(ThreadWatchEventsTool);
82714
+ const WatchToolkitHandlersLive = WatchToolkit.toLayer({ thread_watch_events: (input) => Effect.gen(function* () {
82715
+ yield* requireWatchCapability(input.threadId);
82716
+ const page = yield* (yield* ThreadEventStreamService).read({
82717
+ threadId: input.threadId,
82718
+ ...input.afterSequence !== void 0 ? { afterSequence: input.afterSequence } : {},
82719
+ limit: input.limit ?? 50
82720
+ }).pipe(Effect.mapError((cause) => new ThreadWatchFailedError({
82721
+ threadId: input.threadId,
82722
+ detail: cause.message
82723
+ })));
82724
+ return {
82725
+ threadId: input.threadId,
82726
+ events: page.events,
82727
+ headSequence: page.headSequence,
82728
+ hasMore: page.hasMore
82729
+ };
82730
+ }) });
82731
+ //#endregion
82360
82732
  //#region src/mcp/McpHttpServer.ts
82361
82733
  const unauthorized = HttpServerResponse.jsonUnsafe({
82362
82734
  error: "invalid_mcp_credential",
@@ -82461,12 +82833,13 @@ const PreviewSnapshotRegistrationLive = Layer.effectDiscard(registerPreviewSnaps
82461
82833
  const PreviewToolkitRegistrationLive = Layer.mergeAll(PreviewStandardToolkitRegistrationLive, PreviewSnapshotRegistrationLive);
82462
82834
  const TaskToolkitRegistrationLive = McpServer.toolkit(TaskToolkit).pipe(Layer.provide(TaskToolkitHandlersLive));
82463
82835
  const ThreadToolkitRegistrationLive = McpServer.toolkit(ThreadToolkit).pipe(Layer.provide(ThreadToolkitHandlersLive));
82836
+ const WatchToolkitRegistrationLive = McpServer.toolkit(WatchToolkit).pipe(Layer.provide(WatchToolkitHandlersLive));
82464
82837
  const McpTransportLive = McpServer.layerHttp({
82465
82838
  name: "P4Code",
82466
82839
  version,
82467
82840
  path: "/mcp"
82468
82841
  }).pipe(Layer.provide(McpAuthMiddlewareLive));
82469
- const layer = Layer.mergeAll(PreviewToolkitRegistrationLive, TaskToolkitRegistrationLive, ThreadToolkitRegistrationLive).pipe(Layer.provideMerge(McpTransportLive));
82842
+ const layer = Layer.mergeAll(PreviewToolkitRegistrationLive, TaskToolkitRegistrationLive, ThreadToolkitRegistrationLive, WatchToolkitRegistrationLive).pipe(Layer.provideMerge(McpTransportLive));
82470
82843
  //#endregion
82471
82844
  //#region src/orchestration/Services/CheckpointReactor.ts
82472
82845
  /**
@@ -83877,7 +84250,8 @@ const make$2 = Effect.gen(function* () {
83877
84250
  ...effectiveCwd ? { cwd: effectiveCwd } : {},
83878
84251
  modelSelection: desiredModelSelection,
83879
84252
  ...input?.resumeCursor !== void 0 ? { resumeCursor: input.resumeCursor } : {},
83880
- runtimeMode: desiredRuntimeMode
84253
+ runtimeMode: desiredRuntimeMode,
84254
+ compressMode: thread.compressMode
83881
84255
  });
83882
84256
  const bindSessionToThread = (session) => Effect.gen(function* () {
83883
84257
  if (session.providerInstanceId === void 0) return yield* new ProviderAdapterRequestError({
@@ -83950,6 +84324,7 @@ const make$2 = Effect.gen(function* () {
83950
84324
  const buildSendTurnRequestForThread = Effect.fnUntraced(function* (input) {
83951
84325
  const thread = yield* resolveThread(input.threadId);
83952
84326
  if (!thread) return yield* Effect.die(/* @__PURE__ */ new Error(`Thread '${input.threadId}' was not found in read model.`));
84327
+ const hadActiveSession = thread.session !== null && thread.session.status !== "stopped";
83953
84328
  yield* ensureSessionForThread(input.threadId, input.createdAt, {
83954
84329
  ...input.modelSelection !== void 0 ? { modelSelection: input.modelSelection } : {},
83955
84330
  pendingTurnStart: true
@@ -83968,12 +84343,17 @@ const make$2 = Effect.gen(function* () {
83968
84343
  ...requestedModelSelection,
83969
84344
  model: activeSession.model
83970
84345
  } : requestedModelSelection : input.modelSelection;
84346
+ const compressMode = thread.compressMode;
84347
+ const hasSessionLevelRuleset = activeSession?.provider === "claudeAgent" || activeSession?.provider === "codex";
84348
+ const compressPrefix = !hadActiveSession && !hasSessionLevelRuleset ? compressRulesetFor(compressMode) : compressTurnReminderFor(compressMode);
84349
+ const inputWithCompressPrefix = normalizedInput !== void 0 && compressPrefix !== void 0 ? `${compressPrefix}\n\n${normalizedInput}` : normalizedInput;
83971
84350
  return {
83972
84351
  threadId: input.threadId,
83973
- ...normalizedInput ? { input: normalizedInput } : {},
84352
+ ...inputWithCompressPrefix ? { input: inputWithCompressPrefix } : {},
83974
84353
  ...normalizedAttachments.length > 0 ? { attachments: normalizedAttachments } : {},
83975
84354
  ...modelForTurn !== void 0 ? { modelSelection: modelForTurn } : {},
83976
- ...input.interactionMode !== void 0 ? { interactionMode: input.interactionMode } : {}
84355
+ ...input.interactionMode !== void 0 ? { interactionMode: input.interactionMode } : {},
84356
+ compressMode
83977
84357
  };
83978
84358
  });
83979
84359
  const maybeGenerateAndRenameWorktreeBranchForFirstTurn = Effect.fn("maybeGenerateAndRenameWorktreeBranchForFirstTurn")(function* (input) {