@p4code/cli 0.2.8 → 0.2.10

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.
package/dist/bin.mjs CHANGED
@@ -125,7 +125,7 @@ const closeServer = (server) => {
125
125
  * NetService - Service tag for startup networking helpers.
126
126
  */
127
127
  var NetService = class extends Context.Service()("@p4code/shared/Net/NetService") {};
128
- const make$88 = () => {
128
+ const make$89 = () => {
129
129
  /**
130
130
  * Returns true when a TCP server can bind to {host, port}.
131
131
  * `EADDRNOTAVAIL` is treated as available so IPv6-absent hosts don't fail
@@ -234,10 +234,10 @@ const make$88 = () => {
234
234
  })
235
235
  };
236
236
  };
237
- const layer$79 = Layer.sync(NetService, make$88);
237
+ const layer$80 = Layer.sync(NetService, make$89);
238
238
  //#endregion
239
239
  //#region package.json
240
- var version = "0.2.8";
240
+ var version = "0.2.10";
241
241
  //#endregion
242
242
  //#region src/config.ts
243
243
  /**
@@ -258,8 +258,8 @@ var ServerConfig$1 = class extends Context.Service()("@p4code/cli/config/ServerC
258
258
  /** @deprecated Import and use `layerTest` from this module. */
259
259
  static layerTest = (cwd, baseDirOrPrefix) => layerTest$3(cwd, baseDirOrPrefix);
260
260
  };
261
- const make$87 = (config) => ServerConfig$1.of(config);
262
- const layer$78 = (config) => Layer.succeed(ServerConfig$1, make$87(config));
261
+ const make$88 = (config) => ServerConfig$1.of(config);
262
+ const layer$79 = (config) => Layer.succeed(ServerConfig$1, make$88(config));
263
263
  const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
264
264
  const { join } = yield* Path.Path;
265
265
  const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
@@ -9332,6 +9332,12 @@ const ThreadSpawnResult = Schema$1.Struct({
9332
9332
  projectId: ProjectId,
9333
9333
  title: TrimmedNonEmptyString
9334
9334
  });
9335
+ const ThreadPairCreateInput = Schema$1.Struct({ watcherThreadId: ThreadId.annotate({ description: "The watcher thread to pair with this session's own thread. It must have been created by this session through thread_spawn." }) });
9336
+ const ThreadPairCreateResult = Schema$1.Struct({
9337
+ pairId: ThreadPairId,
9338
+ implementerThreadId: ThreadId,
9339
+ watcherThreadId: ThreadId
9340
+ });
9335
9341
  const ThreadConfigureInput = Schema$1.Struct({
9336
9342
  threadId: ControlTargetThreadId,
9337
9343
  title: Schema$1.optional(TrimmedNonEmptyString),
@@ -10619,6 +10625,116 @@ var UsageReadError = class extends Schema$1.TaggedErrorClass()("UsageReadError",
10619
10625
  }
10620
10626
  };
10621
10627
  //#endregion
10628
+ //#region ../../packages/contracts/src/feed.ts
10629
+ const FeedSourceId = Schema$1.String.pipe(Schema$1.brand("FeedSourceId"));
10630
+ const FeedArticleId = Schema$1.String.pipe(Schema$1.brand("FeedArticleId"));
10631
+ const FeedSourceKind = Schema$1.Literals(["hacker_news", "syndication"]);
10632
+ const FeedArticleStatus = Schema$1.Literals([
10633
+ "pending_summary",
10634
+ "ready",
10635
+ "summary_unavailable",
10636
+ "summary_failed"
10637
+ ]);
10638
+ const FeedEngagementBand = Schema$1.Literals([
10639
+ "unknown",
10640
+ "low",
10641
+ "medium",
10642
+ "high"
10643
+ ]);
10644
+ var FeedSource = class extends Schema$1.Class("FeedSource")({
10645
+ id: FeedSourceId,
10646
+ name: Schema$1.String,
10647
+ kind: FeedSourceKind,
10648
+ feedUrl: Schema$1.String,
10649
+ siteUrl: Schema$1.String,
10650
+ enabled: Schema$1.Boolean,
10651
+ createdAt: Schema$1.String,
10652
+ updatedAt: Schema$1.String
10653
+ }) {};
10654
+ var FeedEngagement = class extends Schema$1.Class("FeedEngagement")({
10655
+ articleId: FeedArticleId,
10656
+ points: Schema$1.NullOr(Schema$1.Number),
10657
+ comments: Schema$1.NullOr(Schema$1.Number),
10658
+ band: FeedEngagementBand,
10659
+ observedAt: Schema$1.String
10660
+ }) {};
10661
+ var FeedSummary = class extends Schema$1.Class("FeedSummary")({
10662
+ articleId: FeedArticleId,
10663
+ modelSelection: Schema$1.String,
10664
+ summary: Schema$1.String,
10665
+ highlights: Schema$1.Array(Schema$1.String),
10666
+ references: Schema$1.Array(Schema$1.String),
10667
+ summarizedAt: Schema$1.String
10668
+ }) {};
10669
+ var FeedArticle = class extends Schema$1.Class("FeedArticle")({
10670
+ id: FeedArticleId,
10671
+ sourceId: FeedSourceId,
10672
+ sourceName: Schema$1.String,
10673
+ canonicalUrl: Schema$1.String,
10674
+ discussionUrl: Schema$1.NullOr(Schema$1.String),
10675
+ title: Schema$1.String,
10676
+ author: Schema$1.NullOr(Schema$1.String),
10677
+ publishedAt: Schema$1.String,
10678
+ fetchedAt: Schema$1.String,
10679
+ contentText: Schema$1.NullOr(Schema$1.String),
10680
+ status: FeedArticleStatus,
10681
+ summary: Schema$1.NullOr(FeedSummary),
10682
+ engagement: FeedEngagement,
10683
+ readAt: Schema$1.NullOr(Schema$1.String)
10684
+ }) {};
10685
+ var FeedListInput = class extends Schema$1.Class("FeedListInput")({
10686
+ query: Schema$1.optional(Schema$1.String),
10687
+ sourceId: Schema$1.optional(FeedSourceId),
10688
+ unreadOnly: Schema$1.optional(Schema$1.Boolean),
10689
+ startDate: Schema$1.optional(Schema$1.String),
10690
+ endDate: Schema$1.optional(Schema$1.String),
10691
+ sort: Schema$1.optional(Schema$1.Literals(["newest", "oldest"]))
10692
+ }) {};
10693
+ var FeedListResult = class extends Schema$1.Class("FeedListResult")({
10694
+ articles: Schema$1.Array(FeedArticle),
10695
+ refreshedAt: Schema$1.NullOr(Schema$1.String)
10696
+ }) {};
10697
+ var FeedSourceUpsertInput = class extends Schema$1.Class("FeedSourceUpsertInput")({
10698
+ id: Schema$1.optional(FeedSourceId),
10699
+ name: Schema$1.String,
10700
+ kind: FeedSourceKind,
10701
+ feedUrl: Schema$1.String,
10702
+ siteUrl: Schema$1.String,
10703
+ enabled: Schema$1.Boolean
10704
+ }) {};
10705
+ var FeedSourceIdInput = class extends Schema$1.Class("FeedSourceIdInput")({ sourceId: FeedSourceId }) {};
10706
+ var FeedMarkReadInput = class extends Schema$1.Class("FeedMarkReadInput")({
10707
+ articleId: FeedArticleId,
10708
+ read: Schema$1.Boolean
10709
+ }) {};
10710
+ var FeedCleanupInput = class extends Schema$1.Class("FeedCleanupInput")({
10711
+ startDate: Schema$1.String,
10712
+ endDate: Schema$1.String,
10713
+ confirm: Schema$1.Boolean
10714
+ }) {};
10715
+ var FeedCleanupResult = class extends Schema$1.Class("FeedCleanupResult")({
10716
+ count: Schema$1.Number,
10717
+ deleted: Schema$1.Boolean
10718
+ }) {};
10719
+ var FeedRefreshResult = class extends Schema$1.Class("FeedRefreshResult")({
10720
+ fetched: Schema$1.Number,
10721
+ summarized: Schema$1.Number,
10722
+ failedSources: Schema$1.Array(Schema$1.String),
10723
+ refreshedAt: Schema$1.String
10724
+ }) {};
10725
+ var FeedError = class extends Schema$1.TaggedErrorClass()("FeedError", {
10726
+ code: Schema$1.Literals([
10727
+ "hub_unavailable",
10728
+ "invalid_feed",
10729
+ "fetch_failed",
10730
+ "article_unreadable",
10731
+ "luna_unavailable",
10732
+ "summarization_failed"
10733
+ ]),
10734
+ message: Schema$1.String
10735
+ }) {};
10736
+ const FeedSourceList = Schema$1.Array(FeedSource);
10737
+ //#endregion
10622
10738
  //#region ../../packages/contracts/src/rpc.ts
10623
10739
  const WS_METHODS = {
10624
10740
  projectsList: "projects.list",
@@ -10698,6 +10814,13 @@ const WS_METHODS = {
10698
10814
  tasksUpdate: "tasks.update",
10699
10815
  tasksDelete: "tasks.delete",
10700
10816
  tasksStartThread: "tasks.startThread",
10817
+ feedList: "feed.list",
10818
+ feedRefresh: "feed.refresh",
10819
+ feedSourcesList: "feed.sources.list",
10820
+ feedSourcesUpsert: "feed.sources.upsert",
10821
+ feedSourcesDelete: "feed.sources.delete",
10822
+ feedMarkRead: "feed.markRead",
10823
+ feedCleanup: "feed.cleanup",
10701
10824
  hubGetSyncStatus: "hub.getSyncStatus",
10702
10825
  hubConnect: "hub.connect",
10703
10826
  hubDisconnect: "hub.disconnect",
@@ -10804,6 +10927,42 @@ const WsTasksDeleteRpc = Rpc.make(WS_METHODS.tasksDelete, {
10804
10927
  success: Schema$1.Struct({}),
10805
10928
  error: TaskRpcError
10806
10929
  });
10930
+ const FeedRpcError = Schema$1.Union([FeedError, EnvironmentAuthorizationError]);
10931
+ const WsFeedListRpc = Rpc.make(WS_METHODS.feedList, {
10932
+ payload: FeedListInput,
10933
+ success: FeedListResult,
10934
+ error: FeedRpcError
10935
+ });
10936
+ const WsFeedRefreshRpc = Rpc.make(WS_METHODS.feedRefresh, {
10937
+ payload: Schema$1.Struct({}),
10938
+ success: FeedRefreshResult,
10939
+ error: FeedRpcError
10940
+ });
10941
+ const WsFeedSourcesListRpc = Rpc.make(WS_METHODS.feedSourcesList, {
10942
+ payload: Schema$1.Struct({}),
10943
+ success: FeedSourceList,
10944
+ error: FeedRpcError
10945
+ });
10946
+ const WsFeedSourcesUpsertRpc = Rpc.make(WS_METHODS.feedSourcesUpsert, {
10947
+ payload: FeedSourceUpsertInput,
10948
+ success: FeedSource,
10949
+ error: FeedRpcError
10950
+ });
10951
+ const WsFeedSourcesDeleteRpc = Rpc.make(WS_METHODS.feedSourcesDelete, {
10952
+ payload: FeedSourceIdInput,
10953
+ success: Schema$1.Struct({}),
10954
+ error: FeedRpcError
10955
+ });
10956
+ const WsFeedMarkReadRpc = Rpc.make(WS_METHODS.feedMarkRead, {
10957
+ payload: FeedMarkReadInput,
10958
+ success: Schema$1.Struct({}),
10959
+ error: FeedRpcError
10960
+ });
10961
+ const WsFeedCleanupRpc = Rpc.make(WS_METHODS.feedCleanup, {
10962
+ payload: FeedCleanupInput,
10963
+ success: FeedCleanupResult,
10964
+ error: FeedRpcError
10965
+ });
10807
10966
  /**
10808
10967
  * Start an agent on a task.
10809
10968
  *
@@ -11542,7 +11701,7 @@ const WsSubscribeAuthAccessRpc = Rpc.make(WS_METHODS.subscribeAuthAccess, {
11542
11701
  error: Schema$1.Union([AuthAccessStreamError, EnvironmentAuthorizationError]),
11543
11702
  stream: true
11544
11703
  });
11545
- const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetProviderUsageRpc, WsServerGetUsageSummaryRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsPullRequestsListRpc, WsPullRequestsListStatsRpc, WsPullRequestsDetailRpc, WsPullRequestsActivityRpc, WsPullRequestsDiffFileContentsRpc, WsPullRequestsRunActionRpc, WsPullRequestsUpdateRpc, WsPullRequestsCommentRpc, WsPullRequestsUpdateCommentRpc, WsPullRequestsSubmitReviewRpc, WsPullRequestsReplyToThreadRpc, WsPullRequestsSetThreadResolutionRpc, WsPullRequestsSetReactionRpc, WsPullRequestsInvalidateRpc, WsPullRequestsReviewerCandidatesRpc, WsPullRequestsRequestReviewersRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsAssetsCreateLocalRpc, WsAssetsRemoveLocalRpc, WsSkillRegistrySearchRpc, WsSkillRegistryFetchRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsMcpOAuthBeginRpc, WsMcpOAuthDisconnectRpc, WsTrackerStatusRpc, WsTrackerSetApiKeyRpc, WsTrackerClearApiKeyRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationSearchThreadsRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
11704
+ const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetProviderUsageRpc, WsServerGetUsageSummaryRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsPullRequestsListRpc, WsPullRequestsListStatsRpc, WsPullRequestsDetailRpc, WsPullRequestsActivityRpc, WsPullRequestsDiffFileContentsRpc, WsPullRequestsRunActionRpc, WsPullRequestsUpdateRpc, WsPullRequestsCommentRpc, WsPullRequestsUpdateCommentRpc, WsPullRequestsSubmitReviewRpc, WsPullRequestsReplyToThreadRpc, WsPullRequestsSetThreadResolutionRpc, WsPullRequestsSetReactionRpc, WsPullRequestsInvalidateRpc, WsPullRequestsReviewerCandidatesRpc, WsPullRequestsRequestReviewersRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsFeedListRpc, WsFeedRefreshRpc, WsFeedSourcesListRpc, WsFeedSourcesUpsertRpc, WsFeedSourcesDeleteRpc, WsFeedMarkReadRpc, WsFeedCleanupRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsAssetsCreateLocalRpc, WsAssetsRemoveLocalRpc, WsSkillRegistrySearchRpc, WsSkillRegistryFetchRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsMcpOAuthBeginRpc, WsMcpOAuthDisconnectRpc, WsTrackerStatusRpc, WsTrackerSetApiKeyRpc, WsTrackerClearApiKeyRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationSearchThreadsRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
11546
11705
  //#endregion
11547
11706
  //#region ../../packages/shared/src/oauthScope.ts
11548
11707
  const OAUTH_SCOPE_TOKEN = /^[\u0021\u0023-\u005b\u005d-\u007e]+$/u;
@@ -11688,7 +11847,7 @@ function deriveAuthClientMetadata(input) {
11688
11847
  //#endregion
11689
11848
  //#region src/auth/EnvironmentAuthPolicy.ts
11690
11849
  var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
11691
- const make$86 = Effect.gen(function* () {
11850
+ const make$87 = Effect.gen(function* () {
11692
11851
  const config = yield* ServerConfig$1;
11693
11852
  const isRemoteReachable = isRemoteReachableHost(config.host);
11694
11853
  const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
@@ -11706,7 +11865,7 @@ const make$86 = Effect.gen(function* () {
11706
11865
  };
11707
11866
  return EnvironmentAuthPolicy.of({ getDescriptor: () => Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")) });
11708
11867
  });
11709
- const layer$77 = Layer.effect(EnvironmentAuthPolicy, make$86);
11868
+ const layer$78 = Layer.effect(EnvironmentAuthPolicy, make$87);
11710
11869
  //#endregion
11711
11870
  //#region src/persistence/Errors.ts
11712
11871
  function summarizeSchemaIssue(issue) {
@@ -11887,7 +12046,7 @@ function toPersistenceSqlOrDecodeError$6(sqlOperation, decodeOperation, correlat
11887
12046
  cause
11888
12047
  });
11889
12048
  }
11890
- const make$85 = Effect.gen(function* () {
12049
+ const make$86 = Effect.gen(function* () {
11891
12050
  const sql = yield* SqlClient.SqlClient;
11892
12051
  const createSessionRow = SqlSchema.void({
11893
12052
  Request: CreateAuthSessionInput,
@@ -12021,7 +12180,7 @@ const make$85 = Effect.gen(function* () {
12021
12180
  setLastConnectedAt
12022
12181
  };
12023
12182
  });
12024
- const layer$76 = Layer.effect(AuthSessionRepository, make$85);
12183
+ const layer$77 = Layer.effect(AuthSessionRepository, make$86);
12025
12184
  //#endregion
12026
12185
  //#region src/auth/ServerSecretStore.ts
12027
12186
  const secretStoreErrorContext = {
@@ -12088,7 +12247,7 @@ const isSecretStoreError = Schema$1.is(SecretStoreError);
12088
12247
  const isPlatformError = (value) => Predicate.isTagged(value, "PlatformError");
12089
12248
  const isSecretAlreadyExistsError = (error) => "cause" in error && isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists";
12090
12249
  var ServerSecretStore = class extends Context.Service()("@p4code/cli/auth/ServerSecretStore") {};
12091
- const make$84 = Effect.gen(function* () {
12250
+ const make$85 = Effect.gen(function* () {
12092
12251
  const crypto = yield* Crypto.Crypto;
12093
12252
  const fileSystem = yield* FileSystem.FileSystem;
12094
12253
  const path = yield* Path.Path;
@@ -12158,7 +12317,7 @@ const make$84 = Effect.gen(function* () {
12158
12317
  remove
12159
12318
  });
12160
12319
  });
12161
- const layer$75 = Layer.effect(ServerSecretStore, make$84);
12320
+ const layer$76 = Layer.effect(ServerSecretStore, make$85);
12162
12321
  //#endregion
12163
12322
  //#region src/auth/SessionStore.ts
12164
12323
  var MalformedSessionTokenError = class extends Schema$1.TaggedErrorClass()("MalformedSessionTokenError", {}) {
@@ -12396,7 +12555,7 @@ function toAuthClientSession(input) {
12396
12555
  current: false
12397
12556
  };
12398
12557
  }
12399
- const make$83 = Effect.gen(function* () {
12558
+ const make$84 = Effect.gen(function* () {
12400
12559
  const crypto = yield* Crypto.Crypto;
12401
12560
  const serverConfig = yield* ServerConfig$1;
12402
12561
  const secretStore = yield* ServerSecretStore;
@@ -12710,7 +12869,7 @@ const make$83 = Effect.gen(function* () {
12710
12869
  markDisconnected
12711
12870
  });
12712
12871
  });
12713
- const layer$74 = Layer.effect(SessionStore, make$83).pipe(Layer.provideMerge(layer$76));
12872
+ const layer$75 = Layer.effect(SessionStore, make$84).pipe(Layer.provideMerge(layer$77));
12714
12873
  //#endregion
12715
12874
  //#region src/persistence/AuthPairingLinks.ts
12716
12875
  const AuthPairingLinkRecord = Schema$1.Struct({
@@ -12771,7 +12930,7 @@ function toPersistenceSqlOrDecodeError$5(sqlOperation, decodeOperation, correlat
12771
12930
  cause
12772
12931
  });
12773
12932
  }
12774
- const make$82 = Effect.gen(function* () {
12933
+ const make$83 = Effect.gen(function* () {
12775
12934
  const sql = yield* SqlClient.SqlClient;
12776
12935
  const createPairingLinkRow = SqlSchema.void({
12777
12936
  Request: CreateAuthPairingLinkInput,
@@ -12906,7 +13065,7 @@ const make$82 = Effect.gen(function* () {
12906
13065
  getByCredential
12907
13066
  };
12908
13067
  });
12909
- const layer$73 = Layer.effect(AuthPairingLinkRepository, make$82);
13068
+ const layer$74 = Layer.effect(AuthPairingLinkRepository, make$83);
12910
13069
  //#endregion
12911
13070
  //#region src/auth/PairingGrantStore.ts
12912
13071
  var UnknownBootstrapCredentialError = class extends Schema$1.TaggedErrorClass()("UnknownBootstrapCredentialError", {}) {
@@ -13001,7 +13160,7 @@ const DEV_STARTUP_TTL_HOURS = Duration.hours(24);
13001
13160
  const PAIRING_TOKEN_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
13002
13161
  const PAIRING_TOKEN_LENGTH = 12;
13003
13162
  const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
13004
- const make$81 = Effect.gen(function* () {
13163
+ const make$82 = Effect.gen(function* () {
13005
13164
  const crypto = yield* Crypto.Crypto;
13006
13165
  const config = yield* ServerConfig$1;
13007
13166
  const pairingLinks = yield* AuthPairingLinkRepository;
@@ -13199,7 +13358,7 @@ const make$81 = Effect.gen(function* () {
13199
13358
  consume
13200
13359
  });
13201
13360
  });
13202
- const layer$72 = Layer.effect(PairingGrantStore, make$81).pipe(Layer.provideMerge(layer$73));
13361
+ const layer$73 = Layer.effect(PairingGrantStore, make$82).pipe(Layer.provideMerge(layer$74));
13203
13362
  //#endregion
13204
13363
  //#region src/persistence/DatabaseSnapshot.ts
13205
13364
  /**
@@ -15517,7 +15676,7 @@ function parseBearerToken(request) {
15517
15676
  const token = header.slice(7).trim();
15518
15677
  return token.length > 0 ? token : null;
15519
15678
  }
15520
- const make$80 = Effect.gen(function* () {
15679
+ const make$81 = Effect.gen(function* () {
15521
15680
  const policy = yield* EnvironmentAuthPolicy;
15522
15681
  const bootstrapCredentials = yield* PairingGrantStore;
15523
15682
  const sessions = yield* SessionStore;
@@ -15712,9 +15871,9 @@ const make$80 = Effect.gen(function* () {
15712
15871
  issueStartupPairingUrl
15713
15872
  });
15714
15873
  });
15715
- const layer$71 = Layer.effect(EnvironmentAuth, make$80).pipe(Layer.provideMerge(layer$72), Layer.provideMerge(layer$74), Layer.provideMerge(layer$77));
15716
- const storageLayer = Layer.mergeAll(layer$75, layerConfig);
15717
- const runtimeLayer = layer$71.pipe(Layer.provideMerge(storageLayer));
15874
+ const layer$72 = Layer.effect(EnvironmentAuth, make$81).pipe(Layer.provideMerge(layer$73), Layer.provideMerge(layer$75), Layer.provideMerge(layer$78));
15875
+ const storageLayer = Layer.mergeAll(layer$76, layerConfig);
15876
+ const runtimeLayer = layer$72.pipe(Layer.provideMerge(storageLayer));
15718
15877
  //#endregion
15719
15878
  //#region src/cliAuthFormat.ts
15720
15879
  const newline = "\n";
@@ -16469,7 +16628,7 @@ const runWithEnvironmentAuth = (flags, run, options) => Effect.gen(function* ()
16469
16628
  }
16470
16629
  return yield* Effect.gen(function* () {
16471
16630
  return yield* run(yield* EnvironmentAuth);
16472
- }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$78(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
16631
+ }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer).pipe(Layer.provide(layer$79(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
16473
16632
  });
16474
16633
  const ttlFlag = Flag.string("ttl").pipe(Flag.withSchema(DurationFromString), Flag.withDescription("TTL, for example `5m`, `1h`, `30d`, or `15 minutes`."), Flag.optional);
16475
16634
  const jsonFlag = Flag.boolean("json").pipe(Flag.withDescription("Emit JSON instead of human-readable output."), Flag.withDefault(false));
@@ -16609,7 +16768,7 @@ const DEFAULT_LIMITS = {
16609
16768
  windowMillis: FAILURE_WINDOW_MS,
16610
16769
  blockMillis: BLOCK_DURATION_MS
16611
16770
  };
16612
- const make$79 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
16771
+ const make$80 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
16613
16772
  const state = yield* Ref.make(initialThrottleState);
16614
16773
  return HubAuthThrottle.of({
16615
16774
  shouldRefuse: Effect.gen(function* () {
@@ -16623,7 +16782,7 @@ const make$79 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LI
16623
16782
  })
16624
16783
  });
16625
16784
  });
16626
- const layer$70 = Layer.effect(HubAuthThrottle, make$79());
16785
+ const layer$71 = Layer.effect(HubAuthThrottle, make$80());
16627
16786
  //#endregion
16628
16787
  //#region src/hub/HubAuth.ts
16629
16788
  /**
@@ -17484,7 +17643,181 @@ const deleteAssetRoute = HttpRouter.add("DELETE", "/assets/:kind/:name", respond
17484
17643
  const outcome = yield* (yield* AgentAssetRepository).deleteByName(requested);
17485
17644
  return outcome._tag === "conflict" ? assetConflict(Option.getOrNull(outcome.current)) : HttpServerResponse.empty({ status: 204 });
17486
17645
  })));
17487
- const layer$69 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, putTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute);
17646
+ const feedSourceColumns = `id, name, kind, feed_url AS "feedUrl", site_url AS "siteUrl",
17647
+ enabled, created_at AS "createdAt", updated_at AS "updatedAt"`;
17648
+ const toFeedSource = (row) => ({
17649
+ ...row,
17650
+ enabled: Boolean(row.enabled)
17651
+ });
17652
+ const FeedArticleWrite = Schema$1.Struct({
17653
+ sourceId: Schema$1.String,
17654
+ canonicalUrl: Schema$1.String,
17655
+ discussionUrl: Schema$1.NullOr(Schema$1.String),
17656
+ title: Schema$1.String,
17657
+ author: Schema$1.NullOr(Schema$1.String),
17658
+ publishedAt: Schema$1.String,
17659
+ fetchedAt: Schema$1.String,
17660
+ contentText: Schema$1.NullOr(Schema$1.String),
17661
+ status: Schema$1.String,
17662
+ contentRevision: Schema$1.String,
17663
+ summary: Schema$1.NullOr(Schema$1.Struct({
17664
+ modelSelection: Schema$1.String,
17665
+ summary: Schema$1.String,
17666
+ highlights: Schema$1.Array(Schema$1.String),
17667
+ references: Schema$1.Array(Schema$1.String),
17668
+ summarizedAt: Schema$1.String
17669
+ })),
17670
+ engagement: Schema$1.Struct({
17671
+ points: Schema$1.NullOr(Schema$1.Number),
17672
+ comments: Schema$1.NullOr(Schema$1.Number),
17673
+ band: Schema$1.String,
17674
+ observedAt: Schema$1.String
17675
+ })
17676
+ });
17677
+ const listFeedSourcesRoute = HttpRouter.add("GET", "/feed/sources", respondToHubFailures(Effect.gen(function* () {
17678
+ yield* authenticateHubRequest();
17679
+ const rows = yield* (yield* SqlClient.SqlClient).unsafe(`SELECT ${feedSourceColumns} FROM feed_sources ORDER BY name`);
17680
+ return HttpServerResponse.jsonUnsafe(rows.map(toFeedSource));
17681
+ })));
17682
+ const upsertFeedSourceRoute = HttpRouter.add("PUT", "/feed/sources", respondToHubFailures(Effect.gen(function* () {
17683
+ yield* authenticateHubRequest();
17684
+ const input = yield* decodeOrInvalid(FeedSourceUpsertInput, "Request body does not match FeedSourceUpsertInput.")(yield* readJsonBody());
17685
+ const sql = yield* SqlClient.SqlClient;
17686
+ const crypto = yield* Crypto.Crypto;
17687
+ const id = input.id ?? FeedSourceId.make(yield* crypto.randomUUIDv4.pipe(Effect.orDie));
17688
+ const now = DateTime.formatIso(yield* DateTime.now);
17689
+ yield* sql`INSERT INTO feed_sources (id, name, kind, feed_url, site_url, enabled, created_at, updated_at)
17690
+ VALUES (${id}, ${input.name}, ${input.kind}, ${input.feedUrl}, ${input.siteUrl}, ${input.enabled ? 1 : 0}, ${now}, ${now})
17691
+ ON CONFLICT(id) DO UPDATE SET name=excluded.name, kind=excluded.kind, feed_url=excluded.feed_url,
17692
+ site_url=excluded.site_url, enabled=excluded.enabled, updated_at=excluded.updated_at`;
17693
+ const rows = yield* sql.unsafe(`SELECT ${feedSourceColumns} FROM feed_sources WHERE id = ?`, [id]);
17694
+ return HttpServerResponse.jsonUnsafe(toFeedSource(rows[0] ?? {}));
17695
+ })));
17696
+ const deleteFeedSourceRoute = HttpRouter.add("DELETE", "/feed/sources/:sourceId", respondToHubFailures(Effect.gen(function* () {
17697
+ yield* authenticateHubRequest();
17698
+ const params = yield* HttpRouter.params;
17699
+ yield* (yield* SqlClient.SqlClient)`DELETE FROM feed_sources WHERE id = ${params.sourceId ?? ""}`;
17700
+ return HttpServerResponse.empty({ status: 204 });
17701
+ })));
17702
+ const listFeedRoute = HttpRouter.add("GET", "/feed/articles", respondToHubFailures(Effect.gen(function* () {
17703
+ yield* authenticateHubRequest();
17704
+ const sql = yield* SqlClient.SqlClient;
17705
+ const articles = yield* sql`
17706
+ SELECT a.id, a.source_id AS "sourceId", s.name AS "sourceName", a.canonical_url AS "canonicalUrl",
17707
+ a.discussion_url AS "discussionUrl", a.title, a.author, a.published_at AS "publishedAt",
17708
+ a.fetched_at AS "fetchedAt", a.content_text AS "contentText", a.status,
17709
+ sm.model_selection AS "modelSelection", sm.summary, sm.highlights_json AS "highlightsJson",
17710
+ sm.references_json AS "referencesJson", sm.summarized_at AS "summarizedAt",
17711
+ e.points, e.comments, COALESCE(e.band, 'unknown') AS band, COALESCE(e.observed_at, a.fetched_at) AS "observedAt",
17712
+ r.read_at AS "readAt"
17713
+ FROM feed_articles a JOIN feed_sources s ON s.id=a.source_id
17714
+ LEFT JOIN feed_summaries sm ON sm.article_id=a.id
17715
+ LEFT JOIN feed_engagement e ON e.article_id=a.id
17716
+ LEFT JOIN feed_read_state r ON r.article_id=a.id ORDER BY a.published_at DESC`;
17717
+ const metadata = yield* sql`SELECT value FROM feed_metadata WHERE key='refreshed_at'`;
17718
+ return HttpServerResponse.jsonUnsafe({
17719
+ articles: articles.map((row) => ({
17720
+ id: row.id,
17721
+ sourceId: row.sourceId,
17722
+ sourceName: row.sourceName,
17723
+ canonicalUrl: row.canonicalUrl,
17724
+ discussionUrl: row.discussionUrl ?? null,
17725
+ title: row.title,
17726
+ author: row.author ?? null,
17727
+ publishedAt: row.publishedAt,
17728
+ fetchedAt: row.fetchedAt,
17729
+ contentText: row.contentText ?? null,
17730
+ status: row.status,
17731
+ readAt: row.readAt ?? null,
17732
+ summary: row.summary == null ? null : {
17733
+ articleId: row.id,
17734
+ modelSelection: row.modelSelection,
17735
+ summary: row.summary,
17736
+ highlights: JSON.parse(String(row.highlightsJson)),
17737
+ references: JSON.parse(String(row.referencesJson)),
17738
+ summarizedAt: row.summarizedAt
17739
+ },
17740
+ engagement: {
17741
+ articleId: row.id,
17742
+ points: row.points ?? null,
17743
+ comments: row.comments ?? null,
17744
+ band: row.band,
17745
+ observedAt: row.observedAt
17746
+ }
17747
+ })),
17748
+ refreshedAt: metadata[0]?.value ?? null
17749
+ });
17750
+ })));
17751
+ const putFeedArticleRoute = HttpRouter.add("PUT", "/feed/articles/:articleId", respondToHubFailures(Effect.gen(function* () {
17752
+ yield* authenticateHubRequest();
17753
+ const params = yield* HttpRouter.params;
17754
+ const body = yield* decodeOrInvalid(FeedArticleWrite, "Request body does not match feed article storage contract.")(yield* readJsonBody());
17755
+ const sql = yield* SqlClient.SqlClient;
17756
+ const id = params.articleId ?? "";
17757
+ yield* sql`INSERT INTO feed_articles (id, source_id, canonical_url, discussion_url, title, author, published_at, fetched_at, content_text, status, content_revision)
17758
+ VALUES (${id}, ${body.sourceId}, ${body.canonicalUrl}, ${body.discussionUrl ?? null}, ${body.title}, ${body.author ?? null}, ${body.publishedAt}, ${body.fetchedAt}, ${body.contentText ?? null}, ${body.status}, ${body.contentRevision})
17759
+ ON CONFLICT(canonical_url) DO UPDATE SET discussion_url=excluded.discussion_url, title=excluded.title,
17760
+ author=excluded.author, published_at=excluded.published_at, fetched_at=excluded.fetched_at,
17761
+ content_text=excluded.content_text, status=excluded.status, content_revision=excluded.content_revision`;
17762
+ if (body.summary) {
17763
+ const summary = body.summary;
17764
+ yield* sql`INSERT INTO feed_summaries (article_id, model_selection, summary, highlights_json, references_json, summarized_at, content_revision)
17765
+ VALUES (${id}, ${summary.modelSelection}, ${summary.summary}, ${JSON.stringify(summary.highlights)}, ${JSON.stringify(summary.references)}, ${summary.summarizedAt}, ${body.contentRevision})
17766
+ ON CONFLICT(article_id) DO UPDATE SET model_selection=excluded.model_selection, summary=excluded.summary,
17767
+ highlights_json=excluded.highlights_json, references_json=excluded.references_json, summarized_at=excluded.summarized_at, content_revision=excluded.content_revision`;
17768
+ }
17769
+ const engagement = body.engagement;
17770
+ yield* sql`INSERT INTO feed_engagement (article_id, points, comments, band, observed_at)
17771
+ VALUES (${id}, ${engagement.points ?? null}, ${engagement.comments ?? null}, ${engagement.band}, ${engagement.observedAt})
17772
+ ON CONFLICT(article_id) DO UPDATE SET points=excluded.points, comments=excluded.comments, band=excluded.band, observed_at=excluded.observed_at`;
17773
+ return HttpServerResponse.empty({ status: 204 });
17774
+ })));
17775
+ const markFeedReadRoute = HttpRouter.add("PUT", "/feed/read", respondToHubFailures(Effect.gen(function* () {
17776
+ yield* authenticateHubRequest();
17777
+ const input = yield* decodeOrInvalid(FeedMarkReadInput, "Request body does not match FeedMarkReadInput.")(yield* readJsonBody());
17778
+ const sql = yield* SqlClient.SqlClient;
17779
+ const readAt = input.read ? DateTime.formatIso(yield* DateTime.now) : null;
17780
+ yield* sql`INSERT INTO feed_read_state (article_id, read_at) VALUES (${input.articleId}, ${readAt})
17781
+ ON CONFLICT(article_id) DO UPDATE SET read_at=excluded.read_at`;
17782
+ return HttpServerResponse.empty({ status: 204 });
17783
+ })));
17784
+ const cleanupFeedRoute = HttpRouter.add("POST", "/feed/cleanup", respondToHubFailures(Effect.gen(function* () {
17785
+ yield* authenticateHubRequest();
17786
+ const input = yield* decodeOrInvalid(FeedCleanupInput, "Request body does not match FeedCleanupInput.")(yield* readJsonBody());
17787
+ const sql = yield* SqlClient.SqlClient;
17788
+ const rows = yield* sql`SELECT COUNT(*) AS count FROM feed_articles WHERE published_at >= ${input.startDate} AND published_at <= ${input.endDate}`;
17789
+ const count = Number(rows[0]?.count ?? 0);
17790
+ if (input.confirm) yield* sql`DELETE FROM feed_articles WHERE published_at >= ${input.startDate} AND published_at <= ${input.endDate}`;
17791
+ return HttpServerResponse.jsonUnsafe({
17792
+ count,
17793
+ deleted: input.confirm
17794
+ });
17795
+ })));
17796
+ const setFeedRefreshedAtRoute = HttpRouter.add("PUT", "/feed/refreshed-at", respondToHubFailures(Effect.gen(function* () {
17797
+ yield* authenticateHubRequest();
17798
+ const body = yield* readJsonBody();
17799
+ if (typeof body.refreshedAt !== "string") return yield* new InvalidHubRequest({ detail: "refreshedAt is required." });
17800
+ yield* (yield* SqlClient.SqlClient)`INSERT INTO feed_metadata (key, value) VALUES ('refreshed_at', ${body.refreshedAt}) ON CONFLICT(key) DO UPDATE SET value=excluded.value`;
17801
+ return HttpServerResponse.empty({ status: 204 });
17802
+ })));
17803
+ const acquireFeedLeaseRoute = HttpRouter.add("POST", "/feed/lease", respondToHubFailures(Effect.gen(function* () {
17804
+ yield* authenticateHubRequest();
17805
+ const body = yield* readJsonBody();
17806
+ if (typeof body.owner !== "string" || typeof body.expiresAt !== "string") return yield* new InvalidHubRequest({ detail: "owner and expiresAt are required." });
17807
+ const sql = yield* SqlClient.SqlClient;
17808
+ yield* sql`DELETE FROM feed_refresh_lease WHERE lease_key='refresh' AND expires_at <= ${DateTime.formatIso(yield* DateTime.now)}`;
17809
+ yield* sql`INSERT INTO feed_refresh_lease (lease_key, owner, expires_at) VALUES ('refresh', ${body.owner}, ${body.expiresAt}) ON CONFLICT(lease_key) DO NOTHING`;
17810
+ const rows = yield* sql`SELECT owner FROM feed_refresh_lease WHERE lease_key='refresh'`;
17811
+ return HttpServerResponse.jsonUnsafe({ acquired: rows[0]?.owner === body.owner });
17812
+ })));
17813
+ const releaseFeedLeaseRoute = HttpRouter.add("DELETE", "/feed/lease", respondToHubFailures(Effect.gen(function* () {
17814
+ yield* authenticateHubRequest();
17815
+ const body = yield* readJsonBody();
17816
+ if (typeof body.owner !== "string") return yield* new InvalidHubRequest({ detail: "owner is required." });
17817
+ yield* (yield* SqlClient.SqlClient)`DELETE FROM feed_refresh_lease WHERE lease_key='refresh' AND owner=${body.owner}`;
17818
+ return HttpServerResponse.empty({ status: 204 });
17819
+ })));
17820
+ const layer$70 = Layer.mergeAll(healthRoute, listTasksRoute, getTaskRoute, createTaskRoute, putTaskRoute, updateTaskRoute, deleteTaskRoute, listAssetsRoute, getAssetRoute, putAssetRoute, deleteAssetRoute, listFeedSourcesRoute, upsertFeedSourceRoute, deleteFeedSourceRoute, listFeedRoute, putFeedArticleRoute, markFeedReadRoute, cleanupFeedRoute, setFeedRefreshedAtRoute, acquireFeedLeaseRoute, releaseFeedLeaseRoute);
17488
17821
  //#endregion
17489
17822
  //#region src/hub/Migrations/001_Tasks.ts
17490
17823
  /**
@@ -17690,6 +18023,77 @@ var _008_TaskExternalRefRemoved_default = Effect.gen(function* () {
17690
18023
  yield* sql`ALTER TABLE tasks DROP COLUMN external_ref_json`;
17691
18024
  });
17692
18025
  //#endregion
18026
+ //#region src/hub/Migrations/009_Feed.ts
18027
+ var _009_Feed_default = Effect.gen(function* () {
18028
+ const sql = yield* SqlClient.SqlClient;
18029
+ yield* sql`CREATE TABLE feed_sources (
18030
+ id TEXT PRIMARY KEY, name TEXT NOT NULL, kind TEXT NOT NULL, feed_url TEXT NOT NULL,
18031
+ site_url TEXT NOT NULL, enabled INTEGER NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL
18032
+ )`;
18033
+ yield* sql`CREATE TABLE feed_articles (
18034
+ id TEXT PRIMARY KEY, source_id TEXT NOT NULL REFERENCES feed_sources(id) ON DELETE CASCADE,
18035
+ canonical_url TEXT NOT NULL UNIQUE, discussion_url TEXT, title TEXT NOT NULL, author TEXT,
18036
+ published_at TEXT NOT NULL, fetched_at TEXT NOT NULL, content_text TEXT, status TEXT NOT NULL,
18037
+ content_revision TEXT NOT NULL
18038
+ )`;
18039
+ yield* sql`CREATE TABLE feed_summaries (
18040
+ article_id TEXT PRIMARY KEY REFERENCES feed_articles(id) ON DELETE CASCADE,
18041
+ model_selection TEXT NOT NULL, summary TEXT NOT NULL, highlights_json TEXT NOT NULL,
18042
+ references_json TEXT NOT NULL, summarized_at TEXT NOT NULL, content_revision TEXT NOT NULL
18043
+ )`;
18044
+ yield* sql`CREATE TABLE feed_engagement (
18045
+ article_id TEXT PRIMARY KEY REFERENCES feed_articles(id) ON DELETE CASCADE,
18046
+ points INTEGER, comments INTEGER, band TEXT NOT NULL, observed_at TEXT NOT NULL
18047
+ )`;
18048
+ yield* sql`CREATE TABLE feed_read_state (
18049
+ article_id TEXT PRIMARY KEY REFERENCES feed_articles(id) ON DELETE CASCADE, read_at TEXT
18050
+ )`;
18051
+ yield* sql`CREATE TABLE feed_refresh_lease (
18052
+ lease_key TEXT PRIMARY KEY, owner TEXT NOT NULL, expires_at TEXT NOT NULL
18053
+ )`;
18054
+ yield* sql`CREATE TABLE feed_metadata (key TEXT PRIMARY KEY, value TEXT NOT NULL)`;
18055
+ yield* sql`CREATE INDEX idx_feed_articles_published ON feed_articles(published_at DESC)`;
18056
+ const now = DateTime.formatIso(yield* DateTime.now);
18057
+ for (const [id, name, kind, feedUrl, siteUrl] of [
18058
+ [
18059
+ "hacker-news",
18060
+ "Hacker News",
18061
+ "hacker_news",
18062
+ "https://hnrss.org/frontpage",
18063
+ "https://news.ycombinator.com"
18064
+ ],
18065
+ [
18066
+ "techcrunch",
18067
+ "TechCrunch",
18068
+ "syndication",
18069
+ "https://techcrunch.com/feed/",
18070
+ "https://techcrunch.com"
18071
+ ],
18072
+ [
18073
+ "the-verge",
18074
+ "The Verge",
18075
+ "syndication",
18076
+ "https://www.theverge.com/rss/index.xml",
18077
+ "https://www.theverge.com"
18078
+ ],
18079
+ [
18080
+ "ars-technica",
18081
+ "Ars Technica",
18082
+ "syndication",
18083
+ "https://feeds.arstechnica.com/arstechnica/index",
18084
+ "https://arstechnica.com"
18085
+ ],
18086
+ [
18087
+ "wired",
18088
+ "Wired",
18089
+ "syndication",
18090
+ "https://www.wired.com/feed/rss",
18091
+ "https://www.wired.com"
18092
+ ]
18093
+ ]) yield* sql`INSERT INTO feed_sources (id, name, kind, feed_url, site_url, enabled, created_at, updated_at)
18094
+ VALUES (${id}, ${name}, ${kind}, ${feedUrl}, ${siteUrl}, 1, ${now}, ${now})`;
18095
+ });
18096
+ //#endregion
17693
18097
  //#region src/hub/Migrations.ts
17694
18098
  /**
17695
18099
  * Hub migrations.
@@ -17740,6 +18144,11 @@ const hubMigrationEntries = [
17740
18144
  8,
17741
18145
  "TaskExternalRefRemoved",
17742
18146
  _008_TaskExternalRefRemoved_default
18147
+ ],
18148
+ [
18149
+ 9,
18150
+ "Feed",
18151
+ _009_Feed_default
17743
18152
  ]
17744
18153
  ];
17745
18154
  const hubMigrationLoader = Migrator.fromRecord(Object.fromEntries(hubMigrationEntries.map(([id, name, migration]) => [`${id}_${name}`, migration])));
@@ -17822,7 +18231,7 @@ const announce = Layer.effectDiscard(Effect.gen(function* () {
17822
18231
  });
17823
18232
  if (isRemoteReachableHost(config.host)) yield* Effect.logWarning("Hub is reachable beyond loopback. The bearer token is the only control — repeated auth failures are not rate limited.", { host: config.host });
17824
18233
  }));
17825
- const makeHubLayer = HttpRouter.serve(layer$69).pipe(Layer.provideMerge(announce), Layer.provideMerge(HubHttpServerLive), Layer.provideMerge(layer$70), Layer.provideMerge(TaskRepositoryLive), Layer.provideMerge(AgentAssetRepositoryLive), Layer.provideMerge(HubPersistenceLive));
18234
+ const makeHubLayer = HttpRouter.serve(layer$70).pipe(Layer.provideMerge(announce), Layer.provideMerge(HubHttpServerLive), Layer.provideMerge(layer$71), Layer.provideMerge(TaskRepositoryLive), Layer.provideMerge(AgentAssetRepositoryLive), Layer.provideMerge(HubPersistenceLive));
17826
18235
  const runHub = Layer.launch(makeHubLayer);
17827
18236
  //#endregion
17828
18237
  //#region src/atomicWrite.ts
@@ -17946,7 +18355,7 @@ function stripDefaultServerSettings(current, defaults) {
17946
18355
  }
17947
18356
  return Object.is(current, defaults) ? void 0 : current;
17948
18357
  }
17949
- const make$78 = Effect.gen(function* () {
18358
+ const make$79 = Effect.gen(function* () {
17950
18359
  const { settingsPath } = yield* ServerConfig$1;
17951
18360
  const fs = yield* FileSystem.FileSystem;
17952
18361
  const pathService = yield* Path.Path;
@@ -18167,7 +18576,7 @@ const make$78 = Effect.gen(function* () {
18167
18576
  }
18168
18577
  };
18169
18578
  });
18170
- const layer$68 = Layer.effect(ServerSettingsService, make$78);
18579
+ const layer$69 = Layer.effect(ServerSettingsService, make$79);
18171
18580
  //#endregion
18172
18581
  //#region src/pathExpansion.ts
18173
18582
  /**
@@ -18541,7 +18950,7 @@ function claudeEntryFromRegistration(registration) {
18541
18950
  };
18542
18951
  }
18543
18952
  var ClaudeMcpFiles = class extends Context.Service()("@p4code/cli/mcp/ClaudeMcpFiles") {};
18544
- const make$77 = Effect.gen(function* () {
18953
+ const make$78 = Effect.gen(function* () {
18545
18954
  const fileSystem = yield* FileSystem.FileSystem;
18546
18955
  const path = yield* Path.Path;
18547
18956
  const services = yield* Effect.context();
@@ -18606,7 +19015,7 @@ const make$77 = Effect.gen(function* () {
18606
19015
  removeProject: (projectDir, name) => removeAt(Effect.succeed(projectFile(projectDir)))(name)
18607
19016
  };
18608
19017
  });
18609
- const layer$67 = Layer.effect(ClaudeMcpFiles, make$77);
19018
+ const layer$68 = Layer.effect(ClaudeMcpFiles, make$78);
18610
19019
  Layer.succeed(ClaudeMcpFiles, {
18611
19020
  readUser: Effect.succeed([]),
18612
19021
  upsertUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
@@ -18742,7 +19151,7 @@ const decodeClientRegistration = Schema$1.decodeUnknownExit(ClientRegistrationRe
18742
19151
  const decodeTokenResponse = Schema$1.decodeUnknownExit(TokenResponse);
18743
19152
  var McpOAuth = class extends Context.Service()("@p4code/cli/mcp/McpOAuth") {};
18744
19153
  const registryError = (detail) => new McpRegistryError({ detail });
18745
- const make$76 = Effect.gen(function* () {
19154
+ const make$77 = Effect.gen(function* () {
18746
19155
  const config = yield* ServerConfig$1;
18747
19156
  const secrets = yield* ServerSecretStore;
18748
19157
  const http = yield* HttpClient.HttpClient;
@@ -19062,7 +19471,7 @@ const make$76 = Effect.gen(function* () {
19062
19471
  accessTokenFor
19063
19472
  };
19064
19473
  });
19065
- const layer$66 = Layer.effect(McpOAuth, make$76);
19474
+ const layer$67 = Layer.effect(McpOAuth, make$77);
19066
19475
  Layer.succeed(McpOAuth, {
19067
19476
  statusFor: () => Effect.succeed(Option.none()),
19068
19477
  begin: () => Effect.fail(new McpRegistryError({ detail: "OAuth sign-in is not available." })),
@@ -19080,7 +19489,7 @@ const decodeRegistration$1 = Schema$1.decodeUnknownExit(RegistrationFromJson$1);
19080
19489
  const encodeRegistration = Schema$1.encodeSync(RegistrationFromJson$1);
19081
19490
  var McpRegistry = class extends Context.Service()("@p4code/cli/mcp/McpRegistry") {};
19082
19491
  const slotsOf = (registration) => registration.secrets ?? [];
19083
- const make$75 = Effect.gen(function* () {
19492
+ const make$76 = Effect.gen(function* () {
19084
19493
  const config = yield* ServerConfig$1;
19085
19494
  const secrets = yield* ServerSecretStore;
19086
19495
  const oauth = yield* McpOAuth;
@@ -19231,7 +19640,7 @@ const make$75 = Effect.gen(function* () {
19231
19640
  }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry resolve failed", { cause }).pipe(Effect.as({}))))
19232
19641
  };
19233
19642
  });
19234
- const layer$65 = Layer.effect(McpRegistry, make$75);
19643
+ const layer$66 = Layer.effect(McpRegistry, make$76);
19235
19644
  //#endregion
19236
19645
  //#region src/sync/skillDirectory.ts
19237
19646
  /**
@@ -19610,7 +20019,7 @@ const formatHubLink = (input) => encodeStoredHubLink({
19610
20019
  shareMode: input.shareMode
19611
20020
  });
19612
20021
  const fromEnvironment = (environment) => validateHubLink(environment.P4CODE_HUB_URL ?? "", environment.P4CODE_HUB_TOKEN ?? "");
19613
- const make$74 = Effect.fn("HubLink.make")(function* (environment) {
20022
+ const make$75 = Effect.fn("HubLink.make")(function* (environment) {
19614
20023
  const secrets = yield* ServerSecretStore;
19615
20024
  const env = environment ?? process.env;
19616
20025
  const fromEnv = fromEnvironment(env);
@@ -19676,7 +20085,7 @@ const make$74 = Effect.fn("HubLink.make")(function* (environment) {
19676
20085
  })
19677
20086
  };
19678
20087
  });
19679
- const layer$64 = Layer.effect(HubLink, make$74());
20088
+ const layer$65 = Layer.effect(HubLink, make$75());
19680
20089
  //#endregion
19681
20090
  //#region src/sync/HubAssetClient.ts
19682
20091
  /**
@@ -19709,7 +20118,7 @@ const decodeAssetListPage = Schema$1.decodeUnknownEffect(AssetListPage);
19709
20118
  const decodeConflictBody$1 = Schema$1.decodeUnknownEffect(ConflictBody$1);
19710
20119
  const decodeAsset = Schema$1.decodeUnknownEffect(AgentAsset);
19711
20120
  var HubAssetClient = class extends Context.Service()("@p4code/cli/sync/HubAssetClient") {};
19712
- const make$73 = Effect.gen(function* () {
20121
+ const make$74 = Effect.gen(function* () {
19713
20122
  const http = yield* HttpClient.HttpClient;
19714
20123
  const link = yield* HubLink;
19715
20124
  const requireSettings = Effect.gen(function* () {
@@ -19791,7 +20200,7 @@ const make$73 = Effect.gen(function* () {
19791
20200
  remove
19792
20201
  };
19793
20202
  });
19794
- const layer$63 = Layer.effect(HubAssetClient, make$73);
20203
+ const layer$64 = Layer.effect(HubAssetClient, make$74);
19795
20204
  //#endregion
19796
20205
  //#region src/sync/mcpRegistrationFiles.ts
19797
20206
  /**
@@ -20366,7 +20775,7 @@ const EMPTY_REPORT = {
20366
20775
  unavailable: null
20367
20776
  };
20368
20777
  var AssetSync = class extends Context.Service()("@p4code/cli/sync/AssetSync") {};
20369
- const make$72 = Effect.gen(function* () {
20778
+ const make$73 = Effect.gen(function* () {
20370
20779
  const client = yield* HubAssetClient;
20371
20780
  const link = yield* HubLink;
20372
20781
  const settingsStore = yield* ServerSettingsService;
@@ -21079,7 +21488,7 @@ const make$72 = Effect.gen(function* () {
21079
21488
  removeLocal
21080
21489
  };
21081
21490
  });
21082
- const layer$62 = Layer.effect(AssetSync, make$72);
21491
+ const layer$63 = Layer.effect(AssetSync, make$73);
21083
21492
  //#endregion
21084
21493
  //#region src/provider/CompressPrompts.ts
21085
21494
  /**
@@ -21430,7 +21839,7 @@ const findAgentPreset = (requested) => {
21430
21839
  };
21431
21840
  //#endregion
21432
21841
  //#region src/cli/assets.ts
21433
- const SyncServicesLive = layer$62.pipe(Layer.provideMerge(layer$63), Layer.provideMerge(layer$64), Layer.provideMerge(layer$68.pipe(Layer.provide(layer$75))), Layer.provideMerge(layer$75), Layer.provideMerge(FetchHttpClient.layer));
21842
+ const SyncServicesLive = layer$63.pipe(Layer.provideMerge(layer$64), Layer.provideMerge(layer$65), Layer.provideMerge(layer$69.pipe(Layer.provide(layer$76))), Layer.provideMerge(layer$76), Layer.provideMerge(FetchHttpClient.layer));
21434
21843
  const runWithSync = (flags, run) => Effect.gen(function* () {
21435
21844
  const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
21436
21845
  return yield* Effect.gen(function* () {
@@ -21438,7 +21847,7 @@ const runWithSync = (flags, run) => Effect.gen(function* () {
21438
21847
  sync: yield* AssetSync,
21439
21848
  link: yield* HubLink
21440
21849
  });
21441
- }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$78(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
21850
+ }).pipe(Effect.provide(SyncServicesLive.pipe(Layer.provide(layer$79(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, "Error")))));
21442
21851
  });
21443
21852
  const STATE_LABEL = {
21444
21853
  synced: "synced",
@@ -27148,12 +27557,12 @@ const runProcessCore = Effect.fn("processRunner.runProcessCore")(function* (spaw
27148
27557
  stderrInvalidUtf8: stderr.invalidUtf8
27149
27558
  };
27150
27559
  });
27151
- const make$71 = Effect.fn("ProcessRunner.make")(function* () {
27560
+ const make$72 = Effect.fn("ProcessRunner.make")(function* () {
27152
27561
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
27153
27562
  const run = (input) => finalizeRunProcess(runProcessCore(spawner, input), input);
27154
27563
  return ProcessRunner.of({ run });
27155
27564
  });
27156
- const layer$61 = Layer.effect(ProcessRunner, make$71());
27565
+ const layer$62 = Layer.effect(ProcessRunner, make$72());
27157
27566
  //#endregion
27158
27567
  //#region src/project/RepositoryIdentityResolver.ts
27159
27568
  const DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY = 512;
@@ -27244,7 +27653,7 @@ const resolveRepositoryIdentityFromCacheKey = Effect.fn("RepositoryIdentityResol
27244
27653
  rootPath: cacheKey
27245
27654
  }) : null;
27246
27655
  });
27247
- const make$70 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
27656
+ const make$71 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
27248
27657
  const processRunner = yield* ProcessRunner;
27249
27658
  const repositoryIdentityCache = yield* Cache.makeWith((cacheKey) => resolveRepositoryIdentityFromCacheKey(cacheKey).pipe(Effect.provideService(ProcessRunner, processRunner)), {
27250
27659
  capacity: options.cacheCapacity ?? DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY,
@@ -27259,7 +27668,7 @@ const make$70 = Effect.fn("RepositoryIdentityResolver.make")(function* (options
27259
27668
  });
27260
27669
  return RepositoryIdentityResolver.of({ resolve });
27261
27670
  });
27262
- const layer$60 = Layer.effect(RepositoryIdentityResolver, make$70()).pipe(Layer.provide(layer$61));
27671
+ const layer$61 = Layer.effect(RepositoryIdentityResolver, make$71()).pipe(Layer.provide(layer$62));
27263
27672
  //#endregion
27264
27673
  //#region src/orchestration/Layers/ProjectionSnapshotQuery.ts
27265
27674
  const decodeReadModel = Schema$1.decodeUnknownEffect(OrchestrationReadModel);
@@ -29301,7 +29710,7 @@ function mergeWithDefaultKeybindings(custom) {
29301
29710
  * Keybindings - Service tag for keybinding configuration operations.
29302
29711
  */
29303
29712
  var Keybindings = class extends Context.Service()("@p4code/cli/keybindings") {};
29304
- const make$69 = Effect.gen(function* () {
29713
+ const make$70 = Effect.gen(function* () {
29305
29714
  const { keybindingsConfigPath } = yield* ServerConfig$1;
29306
29715
  const fs = yield* FileSystem.FileSystem;
29307
29716
  const path = yield* Path.Path;
@@ -29562,7 +29971,7 @@ const make$69 = Effect.gen(function* () {
29562
29971
  }))
29563
29972
  };
29564
29973
  });
29565
- const layer$59 = Layer.effect(Keybindings, make$69);
29974
+ const layer$60 = Layer.effect(Keybindings, make$70);
29566
29975
  //#endregion
29567
29976
  //#region src/process/externalLauncher.ts
29568
29977
  /**
@@ -29789,7 +30198,7 @@ const launchEditorProcess = Effect.fn("externalLauncher.launchEditorProcess")(fu
29789
30198
  cause
29790
30199
  }));
29791
30200
  });
29792
- const make$68 = Effect.gen(function* () {
30201
+ const make$69 = Effect.gen(function* () {
29793
30202
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
29794
30203
  const fileSystem = yield* FileSystem.FileSystem;
29795
30204
  const path = yield* Path.Path;
@@ -29800,7 +30209,7 @@ const make$68 = Effect.gen(function* () {
29800
30209
  launchEditor: (input) => provideCommandResolutionServices(Effect.flatMap(resolveEditorLaunch(input), (launch) => launchEditorProcess(launch).pipe(Effect.provideService(ChildProcessSpawner$1.ChildProcessSpawner, spawner))))
29801
30210
  });
29802
30211
  });
29803
- const layer$58 = Layer.effect(ExternalLauncher, make$68);
30212
+ const layer$59 = Layer.effect(ExternalLauncher, make$69);
29804
30213
  //#endregion
29805
30214
  //#region src/orchestration/Services/OrchestrationReactor.ts
29806
30215
  /**
@@ -29818,7 +30227,7 @@ var OrchestrationReactor = class extends Context.Service()("@p4code/cli/orchestr
29818
30227
  //#endregion
29819
30228
  //#region src/serverLifecycleEvents.ts
29820
30229
  var ServerLifecycleEvents = class extends Context.Service()("@p4code/cli/serverLifecycleEvents") {};
29821
- const make$67 = Effect.gen(function* () {
30230
+ const make$68 = Effect.gen(function* () {
29822
30231
  const pubsub = yield* PubSub.unbounded();
29823
30232
  const state = yield* Ref.make({
29824
30233
  sequence: 0,
@@ -29842,7 +30251,7 @@ const make$67 = Effect.gen(function* () {
29842
30251
  }
29843
30252
  };
29844
30253
  });
29845
- const layer$57 = Layer.effect(ServerLifecycleEvents, make$67);
30254
+ const layer$58 = Layer.effect(ServerLifecycleEvents, make$68);
29846
30255
  //#endregion
29847
30256
  //#region src/telemetry/Identify.ts
29848
30257
  const CodexAuthJsonSchema = Schema$1.Struct({ tokens: Schema$1.Struct({ account_id: Schema$1.String }) });
@@ -30015,7 +30424,7 @@ var AnalyticsService = class AnalyticsService extends Context.Service()("@p4code
30015
30424
  /** No-op layer for callers that intentionally disable telemetry. */
30016
30425
  static layerTest = Layer.succeed(AnalyticsService, inert);
30017
30426
  };
30018
- const make$66 = Effect.gen(function* () {
30427
+ const make$67 = Effect.gen(function* () {
30019
30428
  const telemetryConfig = yield* TelemetryEnvConfig;
30020
30429
  const posthogKey = telemetryConfig.posthogKey.trim();
30021
30430
  if (!telemetryConfig.enabled || posthogKey === "") return inert;
@@ -30085,7 +30494,7 @@ const make$66 = Effect.gen(function* () {
30085
30494
  flush
30086
30495
  });
30087
30496
  });
30088
- const layer$56 = Layer.effect(AnalyticsService, make$66);
30497
+ const layer$57 = Layer.effect(AnalyticsService, make$67);
30089
30498
  AnalyticsService.layerTest;
30090
30499
  //#endregion
30091
30500
  //#region src/service/pinnedRuntime.ts
@@ -30432,7 +30841,7 @@ var BootServiceInstallError = class extends Schema$1.TaggedErrorClass()("BootSer
30432
30841
  }
30433
30842
  };
30434
30843
  var BootService = class extends Context.Service()("@p4code/cli/service/bootService") {};
30435
- const make$65 = Effect.fn("cloud.boot_service.make")(function* (input) {
30844
+ const make$66 = Effect.fn("cloud.boot_service.make")(function* (input) {
30436
30845
  const hostExecPath = yield* HostProcessExecutablePath;
30437
30846
  const hostArguments = yield* HostProcessArguments;
30438
30847
  const host = input.host ?? {
@@ -30654,7 +31063,7 @@ const make$65 = Effect.fn("cloud.boot_service.make")(function* (input) {
30654
31063
  logPath
30655
31064
  });
30656
31065
  });
30657
- const layer$55 = (input) => Layer.effect(BootService, make$65(input));
31066
+ const layer$56 = (input) => Layer.effect(BootService, make$66(input));
30658
31067
  //#endregion
30659
31068
  //#region src/service/selfUpdate.ts
30660
31069
  /**
@@ -30729,7 +31138,7 @@ const resolveServerSelfUpdateCapability = Effect.fn("cloud.server_self_update.re
30729
31138
  return null;
30730
31139
  });
30731
31140
  var ServerSelfUpdate = class extends Context.Service()("@p4code/cli/service/selfUpdate/ServerSelfUpdate") {};
30732
- const make$64 = Effect.fn("cloud.server_self_update.make")(function* (options) {
31141
+ const make$65 = Effect.fn("cloud.server_self_update.make")(function* (options) {
30733
31142
  const serverConfig = yield* ServerConfig$1;
30734
31143
  const fs = yield* FileSystem.FileSystem;
30735
31144
  const path = yield* Path.Path;
@@ -30879,7 +31288,7 @@ const make$64 = Effect.fn("cloud.server_self_update.make")(function* (options) {
30879
31288
  });
30880
31289
  return ServerSelfUpdate.of({ update });
30881
31290
  });
30882
- const layer$54 = Layer.effect(ServerSelfUpdate, make$64()).pipe(Layer.provide(layer$61));
31291
+ const layer$55 = Layer.effect(ServerSelfUpdate, make$65()).pipe(Layer.provide(layer$62));
30883
31292
  //#endregion
30884
31293
  //#region src/environment/ServerEnvironmentLabel.ts
30885
31294
  const ServerEnvironmentLabelCommandProbe = Schema$1.Literals(["macos-computer-name", "linux-pretty-hostname"]);
@@ -31011,7 +31420,7 @@ function platformArch(architecture) {
31011
31420
  default: return "other";
31012
31421
  }
31013
31422
  }
31014
- const make$63 = Effect.gen(function* () {
31423
+ const make$64 = Effect.gen(function* () {
31015
31424
  const fileSystem = yield* FileSystem.FileSystem;
31016
31425
  const path = yield* Path.Path;
31017
31426
  const serverConfig = yield* ServerConfig$1;
@@ -31075,7 +31484,7 @@ const make$63 = Effect.gen(function* () {
31075
31484
  * state. It intentionally has no fallback Layer.succeed value: callers must
31076
31485
  * provide the external platform services and a ServerConfig.
31077
31486
  */
31078
- const layer$53 = Layer.effect(ServerEnvironment, make$63).pipe(Layer.provide(layer$61));
31487
+ const layer$54 = Layer.effect(ServerEnvironment, make$64).pipe(Layer.provide(layer$62));
31079
31488
  //#endregion
31080
31489
  //#region src/provider/Services/ProviderSessionReaper.ts
31081
31490
  var ProviderSessionReaper = class extends Context.Service()("@p4code/cli/provider/Services/ProviderSessionReaper") {};
@@ -32153,7 +32562,7 @@ const maybeOpenBrowser = (target) => Effect.gen(function* () {
32153
32562
  yield* (yield* ExternalLauncher).launchBrowser(target).pipe(Effect.catch(() => Effect.logInfo("browser auto-open unavailable", { hint: `Open ${target} in your browser.` })));
32154
32563
  });
32155
32564
  const runStartupPhase = (phase, effect) => effect.pipe(Effect.annotateSpans({ "startup.phase": phase }), Effect.withSpan(`server.startup.${phase}`));
32156
- const make$62 = Effect.gen(function* () {
32565
+ const make$63 = Effect.gen(function* () {
32157
32566
  const serverConfig = yield* ServerConfig$1;
32158
32567
  const keybindings = yield* Keybindings;
32159
32568
  const orchestrationReactor = yield* OrchestrationReactor;
@@ -32294,7 +32703,7 @@ const make$62 = Effect.gen(function* () {
32294
32703
  enqueueCommand: commandGate.enqueueCommand
32295
32704
  };
32296
32705
  });
32297
- const layer$52 = Layer.effect(ServerRuntimeStartup, make$62);
32706
+ const layer$53 = Layer.effect(ServerRuntimeStartup, make$63);
32298
32707
  //#endregion
32299
32708
  //#region src/serverRuntimeState.ts
32300
32709
  const PersistedServerRuntimeState = Schema$1.Struct({
@@ -32451,7 +32860,7 @@ function expandHomePath$2(input, path) {
32451
32860
  if (input.startsWith("~/") || input.startsWith("~\\")) return path.join(NodeOS.homedir(), input.slice(2));
32452
32861
  return input;
32453
32862
  }
32454
- const make$61 = Effect.gen(function* () {
32863
+ const make$62 = Effect.gen(function* () {
32455
32864
  const fileSystem = yield* FileSystem.FileSystem;
32456
32865
  const path = yield* Path.Path;
32457
32866
  const statWorkspaceRoot = Effect.fn("WorkspacePaths.statWorkspaceRoot")(function* (workspaceRoot, normalizedWorkspaceRoot, phase) {
@@ -32508,7 +32917,7 @@ const make$61 = Effect.gen(function* () {
32508
32917
  resolveRelativePathWithinRoot
32509
32918
  });
32510
32919
  });
32511
- const layer$51 = Layer.effect(WorkspacePaths, make$61);
32920
+ const layer$52 = Layer.effect(WorkspacePaths, make$62);
32512
32921
  //#endregion
32513
32922
  //#region src/cli/project.ts
32514
32923
  const isEnvironmentHttpCommonError = Schema$1.is(EnvironmentHttpCommonError);
@@ -32614,7 +33023,7 @@ const projectCommandUuid = Crypto.Crypto.pipe(Effect.flatMap((crypto) => crypto.
32614
33023
  operation: "generateProjectCommandId",
32615
33024
  cause
32616
33025
  })));
32617
- const ProjectCliRuntimeLive = Layer.mergeAll(layer$51, OrchestrationLayerLive.pipe(Layer.provideMerge(layer$60), Layer.provideMerge(layerConfig)));
33026
+ const ProjectCliRuntimeLive = Layer.mergeAll(layer$52, OrchestrationLayerLive.pipe(Layer.provideMerge(layer$61), Layer.provideMerge(layerConfig)));
32618
33027
  const PROJECT_CLI_LIVE_SERVER_TIMEOUT = Duration.seconds(1);
32619
33028
  const withProjectCliSessionToken = (environmentAuth, run) => Effect.acquireUseRelease(environmentAuth.issueSession({
32620
33029
  scopes: AuthAdministrativeScopes,
@@ -32705,7 +33114,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
32705
33114
  });
32706
33115
  yield* Console.log(output);
32707
33116
  }));
32708
- const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$78(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
33117
+ const offlineRuntimeLayer = ProjectCliRuntimeLive.pipe(Layer.provide(layer$79(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)));
32709
33118
  return yield* Effect.gen(function* () {
32710
33119
  const snapshot = yield* getOfflineSnapshot();
32711
33120
  const orchestrationEngine = yield* OrchestrationEngineService;
@@ -32716,7 +33125,7 @@ const runProjectMutation = Effect.fn("runProjectMutation")(function* (flags, run
32716
33125
  });
32717
33126
  yield* Console.log(output);
32718
33127
  }).pipe(Effect.provide(offlineRuntimeLayer));
32719
- }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$51).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$78(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
33128
+ }).pipe(Effect.provide(Layer.mergeAll(runtimeLayer, layer$52).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provide(layer$79(config)), Layer.provide(Layer.succeed(References.MinimumLogLevel, minimumLogLevel)))));
32720
33129
  });
32721
33130
  const projectAddCommand = Command.make("add", {
32722
33131
  ...projectLocationFlags,
@@ -33691,7 +34100,7 @@ const logP4ProjectFileLoadError = (error) => Effect.logWarning(error).pipe(Effec
33691
34100
  filePath: error.filePath,
33692
34101
  errorTag: error._tag
33693
34102
  }));
33694
- const make$60 = Effect.gen(function* () {
34103
+ const make$61 = Effect.gen(function* () {
33695
34104
  const fileSystem = yield* FileSystem.FileSystem;
33696
34105
  const path = yield* Path.Path;
33697
34106
  const load = Effect.fn("P4ProjectFileLoader.load")(function* (workspaceRoot) {
@@ -33712,7 +34121,7 @@ const make$60 = Effect.gen(function* () {
33712
34121
  });
33713
34122
  return P4ProjectFileLoader.of({ load });
33714
34123
  });
33715
- const layer$50 = Layer.effect(P4ProjectFileLoader, make$60);
34124
+ const layer$51 = Layer.effect(P4ProjectFileLoader, make$61);
33716
34125
  //#endregion
33717
34126
  //#region src/project/ProjectFaviconResolver.ts
33718
34127
  /**
@@ -33787,7 +34196,7 @@ function extractIconHref(source) {
33787
34196
  return null;
33788
34197
  }
33789
34198
  const optionOnNotFound$1 = (effect) => effect.pipe(Effect.map(Option.some), Effect.catchTags({ PlatformError: (error) => error.reason._tag === "NotFound" ? Effect.succeed(Option.none()) : Effect.fail(error) }));
33790
- const make$59 = Effect.gen(function* () {
34199
+ const make$60 = Effect.gen(function* () {
33791
34200
  const fileSystem = yield* FileSystem.FileSystem;
33792
34201
  const path = yield* Path.Path;
33793
34202
  const workspacePaths = yield* WorkspacePaths;
@@ -33856,7 +34265,7 @@ const make$59 = Effect.gen(function* () {
33856
34265
  });
33857
34266
  return ProjectFaviconResolver.of({ resolvePath });
33858
34267
  });
33859
- const layer$49 = Layer.effect(ProjectFaviconResolver, make$59);
34268
+ const layer$50 = Layer.effect(ProjectFaviconResolver, make$60);
33860
34269
  //#endregion
33861
34270
  //#region src/assets/AssetAccess.ts
33862
34271
  const ASSET_ROUTE_PREFIX = "/api/assets";
@@ -34267,10 +34676,10 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
34267
34676
  //#endregion
34268
34677
  //#region src/observability/BrowserTraceCollector.ts
34269
34678
  var BrowserTraceCollector = class extends Context.Service()("@p4code/cli/observability/BrowserTraceCollector") {};
34270
- const make$58 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
34679
+ const make$59 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
34271
34680
  for (const record of records) sink.push(record);
34272
34681
  }) });
34273
- const layer$48 = (sink) => Layer.succeed(BrowserTraceCollector, make$58(sink));
34682
+ const layer$49 = (sink) => Layer.succeed(BrowserTraceCollector, make$59(sink));
34274
34683
  //#endregion
34275
34684
  //#region src/auth/http.ts
34276
34685
  const CREDENTIAL_RESPONSE_HEADERS = {
@@ -37323,7 +37732,7 @@ const classifyNonZeroExit = (command, stderr) => {
37323
37732
  if (command === "gh" && (normalized.includes("could not resolve to a pullrequest") || normalized.includes("repository.pullrequest") || normalized.includes("no pull requests found for branch") || normalized.includes("pull request not found")) || command === "glab" && (normalized.includes("merge request not found") || normalized.includes("not found") || normalized.includes("404")) || command === "az" && normalized.includes("pull request") && (normalized.includes("not found") || normalized.includes("does not exist"))) return "not-found";
37324
37733
  return "command-failed";
37325
37734
  };
37326
- const make$57 = Effect.gen(function* () {
37735
+ const make$58 = Effect.gen(function* () {
37327
37736
  const processRunner = yield* ProcessRunner;
37328
37737
  const run = Effect.fn("VcsProcess.run")(function* (input) {
37329
37738
  const baseError = {
@@ -37382,7 +37791,7 @@ const make$57 = Effect.gen(function* () {
37382
37791
  });
37383
37792
  return VcsProcess.of({ run });
37384
37793
  });
37385
- const layer$47 = Layer.effect(VcsProcess, make$57).pipe(Layer.provide(layer$61));
37794
+ const layer$48 = Layer.effect(VcsProcess, make$58).pipe(Layer.provide(layer$62));
37386
37795
  //#endregion
37387
37796
  //#region src/vcs/VcsDriver.ts
37388
37797
  var VcsDriver = class extends Context.Service()("@p4code/cli/vcs/VcsDriver") {};
@@ -37833,12 +38242,12 @@ const makeVcsDriver = Effect.gen(function* () {
37833
38242
  const driver = yield* makeVcsDriverShape();
37834
38243
  return VcsDriver.of(driver);
37835
38244
  });
37836
- const make$56 = Effect.gen(function* () {
38245
+ const make$57 = Effect.gen(function* () {
37837
38246
  const git = yield* makeGitVcsDriverCore();
37838
38247
  return GitVcsDriver.of(git);
37839
38248
  });
37840
38249
  Layer.effect(VcsDriver, makeVcsDriver);
37841
- const layer$46 = Layer.effect(GitVcsDriver, make$56);
38250
+ const layer$47 = Layer.effect(GitVcsDriver, make$57);
37842
38251
  //#endregion
37843
38252
  //#region src/vcs/VcsProjectConfig.ts
37844
38253
  const ProjectVcsConfigJson = fromLenientJson(Schema$1.Struct({
@@ -37870,7 +38279,7 @@ const logVcsProjectConfigError = (error) => Effect.logWarning(error).pipe(Effect
37870
38279
  configPath: error.configPath,
37871
38280
  errorTag: error._tag
37872
38281
  }));
37873
- const make$55 = Effect.gen(function* () {
38282
+ const make$56 = Effect.gen(function* () {
37874
38283
  const fileSystem = yield* FileSystem.FileSystem;
37875
38284
  const path = yield* Path.Path;
37876
38285
  const findConfigPath = Effect.fn("VcsProjectConfig.findConfigPath")(function* (cwd) {
@@ -37911,7 +38320,7 @@ const make$55 = Effect.gen(function* () {
37911
38320
  });
37912
38321
  return VcsProjectConfig.of({ resolveKind });
37913
38322
  });
37914
- const layer$45 = Layer.effect(VcsProjectConfig, make$55);
38323
+ const layer$46 = Layer.effect(VcsProjectConfig, make$56);
37915
38324
  //#endregion
37916
38325
  //#region src/vcs/VcsDriverRegistry.ts
37917
38326
  const DETECTION_CACHE_CAPACITY = 2048;
@@ -37931,7 +38340,7 @@ function parseDetectionCacheKey(key) {
37931
38340
  cwd: key.slice(separatorIndex + 1)
37932
38341
  };
37933
38342
  }
37934
- const make$54 = Effect.gen(function* () {
38343
+ const make$55 = Effect.gen(function* () {
37935
38344
  const projectConfig = yield* VcsProjectConfig;
37936
38345
  const git = yield* makeVcsDriver;
37937
38346
  const drivers = { git };
@@ -37988,7 +38397,7 @@ const make$54 = Effect.gen(function* () {
37988
38397
  resolve
37989
38398
  });
37990
38399
  });
37991
- const layer$44 = Layer.effect(VcsDriverRegistry, make$54).pipe(Layer.provide(layer$45));
38400
+ const layer$45 = Layer.effect(VcsDriverRegistry, make$55).pipe(Layer.provide(layer$46));
37992
38401
  //#endregion
37993
38402
  //#region src/checkpointing/CheckpointStore.ts
37994
38403
  /**
@@ -38008,7 +38417,7 @@ const layer$44 = Layer.effect(VcsDriverRegistry, make$54).pipe(Layer.provide(lay
38008
38417
  */
38009
38418
  /** Service tag for checkpoint persistence and restore operations. */
38010
38419
  var CheckpointStore = class extends Context.Service()("@p4code/cli/checkpointing/CheckpointStore") {};
38011
- const make$53 = Effect.gen(function* () {
38420
+ const make$54 = Effect.gen(function* () {
38012
38421
  const vcsRegistry = yield* VcsDriverRegistry;
38013
38422
  const resolveCheckpoints = Effect.fn("CheckpointStore.resolveCheckpoints")(function* (operation, cwd) {
38014
38423
  const handle = yield* vcsRegistry.resolve({ cwd });
@@ -38047,7 +38456,7 @@ const make$53 = Effect.gen(function* () {
38047
38456
  deleteCheckpointRefs
38048
38457
  });
38049
38458
  });
38050
- const layer$43 = Layer.effect(CheckpointStore, make$53);
38459
+ const layer$44 = Layer.effect(CheckpointStore, make$54);
38051
38460
  //#endregion
38052
38461
  //#region src/checkpointing/CheckpointDiffQuery.ts
38053
38462
  /**
@@ -38069,7 +38478,7 @@ function buildTurnDiffResult(input, diff) {
38069
38478
  diff
38070
38479
  };
38071
38480
  }
38072
- const make$52 = Effect.gen(function* () {
38481
+ const make$53 = Effect.gen(function* () {
38073
38482
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
38074
38483
  const checkpointStore = yield* CheckpointStore;
38075
38484
  const threadActivities = yield* ProjectionThreadActivityRepository;
@@ -38240,7 +38649,7 @@ const make$52 = Effect.gen(function* () {
38240
38649
  getFullThreadDiff
38241
38650
  });
38242
38651
  });
38243
- const layer$42 = Layer.effect(CheckpointDiffQuery, make$52);
38652
+ const layer$43 = Layer.effect(CheckpointDiffQuery, make$53);
38244
38653
  //#endregion
38245
38654
  //#region ../../packages/shared/src/toolCategory.ts
38246
38655
  const TOOL_CATEGORY_TITLES = {
@@ -41254,7 +41663,7 @@ function makeUpdateState(input) {
41254
41663
  output: input.output ?? null
41255
41664
  };
41256
41665
  }
41257
- const make$51 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
41666
+ const make$52 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
41258
41667
  const providerRegistry = yield* ProviderRegistry;
41259
41668
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
41260
41669
  const httpClient = yield* HttpClient.HttpClient;
@@ -41369,7 +41778,7 @@ const make$51 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
41369
41778
  });
41370
41779
  return ProviderMaintenanceRunner.of({ updateProvider });
41371
41780
  });
41372
- const layer$41 = Layer.effect(ProviderMaintenanceRunner, make$51());
41781
+ const layer$42 = Layer.effect(ProviderMaintenanceRunner, make$52());
41373
41782
  //#endregion
41374
41783
  //#region src/provider/Services/ProviderInstanceRegistry.ts
41375
41784
  var ProviderInstanceRegistry = class extends Context.Service()("@p4code/cli/provider/Services/ProviderInstanceRegistry") {};
@@ -41393,11 +41802,11 @@ const makeTextGenerationFromRegistry = (registry) => TextGeneration.of({
41393
41802
  detail: "This provider does not report account usage."
41394
41803
  }))))
41395
41804
  });
41396
- const make$50 = Effect.gen(function* () {
41805
+ const make$51 = Effect.gen(function* () {
41397
41806
  const registry = yield* ProviderInstanceRegistry;
41398
41807
  return makeTextGenerationFromRegistry(registry);
41399
41808
  });
41400
- const layer$40 = Layer.effect(TextGeneration, make$50);
41809
+ const layer$41 = Layer.effect(TextGeneration, make$51);
41401
41810
  //#endregion
41402
41811
  //#region src/provider/Drivers/ClaudeHome.ts
41403
41812
  const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function* (config) {
@@ -42389,7 +42798,7 @@ Layer.succeed(UsageService, UsageService.of({ readSummary: (input) => Effect.suc
42389
42798
  },
42390
42799
  scanDurationMs: 0
42391
42800
  }) }));
42392
- const make$49 = Effect.gen(function* () {
42801
+ const make$50 = Effect.gen(function* () {
42393
42802
  const fileSystem = yield* FileSystem.FileSystem;
42394
42803
  const path = yield* Path.Path;
42395
42804
  const config = yield* ServerConfig$1;
@@ -42621,7 +43030,302 @@ const make$49 = Effect.gen(function* () {
42621
43030
  };
42622
43031
  }) };
42623
43032
  });
42624
- const layer$39 = Layer.effect(UsageService, make$49);
43033
+ const layer$40 = Layer.effect(UsageService, make$50);
43034
+ //#endregion
43035
+ //#region src/feed/ArticleText.ts
43036
+ const BLOCK_TAGS = /<\/?(?:p|div|article|section|main|h[1-6]|li|br)[^>]*>/gi;
43037
+ function extractReadableArticleText(html) {
43038
+ const text = html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, " ").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, " ").replace(BLOCK_TAGS, "\n").replace(/<[^>]+>/g, " ").replaceAll("&nbsp;", " ").replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replace(/[ \t]+/g, " ").replace(/\n\s*\n+/g, "\n").trim();
43039
+ return text.length >= 160 ? text : null;
43040
+ }
43041
+ function hackerNewsEngagementBand(points, comments) {
43042
+ if (points >= 300 || comments >= 100) return "high";
43043
+ if (points >= 100 || comments >= 40) return "medium";
43044
+ return "low";
43045
+ }
43046
+ function hackerNewsDiscussionUrl(id) {
43047
+ return `https://news.ycombinator.com/item?id=${encodeURIComponent(id)}`;
43048
+ }
43049
+ function hackerNewsItemId(discussionUrl) {
43050
+ if (discussionUrl === null) return null;
43051
+ try {
43052
+ return new URL(discussionUrl).searchParams.get("id");
43053
+ } catch {
43054
+ return null;
43055
+ }
43056
+ }
43057
+ //#endregion
43058
+ //#region src/feed/SyndicationSource.ts
43059
+ const decodeEntities = (value) => value.replaceAll("<![CDATA[", "").replaceAll("]]>", "").replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"").replaceAll("&#39;", "'").trim();
43060
+ const tag = (xml, names) => {
43061
+ for (const name of names) {
43062
+ const match = xml.match(new RegExp(`<${name}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${name}>`, "i"));
43063
+ if (match?.[1]) return decodeEntities(match[1]);
43064
+ }
43065
+ return null;
43066
+ };
43067
+ function canonicalizeArticleUrl(value) {
43068
+ const url = new URL(value);
43069
+ url.hash = "";
43070
+ for (const key of [...url.searchParams.keys()]) if (key.startsWith("utm_") || key === "ref" || key === "source") url.searchParams.delete(key);
43071
+ url.searchParams.sort();
43072
+ return url.toString();
43073
+ }
43074
+ function parseSyndicationFeed(xml) {
43075
+ return (xml.match(/<(?:item|entry)(?:\s[^>]*)?>[\s\S]*?<\/(?:item|entry)>/gi) ?? []).flatMap((block) => {
43076
+ const atomLink = block.match(/<link\b[^>]*href=["']([^"']+)["'][^>]*>/i)?.[1] ?? null;
43077
+ const rawUrl = tag(block, [
43078
+ "link",
43079
+ "guid",
43080
+ "id"
43081
+ ]);
43082
+ const title = tag(block, ["title"]);
43083
+ const url = atomLink ?? rawUrl;
43084
+ if (!title || !url) return [];
43085
+ let canonicalUrl;
43086
+ try {
43087
+ canonicalUrl = canonicalizeArticleUrl(url);
43088
+ } catch {
43089
+ return [];
43090
+ }
43091
+ const date = tag(block, [
43092
+ "pubDate",
43093
+ "published",
43094
+ "updated"
43095
+ ]);
43096
+ const parsedDate = date === null ? NaN : Date.parse(date);
43097
+ return [{
43098
+ title,
43099
+ url: canonicalUrl,
43100
+ author: tag(block, [
43101
+ "dc:creator",
43102
+ "author",
43103
+ "name"
43104
+ ]),
43105
+ publishedAt: Number.isNaN(parsedDate) ? (/* @__PURE__ */ new Date(0)).toISOString() : new Date(parsedDate).toISOString(),
43106
+ content: tag(block, [
43107
+ "content:encoded",
43108
+ "content",
43109
+ "description",
43110
+ "summary"
43111
+ ]),
43112
+ discussionUrl: tag(block, ["comments"])
43113
+ }];
43114
+ });
43115
+ }
43116
+ //#endregion
43117
+ //#region src/feed/FeedService.ts
43118
+ const FEED_REQUEST_TIMEOUT_MS = 2e4;
43119
+ const FEED_REFRESH_LEASE_MS = 5 * 6e4;
43120
+ const FEED_FETCH_CONCURRENCY = 4;
43121
+ const FEED_MODEL = "gpt-5.6-luna";
43122
+ const FEED_FALLBACK_MODEL = "claude-sonnet-5";
43123
+ const fail = (code, message) => new FeedError({
43124
+ code,
43125
+ message
43126
+ });
43127
+ const jsonRequest = Effect.fn("FeedService.jsonRequest")(function* (url, token, init) {
43128
+ const response = yield* Effect.tryPromise({
43129
+ try: (signal) => fetch(url, {
43130
+ ...init,
43131
+ signal,
43132
+ headers: {
43133
+ authorization: `Bearer ${token}`,
43134
+ accept: "application/json",
43135
+ "content-type": "application/json",
43136
+ ...init?.headers
43137
+ }
43138
+ }),
43139
+ catch: () => fail("hub_unavailable", "Hub is unavailable.")
43140
+ }).pipe(Effect.timeout(FEED_REQUEST_TIMEOUT_MS), Effect.mapError(() => fail("hub_unavailable", "Hub request timed out.")));
43141
+ if (!response.ok) return yield* fail("hub_unavailable", `Hub returned status ${response.status}.`);
43142
+ if (response.status === 204) return {};
43143
+ return yield* Effect.tryPromise({
43144
+ try: () => response.json(),
43145
+ catch: () => fail("hub_unavailable", "Hub returned invalid JSON.")
43146
+ });
43147
+ });
43148
+ const make$49 = Effect.gen(function* () {
43149
+ const hubLink = yield* HubLink;
43150
+ const providers = yield* ProviderInstanceRegistry;
43151
+ const settings = Effect.fn("FeedService.settings")(function* () {
43152
+ const state = yield* hubLink.current;
43153
+ if (Option.isNone(state.settings)) return yield* fail("hub_unavailable", "Connect this environment to Hub to use Feed.");
43154
+ return state.settings.value;
43155
+ });
43156
+ const call = Effect.fn("FeedService.call")(function* (path, init) {
43157
+ const linked = yield* settings();
43158
+ return yield* jsonRequest(`${linked.baseUrl}${path}`, linked.token, init);
43159
+ });
43160
+ const sources = () => call("/feed/sources");
43161
+ return {
43162
+ list: Effect.fn("FeedService.list")(function* (input) {
43163
+ const result = yield* call("/feed/articles");
43164
+ const query = input.query?.trim().toLocaleLowerCase();
43165
+ const articles = result.articles.filter((article) => input.sourceId === void 0 || article.sourceId === input.sourceId).filter((article) => !input.unreadOnly || article.readAt === null).filter((article) => input.startDate === void 0 || article.publishedAt >= input.startDate).filter((article) => input.endDate === void 0 || article.publishedAt <= input.endDate).filter((article) => !query || `${article.title}\n${article.summary?.summary ?? ""}\n${article.summary?.highlights.join(" ") ?? ""}`.toLocaleLowerCase().includes(query)).toSorted((a, b) => input.sort === "oldest" ? a.publishedAt.localeCompare(b.publishedAt) : b.publishedAt.localeCompare(a.publishedAt));
43166
+ return {
43167
+ ...result,
43168
+ articles
43169
+ };
43170
+ }),
43171
+ refresh: Effect.fn("FeedService.refresh")(function* () {
43172
+ const owner = crypto.randomUUID();
43173
+ const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
43174
+ if (!(yield* call("/feed/lease", {
43175
+ method: "POST",
43176
+ body: JSON.stringify({
43177
+ owner,
43178
+ expiresAt: new Date(Date.now() + FEED_REFRESH_LEASE_MS).toISOString()
43179
+ })
43180
+ })).acquired) return {
43181
+ fetched: 0,
43182
+ summarized: 0,
43183
+ failedSources: [],
43184
+ refreshedAt
43185
+ };
43186
+ const existing = yield* call("/feed/articles");
43187
+ const existingByUrl = new Map(existing.articles.map((article) => [article.canonicalUrl, article]));
43188
+ const enabled = (yield* sources()).filter((source) => source.enabled);
43189
+ let fetched = 0;
43190
+ let summarized = 0;
43191
+ const failedSources = [];
43192
+ yield* Effect.forEach(enabled, (source) => Effect.gen(function* () {
43193
+ const entries = parseSyndicationFeed(yield* Effect.tryPromise({
43194
+ try: () => fetch(source.feedUrl).then((response) => {
43195
+ if (!response.ok) throw new Error(String(response.status));
43196
+ return response.text();
43197
+ }),
43198
+ catch: () => fail("fetch_failed", `Could not fetch ${source.name}.`)
43199
+ }));
43200
+ for (const entry of entries) {
43201
+ const current = existingByUrl.get(entry.url);
43202
+ let contentText = entry.content ? extractReadableArticleText(entry.content) : null;
43203
+ if (contentText === null) contentText = yield* Effect.tryPromise({
43204
+ try: () => fetch(entry.url).then((response) => response.ok ? response.text() : "").then(extractReadableArticleText),
43205
+ catch: () => null
43206
+ });
43207
+ const revision = contentText ?? `${entry.title}:${entry.publishedAt}`;
43208
+ if (current?.contentText === contentText && current.summary !== null) continue;
43209
+ const id = current?.id ?? FeedArticleId.make(crypto.randomUUID());
43210
+ const hnId = source.kind === "hacker_news" ? hackerNewsItemId(entry.discussionUrl) : null;
43211
+ const hnEngagement = hnId === null ? null : yield* Effect.tryPromise({
43212
+ try: () => fetch(`https://hacker-news.firebaseio.com/v0/item/${encodeURIComponent(hnId)}.json`).then((response) => response.ok ? response.json() : null),
43213
+ catch: () => null
43214
+ });
43215
+ let summary = null;
43216
+ let status = "summary_unavailable";
43217
+ if (contentText !== null) {
43218
+ const instances = yield* providers.listInstances;
43219
+ const candidates = [{
43220
+ instance: instances.find((instance) => instance.driverKind === "codex" && instance.enabled),
43221
+ model: FEED_MODEL
43222
+ }, {
43223
+ instance: instances.find((instance) => instance.driverKind === "claudeAgent" && instance.enabled),
43224
+ model: FEED_FALLBACK_MODEL
43225
+ }];
43226
+ for (const candidate of candidates) {
43227
+ if (!candidate.instance) continue;
43228
+ const generated = yield* candidate.instance.textGeneration.generatePrContent({
43229
+ cwd: process.cwd(),
43230
+ baseBranch: "feed",
43231
+ headBranch: "article",
43232
+ commitSummary: entry.title,
43233
+ diffSummary: "Summarize this article for a dense technology news feed. Return concise summary in body.",
43234
+ diffPatch: contentText.slice(0, 24e3),
43235
+ modelSelection: {
43236
+ instanceId: ProviderInstanceId.make(candidate.instance.instanceId),
43237
+ model: candidate.model
43238
+ }
43239
+ }).pipe(Effect.option);
43240
+ if (Option.isNone(generated)) continue;
43241
+ const body = generated.value.body.trim();
43242
+ summary = {
43243
+ modelSelection: `${candidate.instance.instanceId}:${candidate.model}`,
43244
+ summary: body,
43245
+ highlights: body.split(/(?<=[.!?])\s+/).filter(Boolean).slice(0, 3),
43246
+ references: [entry.url],
43247
+ summarizedAt: refreshedAt
43248
+ };
43249
+ status = "ready";
43250
+ summarized += 1;
43251
+ break;
43252
+ }
43253
+ if (summary === null) status = "summary_failed";
43254
+ }
43255
+ yield* call(`/feed/articles/${encodeURIComponent(id)}`, {
43256
+ method: "PUT",
43257
+ body: JSON.stringify({
43258
+ sourceId: source.id,
43259
+ canonicalUrl: entry.url,
43260
+ discussionUrl: hnId ? hackerNewsDiscussionUrl(hnId) : null,
43261
+ title: entry.title,
43262
+ author: entry.author,
43263
+ publishedAt: entry.publishedAt,
43264
+ fetchedAt: refreshedAt,
43265
+ contentText,
43266
+ status,
43267
+ contentRevision: revision,
43268
+ summary,
43269
+ engagement: hnEngagement === null ? {
43270
+ points: null,
43271
+ comments: null,
43272
+ band: "unknown",
43273
+ observedAt: refreshedAt
43274
+ } : {
43275
+ points: hnEngagement.score ?? 0,
43276
+ comments: hnEngagement.descendants ?? 0,
43277
+ band: hackerNewsEngagementBand(hnEngagement.score ?? 0, hnEngagement.descendants ?? 0),
43278
+ observedAt: refreshedAt
43279
+ }
43280
+ })
43281
+ });
43282
+ fetched += 1;
43283
+ }
43284
+ }).pipe(Effect.catch(() => Effect.sync(() => {
43285
+ failedSources.push(source.name);
43286
+ }))), { concurrency: FEED_FETCH_CONCURRENCY });
43287
+ yield* call("/feed/refreshed-at", {
43288
+ method: "PUT",
43289
+ body: JSON.stringify({ refreshedAt })
43290
+ });
43291
+ yield* call("/feed/lease", {
43292
+ method: "DELETE",
43293
+ body: JSON.stringify({ owner })
43294
+ });
43295
+ return {
43296
+ fetched,
43297
+ summarized,
43298
+ failedSources,
43299
+ refreshedAt
43300
+ };
43301
+ }),
43302
+ sources,
43303
+ upsertSource: (input) => call("/feed/sources", {
43304
+ method: "PUT",
43305
+ body: JSON.stringify(input)
43306
+ }),
43307
+ deleteSource: (input) => call(`/feed/sources/${encodeURIComponent(input.sourceId)}`, { method: "DELETE" }),
43308
+ markRead: (input) => call("/feed/read", {
43309
+ method: "PUT",
43310
+ body: JSON.stringify(input)
43311
+ }),
43312
+ cleanup: (input) => call("/feed/cleanup", {
43313
+ method: "POST",
43314
+ body: JSON.stringify(input)
43315
+ })
43316
+ };
43317
+ });
43318
+ const unavailable = () => Effect.fail(fail("hub_unavailable", "Feed service is unavailable."));
43319
+ var FeedService = class extends Context.Reference("@p4code/cli/feed/FeedService", { defaultValue: () => ({
43320
+ list: unavailable,
43321
+ refresh: unavailable,
43322
+ sources: unavailable,
43323
+ upsertSource: unavailable,
43324
+ deleteSource: unavailable,
43325
+ markRead: unavailable,
43326
+ cleanup: unavailable
43327
+ }) }) {};
43328
+ const layer$39 = Layer.effect(FeedService, make$49);
42625
43329
  const SKILL_MANIFEST_FILENAME = "SKILL.md";
42626
43330
  /**
42627
43331
  * Split a catalogue id (`owner/repo/skill-name`) into its parts.
@@ -44928,7 +45632,7 @@ const makeWithOptions$1 = Effect.fn("TerminalManager.makeWithOptions")(function*
44928
45632
  subscribeMetadata
44929
45633
  });
44930
45634
  });
44931
- const layer$36 = Layer.effect(TerminalManager, make$46()).pipe(Layer.provide(layer$61));
45635
+ const layer$36 = Layer.effect(TerminalManager, make$46()).pipe(Layer.provide(layer$62));
44932
45636
  //#endregion
44933
45637
  //#region src/mcp/McpInvocationContext.ts
44934
45638
  var McpInvocationContext = class extends Context.Service()("@p4code/cli/mcp/McpInvocationContext") {};
@@ -59618,6 +60322,13 @@ const RPC_REQUIRED_SCOPE = /* @__PURE__ */ new Map([
59618
60322
  [WS_METHODS.tasksUpdate, AuthOrchestrationOperateScope],
59619
60323
  [WS_METHODS.tasksDelete, AuthOrchestrationOperateScope],
59620
60324
  [WS_METHODS.tasksStartThread, AuthOrchestrationOperateScope],
60325
+ [WS_METHODS.feedList, AuthOrchestrationReadScope],
60326
+ [WS_METHODS.feedRefresh, AuthOrchestrationReadScope],
60327
+ [WS_METHODS.feedSourcesList, AuthOrchestrationReadScope],
60328
+ [WS_METHODS.feedSourcesUpsert, AuthOrchestrationOperateScope],
60329
+ [WS_METHODS.feedSourcesDelete, AuthOrchestrationOperateScope],
60330
+ [WS_METHODS.feedMarkRead, AuthOrchestrationOperateScope],
60331
+ [WS_METHODS.feedCleanup, AuthOrchestrationOperateScope],
59621
60332
  [WS_METHODS.subscribeTasks, AuthOrchestrationReadScope],
59622
60333
  [WS_METHODS.hubGetSyncStatus, AuthOrchestrationReadScope],
59623
60334
  [WS_METHODS.hubConnect, AuthOrchestrationOperateScope],
@@ -59793,6 +60504,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
59793
60504
  const linearClient = yield* LinearClient;
59794
60505
  const claudeMcpFiles = yield* ClaudeMcpFiles;
59795
60506
  const skillRegistry = yield* SkillRegistry;
60507
+ const feed = yield* FeedService;
59796
60508
  const listMcpServersEverywhere = Effect.gen(function* () {
59797
60509
  const servers = [...yield* mcpRegistry.list];
59798
60510
  const projectRows = yield* projectionProjects.listAll().pipe(Effect.map((rows) => rows.filter((row) => row.deletedAt === null)), Effect.orElseSucceed(() => []));
@@ -60373,6 +61085,13 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
60373
61085
  };
60374
61086
  }), { "rpc.aggregate": "tasks" }),
60375
61087
  [WS_METHODS.subscribeTasks]: ({ source }) => observeRpcStreamEffect$1(WS_METHODS.subscribeTasks, Effect.succeed(taskRepositories.forSource(source).streamWithSnapshot.pipe(Stream.catch((cause) => Stream.fromEffect(toTaskStoreError("tasks.subscribe")(cause))))), { "rpc.aggregate": "tasks" }),
61088
+ [WS_METHODS.feedList]: (input) => observeRpcEffect$1(WS_METHODS.feedList, feed.list(input), { "rpc.aggregate": "feed" }),
61089
+ [WS_METHODS.feedRefresh]: () => observeRpcEffect$1(WS_METHODS.feedRefresh, feed.refresh(), { "rpc.aggregate": "feed" }),
61090
+ [WS_METHODS.feedSourcesList]: () => observeRpcEffect$1(WS_METHODS.feedSourcesList, feed.sources(), { "rpc.aggregate": "feed" }),
61091
+ [WS_METHODS.feedSourcesUpsert]: (input) => observeRpcEffect$1(WS_METHODS.feedSourcesUpsert, feed.upsertSource(input), { "rpc.aggregate": "feed" }),
61092
+ [WS_METHODS.feedSourcesDelete]: (input) => observeRpcEffect$1(WS_METHODS.feedSourcesDelete, feed.deleteSource(input).pipe(Effect.as({})), { "rpc.aggregate": "feed" }),
61093
+ [WS_METHODS.feedMarkRead]: (input) => observeRpcEffect$1(WS_METHODS.feedMarkRead, feed.markRead(input).pipe(Effect.as({})), { "rpc.aggregate": "feed" }),
61094
+ [WS_METHODS.feedCleanup]: (input) => observeRpcEffect$1(WS_METHODS.feedCleanup, feed.cleanup(input), { "rpc.aggregate": "feed" }),
60376
61095
  [WS_METHODS.hubGetSyncStatus]: (_input) => observeRpcEffect$1(WS_METHODS.hubGetSyncStatus, assetSync.status, { "rpc.aggregate": "hub" }),
60377
61096
  [WS_METHODS.hubConnect]: (input) => observeRpcEffect$1(WS_METHODS.hubConnect, hubLink.connect(input).pipe(Effect.mapError((cause) => new HubLinkError({ detail: cause.message })), Effect.andThen(assetSync.status)), { "rpc.aggregate": "hub" }),
60378
61097
  [WS_METHODS.hubDisconnect]: (_input) => observeRpcEffect$1(WS_METHODS.hubDisconnect, hubLink.disconnect.pipe(Effect.mapError((cause) => new HubLinkError({ detail: cause.message })), Effect.andThen(assetSync.status)), { "rpc.aggregate": "hub" }),
@@ -60665,7 +61384,7 @@ const websocketRpcRouteLayer = Layer.unwrap(Effect.gen(function* () {
60665
61384
  const serverAuth = yield* EnvironmentAuth;
60666
61385
  const sessions = yield* SessionStore;
60667
61386
  const session = yield* serverAuth.authenticateWebSocketUpgrade(request).pipe(Effect.catchIf(isServerAuthCredentialError, (error) => failEnvironmentAuthInvalid(serverAuthCredentialReason(error))), Effect.catchIf(isServerAuthInternalError, (error) => failEnvironmentInternal("internal_error", error)));
60668
- const rpcWebSocketHttpEffect = yield* RpcServer.toHttpEffectWebsocket(WsRpcGroup, { disableTracing: true }).pipe(Effect.provide(makeWsRpcLayer(session, previewAutomationBroker).pipe(Layer.provideMerge(RpcSerialization.layerJson), Layer.provide(layer$41), Layer.provide(Layer.succeed(ServerSelfUpdate, serverSelfUpdate)), Layer.provide(Layer.succeed(PullRequestService, pullRequests)), Layer.provide(Layer.succeed(TaskRepositoryRegistry, taskRepositories)), Layer.provide(Layer.succeed(ProjectionProjectRepository, projectionProjects)), Layer.provide(Layer.succeed(P4ProjectFileLoader, p4ProjectFileLoader)), Layer.provide(layer$6.pipe(Layer.provide(layer$21.pipe(Layer.provide(Layer.mergeAll(layer$29, layer$27, layer$25, layer$23)), Layer.provideMerge(layer$46), Layer.provide(layer$44.pipe(Layer.provide(layer$45))))), Layer.provide(layer$47))))));
61387
+ const rpcWebSocketHttpEffect = yield* RpcServer.toHttpEffectWebsocket(WsRpcGroup, { disableTracing: true }).pipe(Effect.provide(makeWsRpcLayer(session, previewAutomationBroker).pipe(Layer.provideMerge(RpcSerialization.layerJson), Layer.provide(layer$42), Layer.provide(Layer.succeed(ServerSelfUpdate, serverSelfUpdate)), Layer.provide(Layer.succeed(PullRequestService, pullRequests)), Layer.provide(Layer.succeed(TaskRepositoryRegistry, taskRepositories)), Layer.provide(Layer.succeed(ProjectionProjectRepository, projectionProjects)), Layer.provide(Layer.succeed(P4ProjectFileLoader, p4ProjectFileLoader)), Layer.provide(layer$6.pipe(Layer.provide(layer$21.pipe(Layer.provide(Layer.mergeAll(layer$29, layer$27, layer$25, layer$23)), Layer.provideMerge(layer$47), Layer.provide(layer$45.pipe(Layer.provide(layer$46))))), Layer.provide(layer$48))))));
60669
61388
  return yield* Effect.acquireUseRelease(sessions.markConnected(session.sessionId), () => rpcWebSocketHttpEffect, () => sessions.markDisconnected(session.sessionId));
60670
61389
  }).pipe(Effect.catchTags({
60671
61390
  EnvironmentAuthInvalidError: HttpServerRespondable.toResponse,
@@ -62803,7 +63522,7 @@ const makeOpenCodeRuntime = Effect.gen(function* () {
62803
63522
  };
62804
63523
  });
62805
63524
  var OpenCodeRuntime = class extends Context.Service()("@p4code/cli/provider/opencodeRuntime") {};
62806
- const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$79));
63525
+ const OpenCodeRuntimeLive = Layer.effect(OpenCodeRuntime, makeOpenCodeRuntime).pipe(Layer.provide(layer$80));
62807
63526
  //#endregion
62808
63527
  //#region src/textGeneration/TextGenerationUtils.ts
62809
63528
  const isTextGenerationError$3 = Schema$1.is(TextGenerationError);
@@ -100628,6 +101347,17 @@ const ThreadSpawnTool = Tool.make("thread_spawn", {
100628
101347
  Crypto.Crypto
100629
101348
  ]
100630
101349
  }).annotate(Tool.Title, "Start a thread").annotate(Tool.Readonly, false).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, false);
101350
+ const ThreadPairCreateTool = Tool.make("thread_pair_create", {
101351
+ description: "Create a persisted Fusion pair between this agent session's own thread as implementer and a watcher it previously created with thread_spawn. Returns the pair id used by clients to open the paired view. No browser authentication or direct database access is needed.",
101352
+ parameters: ThreadPairCreateInput,
101353
+ success: ThreadPairCreateResult,
101354
+ failure: ThreadControlToolError,
101355
+ dependencies: [
101356
+ McpInvocationContext,
101357
+ OrchestrationEngineService,
101358
+ Crypto.Crypto
101359
+ ]
101360
+ }).annotate(Tool.Title, "Create a Fusion pair").annotate(Tool.Readonly, false).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, false);
100631
101361
  const ThreadConfigureTool = Tool.make("thread_configure", {
100632
101362
  description: "Change a thread's settings: title, model, permission mode, interaction mode, compression, and whether it may use subagents without asking. Omit threadId to configure this session's own thread; name one only if this session started it. Every field is optional and an omitted field is left alone; the settings actually changed come back in the result.",
100633
101363
  parameters: ThreadConfigureInput,
@@ -100698,7 +101428,7 @@ const AssetCompressTool = Tool.make("asset_compress", {
100698
101428
  Path.Path
100699
101429
  ]
100700
101430
  }).annotate(Tool.Title, "Compress an asset").annotate(Tool.Readonly, false).annotate(Tool.Destructive, true).annotate(Tool.Idempotent, false);
100701
- const ThreadToolkit = Toolkit.make(ThreadSpawnTool, ThreadConfigureTool, ThreadSettleTool, ThreadSnoozeTool, ThreadRenameTool, MemoryAppendTool, AssetCompressTool);
101431
+ const ThreadToolkit = Toolkit.make(ThreadSpawnTool, ThreadPairCreateTool, ThreadConfigureTool, ThreadSettleTool, ThreadSnoozeTool, ThreadRenameTool, MemoryAppendTool, AssetCompressTool);
100702
101432
  //#endregion
100703
101433
  //#region src/mcp/toolkits/threads/handlers.ts
100704
101434
  const DEFAULT_MEMORY_APPEND_TARGET = "CLAUDE.md";
@@ -100795,6 +101525,24 @@ const ThreadToolkitHandlersLive = ThreadToolkit.toLayer({
100795
101525
  title: input.title
100796
101526
  };
100797
101527
  }),
101528
+ thread_pair_create: (input) => Effect.gen(function* () {
101529
+ const { invocation, threadId: watcherThreadId } = yield* requireThreadControlTarget(input.watcherThreadId);
101530
+ const crypto = yield* Crypto.Crypto;
101531
+ const pairId = ThreadPairId.make(yield* crypto.randomUUIDv4.pipe(Effect.orDie));
101532
+ yield* dispatchControl({
101533
+ type: "thread-pair.create",
101534
+ commandId: yield* newCommandId,
101535
+ pairId,
101536
+ implementerThreadId: invocation.threadId,
101537
+ watcherThreadId,
101538
+ createdAt: DateTime.formatIso(yield* DateTime.now)
101539
+ }, invocation.threadId);
101540
+ return {
101541
+ pairId,
101542
+ implementerThreadId: invocation.threadId,
101543
+ watcherThreadId
101544
+ };
101545
+ }),
100798
101546
  thread_configure: (input) => Effect.gen(function* () {
100799
101547
  const { threadId } = yield* requireThreadControlTarget(input.threadId);
100800
101548
  const createdAt = DateTime.formatIso(yield* DateTime.now);
@@ -104394,7 +105142,7 @@ const ObservabilityLive = Layer.unwrap(Effect.gen(function* () {
104394
105142
  sink,
104395
105143
  ...delegate ? { delegate } : {}
104396
105144
  });
104397
- return Layer.mergeAll(Layer.succeed(Tracer.Tracer, tracer), layer$48(sink));
105145
+ return Layer.mergeAll(Layer.succeed(Tracer.Tracer, tracer), layer$49(sink));
104398
105146
  })).pipe(Layer.provide(OtlpExporter.layerFlusher), Layer.provideMerge(otlpSerializationLayer));
104399
105147
  const metricsLayer = config.otlpMetricsUrl === void 0 ? Layer.empty : OtlpMetrics.layer({
104400
105148
  url: config.otlpMetricsUrl,
@@ -104695,27 +105443,27 @@ const ReactorLayerLive = Layer.empty.pipe(Layer.provideMerge(OrchestrationReacto
104695
105443
  const ProviderSessionDirectoryLayerLive = ProviderSessionDirectoryLive.pipe(Layer.provide(layer$4));
104696
105444
  const ProviderLayerLive = ProviderServiceLive.pipe(Layer.provide(ProviderAdapterRegistryLive), Layer.provideMerge(ProviderSessionDirectoryLayerLive));
104697
105445
  const PersistenceLayerLive = Layer.empty.pipe(Layer.provideMerge(layerConfig));
104698
- const VcsDriverRegistryLayerLive = layer$44.pipe(Layer.provide(layer$45));
104699
- const SourceControlProviderRegistryLayerLive = layer$21.pipe(Layer.provide(Layer.mergeAll(layer$29, layer$27, layer$25, layer$23)), Layer.provideMerge(layer$46), Layer.provideMerge(VcsDriverRegistryLayerLive));
104700
- const GitManagerLayerLive = layer$20.pipe(Layer.provideMerge(layer$30), Layer.provideMerge(layer$46), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(layer$40));
104701
- const GitLayerLive = Layer.empty.pipe(Layer.provideMerge(GitManagerLayerLive), Layer.provideMerge(layer$46));
105446
+ const VcsDriverRegistryLayerLive = layer$45.pipe(Layer.provide(layer$46));
105447
+ const SourceControlProviderRegistryLayerLive = layer$21.pipe(Layer.provide(Layer.mergeAll(layer$29, layer$27, layer$25, layer$23)), Layer.provideMerge(layer$47), Layer.provideMerge(VcsDriverRegistryLayerLive));
105448
+ const GitManagerLayerLive = layer$20.pipe(Layer.provideMerge(layer$30), Layer.provideMerge(layer$47), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(layer$41));
105449
+ const GitLayerLive = Layer.empty.pipe(Layer.provideMerge(GitManagerLayerLive), Layer.provideMerge(layer$47));
104702
105450
  const GitWorkflowLayerLive = layer$19.pipe(Layer.provideMerge(VcsDriverRegistryLayerLive), Layer.provideMerge(GitLayerLive));
104703
- const SourceControlRepositoryServiceLayerLive = layer$5.pipe(Layer.provideMerge(layer$46), Layer.provideMerge(SourceControlProviderRegistryLayerLive));
104704
- const ReviewLayerLive = layer$16.pipe(Layer.provideMerge(layer$46), Layer.provideMerge(VcsDriverRegistryLayerLive));
104705
- const VcsLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$45), Layer.provideMerge(VcsDriverRegistryLayerLive), Layer.provideMerge(layer$17.pipe(Layer.provide(VcsDriverRegistryLayerLive))), Layer.provideMerge(GitWorkflowLayerLive), Layer.provideMerge(ReviewLayerLive), Layer.provideMerge(SourceControlRepositoryServiceLayerLive), Layer.provideMerge(layer$18.pipe(Layer.provide(GitWorkflowLayerLive))));
104706
- const CheckpointingLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$42), Layer.provideMerge(layer$43.pipe(Layer.provide(VcsDriverRegistryLayerLive))));
104707
- const PortScannerLayerLive = layer$37.pipe(Layer.provide(layer$61));
105451
+ const SourceControlRepositoryServiceLayerLive = layer$5.pipe(Layer.provideMerge(layer$47), Layer.provideMerge(SourceControlProviderRegistryLayerLive));
105452
+ const ReviewLayerLive = layer$16.pipe(Layer.provideMerge(layer$47), Layer.provideMerge(VcsDriverRegistryLayerLive));
105453
+ const VcsLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$46), Layer.provideMerge(VcsDriverRegistryLayerLive), Layer.provideMerge(layer$17.pipe(Layer.provide(VcsDriverRegistryLayerLive))), Layer.provideMerge(GitWorkflowLayerLive), Layer.provideMerge(ReviewLayerLive), Layer.provideMerge(SourceControlRepositoryServiceLayerLive), Layer.provideMerge(layer$18.pipe(Layer.provide(GitWorkflowLayerLive))));
105454
+ const CheckpointingLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$43), Layer.provideMerge(layer$44.pipe(Layer.provide(VcsDriverRegistryLayerLive))));
105455
+ const PortScannerLayerLive = layer$37.pipe(Layer.provide(layer$62));
104708
105456
  const TerminalLayerLive = layer$36.pipe(Layer.provide(PtyAdapterLive), Layer.provide(PortScannerLayerLive));
104709
105457
  const PreviewLayerLive = Layer.empty.pipe(Layer.provideMerge(layer$34), Layer.provideMerge(PortScannerLayerLive));
104710
- const WorkspaceEntriesLayerLive = layer$32.pipe(Layer.provide(layer$51));
104711
- const WorkspaceFileSystemLayerLive = layer$31.pipe(Layer.provide(layer$51), Layer.provide(WorkspaceEntriesLayerLive));
104712
- const WorkspaceLayerLive = Layer.mergeAll(layer$51, WorkspaceEntriesLayerLive, WorkspaceFileSystemLayerLive);
104713
- const ProjectFaviconResolverLayerLive = layer$49.pipe(Layer.provide(layer$51), Layer.provide(layer$50));
104714
- const AuthLayerLive = layer$71.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$75));
105458
+ const WorkspaceEntriesLayerLive = layer$32.pipe(Layer.provide(layer$52));
105459
+ const WorkspaceFileSystemLayerLive = layer$31.pipe(Layer.provide(layer$52), Layer.provide(WorkspaceEntriesLayerLive));
105460
+ const WorkspaceLayerLive = Layer.mergeAll(layer$52, WorkspaceEntriesLayerLive, WorkspaceFileSystemLayerLive);
105461
+ const ProjectFaviconResolverLayerLive = layer$50.pipe(Layer.provide(layer$52), Layer.provide(layer$51));
105462
+ const AuthLayerLive = layer$72.pipe(Layer.provideMerge(PersistenceLayerLive), Layer.provide(layer$76));
104715
105463
  const ProviderRuntimeLayerLive = ProviderSessionReaperLive.pipe(Layer.provideMerge(ProviderLayerLive), Layer.provideMerge(OrchestrationLayerLive));
104716
- const RuntimeCoreDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(CheckpointingLayerLive), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(GitLayerLive), Layer.provideMerge(VcsLayerLive), Layer.provideMerge(ProviderRuntimeLayerLive), Layer.provideMerge(Layer.mergeAll(TerminalLayerLive, PreviewLayerLive, RoutedTaskRepositoryLive)), Layer.provideMerge(Layer.mergeAll(PersistenceLayerLive, layer$64)), Layer.provideMerge(layer$59), Layer.provideMerge(ProviderRegistryLive), Layer.provideMerge(ProviderInstanceRegistryHydrationLive), Layer.provideMerge(ProviderEventLoggersLive), Layer.provideMerge(OpenCodeRuntimeLive), Layer.provideMerge(layer$68.pipe(Layer.provide(layer$75))), Layer.provideMerge(WorkspaceLayerLive), Layer.provideMerge(ProjectFaviconResolverLayerLive), Layer.provideMerge(layer$60), Layer.provideMerge(layer$53), Layer.provideMerge(AuthLayerLive), Layer.provideMerge(layer$1.pipe(Layer.provideMerge(LinearClientLive), Layer.provideMerge(Layer.mergeAll(LinearMcpClientLive, TrackerSecretsLive)), Layer.provideMerge(Layer.mergeAll(layer$65, layer$38).pipe(Layer.provideMerge(layer$66), Layer.provideMerge(layer$67))))), Layer.provideMerge(layer$75));
104717
- const UsageLayerLive = layer$39.pipe(Layer.provide(layer$68.pipe(Layer.provide(layer$75))));
104718
- const RuntimeDependenciesLive = RuntimeCoreDependenciesLive.pipe(Layer.provideMerge(UsageLayerLive), Layer.provideMerge(layer$15), Layer.provideMerge(layer$14), Layer.provideMerge(layer$13), Layer.provideMerge(layer$56), Layer.provideMerge(layer$58), Layer.provideMerge(layer$57), Layer.provide(layer$79));
105464
+ const RuntimeCoreDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(CheckpointingLayerLive), Layer.provideMerge(SourceControlProviderRegistryLayerLive), Layer.provideMerge(GitLayerLive), Layer.provideMerge(VcsLayerLive), Layer.provideMerge(ProviderRuntimeLayerLive), Layer.provideMerge(Layer.mergeAll(TerminalLayerLive, PreviewLayerLive, RoutedTaskRepositoryLive)), Layer.provideMerge(Layer.mergeAll(PersistenceLayerLive, layer$65)), Layer.provideMerge(layer$60), Layer.provideMerge(ProviderRegistryLive), Layer.provideMerge(ProviderInstanceRegistryHydrationLive), Layer.provideMerge(ProviderEventLoggersLive), Layer.provideMerge(OpenCodeRuntimeLive), Layer.provideMerge(layer$69.pipe(Layer.provide(layer$76))), Layer.provideMerge(WorkspaceLayerLive), Layer.provideMerge(ProjectFaviconResolverLayerLive), Layer.provideMerge(layer$61), Layer.provideMerge(layer$54), Layer.provideMerge(AuthLayerLive), Layer.provideMerge(layer$1.pipe(Layer.provideMerge(LinearClientLive), Layer.provideMerge(Layer.mergeAll(LinearMcpClientLive, TrackerSecretsLive)), Layer.provideMerge(Layer.mergeAll(layer$66, layer$38).pipe(Layer.provideMerge(layer$67), Layer.provideMerge(layer$68))))), Layer.provideMerge(layer$76));
105465
+ const UsageLayerLive = layer$40.pipe(Layer.provide(layer$69.pipe(Layer.provide(layer$76))));
105466
+ const RuntimeDependenciesLive = layer$39.pipe(Layer.provideMerge(RuntimeCoreDependenciesLive)).pipe(Layer.provideMerge(UsageLayerLive), Layer.provideMerge(layer$15), Layer.provideMerge(layer$14), Layer.provideMerge(layer$13), Layer.provideMerge(layer$57), Layer.provideMerge(layer$59), Layer.provideMerge(layer$58), Layer.provide(layer$80));
104719
105467
  /**
104720
105468
  * Hub asset sync.
104721
105469
  *
@@ -104723,10 +105471,10 @@ const RuntimeDependenciesLive = RuntimeCoreDependenciesLive.pipe(Layer.provideMe
104723
105471
  * not-configured shape, and every call reports that rather than failing — so
104724
105472
  * this costs a server with no hub nothing but a layer.
104725
105473
  */
104726
- const AssetSyncLive = layer$62.pipe(Layer.provideMerge(layer$63), Layer.provideMerge(layer$64));
104727
- const RuntimeServicesLive = layer$52.pipe(Layer.provideMerge(AssetSyncLive), Layer.provideMerge(RuntimeDependenciesLive));
104728
- const PullRequestServiceLive = layer$7.pipe(Layer.provide(layer$8), Layer.provide(SourceControlProviderRegistryLayerLive), Layer.provide(layer$47));
104729
- const makeRoutesLayer = Layer.mergeAll(Layer.mergeAll(HttpApiBuilder.layer(EnvironmentHttpApi).pipe(Layer.provide(authHttpApiLayer), Layer.provide(orchestrationHttpApiLayer), Layer.provide(pullRequestHttpApiLayer), Layer.provide(serverEnvironmentHttpApiLayer), Layer.provide(environmentAuthenticatedAuthLayer)), otlpTracesProxyRouteLayer, assetRouteLayer, mcpOAuthCallbackRouteLayer, staticAndDevRouteLayer, websocketRpcRouteLayer), layer.pipe(Layer.provide(layer$3))).pipe(Layer.provide(ProjectionProjectRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(layer$50), Layer.provide(PullRequestServiceLive), Layer.provide(layer$35), Layer.provide(layer$54), Layer.provide(browserApiCorsLayer), Layer.provide(httpCompressionLayer));
105474
+ const AssetSyncLive = layer$63.pipe(Layer.provideMerge(layer$64), Layer.provideMerge(layer$65));
105475
+ const RuntimeServicesLive = layer$53.pipe(Layer.provideMerge(AssetSyncLive), Layer.provideMerge(RuntimeDependenciesLive));
105476
+ const PullRequestServiceLive = layer$7.pipe(Layer.provide(layer$8), Layer.provide(SourceControlProviderRegistryLayerLive), Layer.provide(layer$48));
105477
+ const makeRoutesLayer = Layer.mergeAll(Layer.mergeAll(HttpApiBuilder.layer(EnvironmentHttpApi).pipe(Layer.provide(authHttpApiLayer), Layer.provide(orchestrationHttpApiLayer), Layer.provide(pullRequestHttpApiLayer), Layer.provide(serverEnvironmentHttpApiLayer), Layer.provide(environmentAuthenticatedAuthLayer)), otlpTracesProxyRouteLayer, assetRouteLayer, mcpOAuthCallbackRouteLayer, staticAndDevRouteLayer, websocketRpcRouteLayer), layer.pipe(Layer.provide(layer$3))).pipe(Layer.provide(ProjectionProjectRepositoryLive.pipe(Layer.provide(PersistenceLayerLive))), Layer.provide(layer$51), Layer.provide(PullRequestServiceLive), Layer.provide(layer$35), Layer.provide(layer$55), Layer.provide(browserApiCorsLayer), Layer.provide(httpCompressionLayer));
104730
105478
  const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
104731
105479
  const config = yield* ServerConfig$1;
104732
105480
  yield* fixPath();
@@ -104769,7 +105517,7 @@ const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
104769
105517
  cause,
104770
105518
  servePort: configured.servePort
104771
105519
  }))) : Effect.void)) : Layer.empty;
104772
- return Layer.mergeAll(HttpRouter.serve(makeRoutesLayer, { disableLogger: !config.logWebSocketEvents }), httpListeningLayer, runtimeStateLayer, tailscaleServeLayer).pipe(Layer.provideMerge(RuntimeServicesLive), Layer.provideMerge(HttpResponseCompressionLive), Layer.provideMerge(HttpServerLive), Layer.provide(ObservabilityLive), Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(layer$47), Layer.provideMerge(PlatformServicesLive));
105520
+ return Layer.mergeAll(HttpRouter.serve(makeRoutesLayer, { disableLogger: !config.logWebSocketEvents }), httpListeningLayer, runtimeStateLayer, tailscaleServeLayer).pipe(Layer.provideMerge(RuntimeServicesLive), Layer.provideMerge(HttpResponseCompressionLive), Layer.provideMerge(HttpServerLive), Layer.provide(ObservabilityLive), Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(layer$48), Layer.provideMerge(PlatformServicesLive));
104773
105521
  }));
104774
105522
  const runServer = Layer.launch(makeServerLayer);
104775
105523
  //#endregion
@@ -105067,11 +105815,11 @@ function describeServiceUpdateState(state) {
105067
105815
  //#endregion
105068
105816
  //#region src/cli/service.ts
105069
105817
  const isBootServiceCommandError = Schema$1.is(BootServiceCommandError);
105070
- const bootServiceLayer = (config) => layer$55({
105818
+ const bootServiceLayer = (config) => layer$56({
105071
105819
  baseDir: config.baseDir,
105072
105820
  logsDir: config.logsDir,
105073
105821
  cliVersion: version
105074
- }).pipe(Layer.provide(layer$61));
105822
+ }).pipe(Layer.provide(layer$62));
105075
105823
  /**
105076
105824
  * The update installed a build that never reported itself listening.
105077
105825
  *
@@ -105197,7 +105945,7 @@ const runServiceCommand = Effect.fn("cli.service.run")(function* (flags, run, pr
105197
105945
  const baseDirNotice = yield* describeNonDefaultBaseDir(config.baseDir);
105198
105946
  if (baseDirNotice !== null) yield* Console.error(baseDirNotice);
105199
105947
  if (prepare !== void 0) yield* prepare(config);
105200
- return yield* run.pipe(Effect.tapError((error) => isBootServiceCommandError(error) ? BootService.pipe(Effect.flatMap((service) => Console.error(`Details: ${service.logPath}`))) : Effect.void), Effect.provide(Layer.mergeAll(bootServiceLayer(config), layer$61)));
105948
+ return yield* run.pipe(Effect.tapError((error) => isBootServiceCommandError(error) ? BootService.pipe(Effect.flatMap((service) => Console.error(`Details: ${service.logPath}`))) : Effect.void), Effect.provide(Layer.mergeAll(bootServiceLayer(config), layer$62)));
105201
105949
  });
105202
105950
  /**
105203
105951
  * Options the installed unit carries, rather than ones this command consumes.
@@ -105364,7 +106112,7 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
105364
106112
  ]));
105365
106113
  //#endregion
105366
106114
  //#region src/bin.ts
105367
- const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$79, FetchHttpClient.layer);
106115
+ const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$80, FetchHttpClient.layer);
105368
106116
  /**
105369
106117
  * Prints an update reminder before dispatching, at most once a day.
105370
106118
  *