@dxos/plugin-magazine 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/dist/lib/MagazinePlugin.mjs +36 -0
  2. package/dist/lib/MagazinePlugin.mjs.map +1 -0
  3. package/dist/lib/MagazinePlugin.workerd.mjs +26 -0
  4. package/dist/lib/MagazinePlugin.workerd.mjs.map +1 -0
  5. package/dist/lib/atoms.mjs +175 -0
  6. package/dist/lib/atoms.mjs.map +1 -0
  7. package/dist/lib/capabilities.mjs +12 -0
  8. package/dist/lib/capabilities.mjs.map +1 -0
  9. package/dist/lib/chunk-FeedArticle.mjs +70 -0
  10. package/dist/lib/chunk-FeedArticle.mjs.map +1 -0
  11. package/dist/lib/chunk-FeedProperties.mjs +78 -0
  12. package/dist/lib/chunk-FeedProperties.mjs.map +1 -0
  13. package/dist/lib/chunk-MagazineArticle.mjs +267 -0
  14. package/dist/lib/chunk-MagazineArticle.mjs.map +1 -0
  15. package/dist/lib/chunk-PostArticle.mjs +174 -0
  16. package/dist/lib/chunk-PostArticle.mjs.map +1 -0
  17. package/dist/lib/chunk-PostCard.mjs +62 -0
  18. package/dist/lib/chunk-PostCard.mjs.map +1 -0
  19. package/dist/lib/chunk-app-graph-builder.mjs +91 -0
  20. package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
  21. package/dist/lib/chunk-clear-magazine.mjs +37 -0
  22. package/dist/lib/chunk-clear-magazine.mjs.map +1 -0
  23. package/dist/lib/chunk-create-object.mjs +59 -0
  24. package/dist/lib/chunk-create-object.mjs.map +1 -0
  25. package/dist/lib/chunk-curate-magazine.mjs +164 -0
  26. package/dist/lib/chunk-curate-magazine.mjs.map +1 -0
  27. package/dist/lib/chunk-date.mjs +25 -0
  28. package/dist/lib/chunk-date.mjs.map +1 -0
  29. package/dist/lib/chunk-fetch-article-content.mjs +26 -0
  30. package/dist/lib/chunk-fetch-article-content.mjs.map +1 -0
  31. package/dist/lib/chunk-load-post-content.mjs +57 -0
  32. package/dist/lib/chunk-load-post-content.mjs.map +1 -0
  33. package/dist/lib/{neutral/chunk-JFPR6OV4.mjs → chunk-meta.mjs} +19 -26
  34. package/dist/lib/chunk-meta.mjs.map +1 -0
  35. package/dist/lib/chunk-operation-handler.mjs +13 -0
  36. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  37. package/dist/lib/chunk-paths.mjs +8 -0
  38. package/dist/lib/chunk-paths.mjs.map +1 -0
  39. package/dist/lib/chunk-post-content.mjs +14 -0
  40. package/dist/lib/chunk-post-content.mjs.map +1 -0
  41. package/dist/lib/chunk-react-surface.mjs +60 -0
  42. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  43. package/dist/lib/chunk-routine-templates.mjs +52 -0
  44. package/dist/lib/chunk-routine-templates.mjs.map +1 -0
  45. package/dist/lib/chunk-skill-definition.mjs +12 -0
  46. package/dist/lib/chunk-skill-definition.mjs.map +1 -0
  47. package/dist/lib/chunk-sources.mjs +576 -0
  48. package/dist/lib/chunk-sources.mjs.map +1 -0
  49. package/dist/lib/chunk-sync-feed.mjs +86 -0
  50. package/dist/lib/chunk-sync-feed.mjs.map +1 -0
  51. package/dist/lib/chunk-text.mjs +52 -0
  52. package/dist/lib/chunk-text.mjs.map +1 -0
  53. package/dist/lib/chunk-types.mjs +607 -0
  54. package/dist/lib/chunk-types.mjs.map +1 -0
  55. package/dist/lib/components.mjs +323 -0
  56. package/dist/lib/components.mjs.map +1 -0
  57. package/dist/lib/containers.mjs +11 -0
  58. package/dist/lib/containers.mjs.map +1 -0
  59. package/dist/lib/index.mjs +3 -0
  60. package/dist/lib/meta.mjs +2 -0
  61. package/dist/lib/operations.mjs +7 -0
  62. package/dist/lib/operations.mjs.map +1 -0
  63. package/dist/lib/plugin.mjs +9 -0
  64. package/dist/lib/plugin.mjs.map +1 -0
  65. package/dist/lib/plugin.workerd.mjs +3 -0
  66. package/dist/lib/{neutral/skills/index.mjs → skills.mjs} +15 -28
  67. package/dist/lib/skills.mjs.map +1 -0
  68. package/dist/lib/testing.mjs +71 -0
  69. package/dist/lib/testing.mjs.map +1 -0
  70. package/dist/lib/translations.mjs +74 -0
  71. package/dist/lib/translations.mjs.map +1 -0
  72. package/dist/lib/types.mjs +2 -0
  73. package/dist/types/src/MagazinePlugin.d.ts.map +1 -1
  74. package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
  75. package/dist/types/src/capabilities/create-object.d.ts +1 -1
  76. package/dist/types/src/capabilities/index.d.ts +0 -1
  77. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  79. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  80. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/routine-templates.d.ts +1 -1
  82. package/dist/types/src/components/PostContent/PostContent.d.ts +1 -13
  83. package/dist/types/src/components/PostContent/PostContent.d.ts.map +1 -1
  84. package/dist/types/src/components/PostContent/dedupe-images.d.ts +13 -0
  85. package/dist/types/src/components/PostContent/dedupe-images.d.ts.map +1 -0
  86. package/dist/types/src/components/PostContent/index.d.ts +1 -0
  87. package/dist/types/src/components/PostContent/index.d.ts.map +1 -1
  88. package/dist/types/src/components/PostStack/PostStack.d.ts +1 -1
  89. package/dist/types/src/components/PostStack/PostStack.d.ts.map +1 -1
  90. package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts +1 -1
  91. package/dist/types/src/components/SubscriptionStack/SubscriptionStack.d.ts.map +1 -1
  92. package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts +4 -1
  93. package/dist/types/src/containers/FeedArticle/FeedArticle.d.ts.map +1 -1
  94. package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts +4 -1
  95. package/dist/types/src/containers/FeedProperties/FeedProperties.d.ts.map +1 -1
  96. package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts +4 -1
  97. package/dist/types/src/containers/MagazineArticle/MagazineArticle.d.ts.map +1 -1
  98. package/dist/types/src/containers/MagazineArticle/MagazineArticle.stories.d.ts.map +1 -1
  99. package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts +4 -1
  100. package/dist/types/src/containers/MagazineArticle/MagazineTile.d.ts.map +1 -1
  101. package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts +4 -8
  102. package/dist/types/src/containers/MagazineArticle/useToolbar.d.ts.map +1 -1
  103. package/dist/types/src/containers/PostArticle/PostArticle.d.ts +4 -1
  104. package/dist/types/src/containers/PostArticle/PostArticle.d.ts.map +1 -1
  105. package/dist/types/src/containers/PostArticle/PostArticle.stories.d.ts.map +1 -1
  106. package/dist/types/src/containers/PostArticle/PostToolbar.d.ts +1 -1
  107. package/dist/types/src/containers/PostArticle/PostToolbar.d.ts.map +1 -1
  108. package/dist/types/src/containers/PostCard/PostCard.d.ts +4 -6
  109. package/dist/types/src/containers/PostCard/PostCard.d.ts.map +1 -1
  110. package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts +4 -1
  111. package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.d.ts.map +1 -1
  112. package/dist/types/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.d.ts.map +1 -1
  113. package/dist/types/src/stories/ArticleExtractor.stories.d.ts +1 -0
  114. package/dist/types/src/stories/ArticleExtractor.stories.d.ts.map +1 -1
  115. package/dist/types/src/stories/MagazineCurate.stories.d.ts.map +1 -1
  116. package/dist/types/src/templates/magazine-curation.d.ts.map +1 -1
  117. package/dist/types/src/translations.d.ts +1 -0
  118. package/dist/types/src/translations.d.ts.map +1 -1
  119. package/dist/types/tsconfig.tsbuildinfo +1 -1
  120. package/dx.config.ts +1 -1
  121. package/package.json +57 -60
  122. package/src/MagazinePlugin.tsx +0 -3
  123. package/src/atoms/atoms.test.ts +5 -4
  124. package/src/capabilities/app-graph-builder.ts +8 -6
  125. package/src/capabilities/index.ts +0 -1
  126. package/src/capabilities/{react-surface.tsx → react-surface.ts} +10 -12
  127. package/src/components/PostContent/PostContent.test.ts +1 -1
  128. package/src/components/PostContent/PostContent.tsx +1 -41
  129. package/src/components/PostContent/dedupe-images.ts +48 -0
  130. package/src/components/PostContent/index.ts +1 -0
  131. package/src/containers/FeedArticle/FeedArticle.stories.tsx +2 -2
  132. package/src/containers/FeedArticle/FeedArticle.tsx +4 -2
  133. package/src/containers/FeedProperties/FeedProperties.tsx +6 -4
  134. package/src/containers/MagazineArticle/MagazineArticle.stories.tsx +2 -1
  135. package/src/containers/MagazineArticle/MagazineArticle.tsx +8 -6
  136. package/src/containers/MagazineArticle/MagazineTile.tsx +2 -0
  137. package/src/containers/MagazineArticle/useToolbar.tsx +2 -0
  138. package/src/containers/PostArticle/PostArticle.stories.tsx +2 -1
  139. package/src/containers/PostArticle/PostArticle.tsx +6 -3
  140. package/src/containers/PostArticle/PostToolbar.tsx +1 -1
  141. package/src/containers/PostCard/PostCard.tsx +3 -1
  142. package/src/containers/SubscriptionsArticle/SubscriptionsArticle.stories.tsx +2 -1
  143. package/src/containers/SubscriptionsArticle/SubscriptionsArticle.tsx +5 -3
  144. package/src/operations/curate-magazine.test.ts +108 -4
  145. package/src/operations/sync-feed.test.ts +1 -1
  146. package/src/operations/sync-feed.ts +1 -1
  147. package/src/paths.ts +3 -3
  148. package/src/stories/ArticleExtractor.stories.tsx +1 -1
  149. package/src/stories/MagazineCurate.stories.tsx +3 -2
  150. package/src/templates/magazine-curation.ts +3 -2
  151. package/src/types/Magazine.test.ts +1 -1
  152. package/src/types/Subscription.ts +1 -1
  153. package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs +0 -90
  154. package/dist/lib/neutral/FeedArticle-PEWCFFSP.mjs.map +0 -7
  155. package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs +0 -97
  156. package/dist/lib/neutral/FeedProperties-EIO7IZOA.mjs.map +0 -7
  157. package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs +0 -325
  158. package/dist/lib/neutral/MagazineArticle-5T7RTIPS.mjs.map +0 -7
  159. package/dist/lib/neutral/MagazinePlugin.mjs +0 -62
  160. package/dist/lib/neutral/MagazinePlugin.mjs.map +0 -7
  161. package/dist/lib/neutral/MagazinePlugin.workerd.mjs +0 -12
  162. package/dist/lib/neutral/MagazinePlugin.workerd.mjs.map +0 -7
  163. package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs +0 -230
  164. package/dist/lib/neutral/PostArticle-BGIPU7XA.mjs.map +0 -7
  165. package/dist/lib/neutral/PostCard-VDGN7BBA.mjs +0 -60
  166. package/dist/lib/neutral/PostCard-VDGN7BBA.mjs.map +0 -7
  167. package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs +0 -121
  168. package/dist/lib/neutral/app-graph-builder-JDPRBVHL.mjs.map +0 -7
  169. package/dist/lib/neutral/capabilities/index.mjs +0 -21
  170. package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
  171. package/dist/lib/neutral/chunk-3K4AQKBZ.mjs +0 -12
  172. package/dist/lib/neutral/chunk-3K4AQKBZ.mjs.map +0 -7
  173. package/dist/lib/neutral/chunk-AFPBWBTK.mjs +0 -591
  174. package/dist/lib/neutral/chunk-AFPBWBTK.mjs.map +0 -7
  175. package/dist/lib/neutral/chunk-APQRTYT3.mjs +0 -57
  176. package/dist/lib/neutral/chunk-APQRTYT3.mjs.map +0 -7
  177. package/dist/lib/neutral/chunk-GU725ZF4.mjs +0 -11
  178. package/dist/lib/neutral/chunk-GU725ZF4.mjs.map +0 -7
  179. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  180. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  181. package/dist/lib/neutral/chunk-JFPR6OV4.mjs.map +0 -7
  182. package/dist/lib/neutral/chunk-KTYLUOUG.mjs +0 -36
  183. package/dist/lib/neutral/chunk-KTYLUOUG.mjs.map +0 -7
  184. package/dist/lib/neutral/chunk-LFSQMLPK.mjs +0 -8
  185. package/dist/lib/neutral/chunk-LFSQMLPK.mjs.map +0 -7
  186. package/dist/lib/neutral/chunk-MBPX7RPI.mjs +0 -14
  187. package/dist/lib/neutral/chunk-MBPX7RPI.mjs.map +0 -7
  188. package/dist/lib/neutral/chunk-OYCDRSWB.mjs +0 -624
  189. package/dist/lib/neutral/chunk-OYCDRSWB.mjs.map +0 -7
  190. package/dist/lib/neutral/chunk-SAWKLGJU.mjs +0 -28
  191. package/dist/lib/neutral/chunk-SAWKLGJU.mjs.map +0 -7
  192. package/dist/lib/neutral/chunk-XCNCK47N.mjs +0 -15
  193. package/dist/lib/neutral/chunk-XCNCK47N.mjs.map +0 -7
  194. package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs +0 -59
  195. package/dist/lib/neutral/clear-magazine-KNY4OWY4.mjs.map +0 -7
  196. package/dist/lib/neutral/components/index.mjs +0 -338
  197. package/dist/lib/neutral/components/index.mjs.map +0 -7
  198. package/dist/lib/neutral/containers/index.mjs +0 -17
  199. package/dist/lib/neutral/containers/index.mjs.map +0 -7
  200. package/dist/lib/neutral/create-object-SYZMRR4H.mjs +0 -98
  201. package/dist/lib/neutral/create-object-SYZMRR4H.mjs.map +0 -7
  202. package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs +0 -184
  203. package/dist/lib/neutral/curate-magazine-7RMKSJC5.mjs.map +0 -7
  204. package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs +0 -31
  205. package/dist/lib/neutral/fetch-article-content-CXPKXIMR.mjs.map +0 -7
  206. package/dist/lib/neutral/index.mjs +0 -18
  207. package/dist/lib/neutral/index.mjs.map +0 -7
  208. package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs +0 -65
  209. package/dist/lib/neutral/load-post-content-H3S4TKVM.mjs.map +0 -7
  210. package/dist/lib/neutral/meta.json +0 -1
  211. package/dist/lib/neutral/meta.mjs +0 -8
  212. package/dist/lib/neutral/meta.mjs.map +0 -7
  213. package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs +0 -18
  214. package/dist/lib/neutral/navigation-resolver-IN4OMCDR.mjs.map +0 -7
  215. package/dist/lib/neutral/operation-handler-JE3743BU.mjs +0 -8
  216. package/dist/lib/neutral/operation-handler-JE3743BU.mjs.map +0 -7
  217. package/dist/lib/neutral/operations/index.mjs +0 -8
  218. package/dist/lib/neutral/operations/index.mjs.map +0 -7
  219. package/dist/lib/neutral/plugin.mjs +0 -16
  220. package/dist/lib/neutral/plugin.mjs.map +0 -7
  221. package/dist/lib/neutral/plugin.workerd.mjs +0 -16
  222. package/dist/lib/neutral/plugin.workerd.mjs.map +0 -7
  223. package/dist/lib/neutral/react-surface-TZESAMG2.mjs +0 -60
  224. package/dist/lib/neutral/react-surface-TZESAMG2.mjs.map +0 -7
  225. package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs +0 -52
  226. package/dist/lib/neutral/routine-templates-D5A2L4KL.mjs.map +0 -7
  227. package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs +0 -8
  228. package/dist/lib/neutral/skill-definition-3KLMUEC5.mjs.map +0 -7
  229. package/dist/lib/neutral/skills/index.mjs.map +0 -7
  230. package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs +0 -99
  231. package/dist/lib/neutral/sync-feed-SDXYF7HU.mjs.map +0 -7
  232. package/dist/lib/neutral/translations.mjs +0 -81
  233. package/dist/lib/neutral/translations.mjs.map +0 -7
  234. package/dist/lib/neutral/types/index.mjs +0 -14
  235. package/dist/lib/neutral/types/index.mjs.map +0 -7
  236. package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -5
  237. package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
  238. package/dist/types/src/operations/curate-magazine.skill.test.d.ts +0 -2
  239. package/dist/types/src/operations/curate-magazine.skill.test.d.ts.map +0 -1
  240. package/src/capabilities/navigation-resolver.ts +0 -21
  241. package/src/operations/curate-magazine.skill.conversations.json +0 -1
  242. package/src/operations/curate-magazine.skill.test.ts +0 -167
@@ -0,0 +1,607 @@
1
+ import { trim } from "@dxos/util";
2
+ import * as Schema from "effect/Schema";
3
+ import { Annotation, DXN, Database, Feed, Filter, Format, Obj, Query, Ref, Registry, Scope, Tag, Type } from "@dxos/echo";
4
+ import * as Effect from "effect/Effect";
5
+ import { FormInlineAnnotation, FormInputAnnotation, LabelAnnotation } from "@dxos/echo/Annotation";
6
+ import { EffectEx } from "@dxos/effect";
7
+ import { FactoryAnnotation, FeedAnnotation, StateMap, TagIndex } from "@dxos/schema";
8
+ import { Instructions, Operation, Skill } from "@dxos/compute";
9
+ import { meta } from "#meta";
10
+ import { AppAnnotation } from "@dxos/app-toolkit";
11
+ //#region \0rolldown/runtime.js
12
+ var __defProp = Object.defineProperty;
13
+ var __exportAll = (all, no_symbols) => {
14
+ let target = {};
15
+ for (var name in all) __defProp(target, name, {
16
+ get: all[name],
17
+ enumerable: true
18
+ });
19
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
20
+ return target;
21
+ };
22
+ //#endregion
23
+ //#region src/types/Subscription.ts
24
+ var Subscription_exports = /* @__PURE__ */ __exportAll({
25
+ DEFAULT_KEEP: () => 10,
26
+ FeedType: () => FeedType,
27
+ Post: () => Post,
28
+ PostContent: () => PostContent,
29
+ PostState: () => PostState$1,
30
+ SYSTEM_TAGS: () => SYSTEM_TAGS,
31
+ Subscription: () => Subscription,
32
+ appendPostContent: () => appendPostContent,
33
+ findPostContent: () => findPostContent,
34
+ findSystemTagUri: () => findSystemTagUri,
35
+ getPostSubscription: () => getPostSubscription,
36
+ getReadAt: () => getReadAt,
37
+ hasTag: () => hasTag,
38
+ instanceOf: () => instanceOf$1,
39
+ makePost: () => makePost,
40
+ makeSubscription: () => makeSubscription,
41
+ pickLatestPostContent: () => pickLatestPostContent,
42
+ queryPostContentForPost: () => queryPostContentForPost,
43
+ setReadAt: () => setReadAt,
44
+ setTag: () => setTag
45
+ });
46
+ /** Subscription protocol type. */
47
+ var FeedType = Schema.Literal("standard-site", "rss", "bluesky");
48
+ /**
49
+ * System per-Post flags (starred/archived) modelled as space-wide {@link Tag} objects (resolved via
50
+ * `Tag.findOrCreate` on first use). Each entry is a single source of truth carrying its foreign
51
+ * `key` plus display `label`/`hue`.
52
+ */
53
+ var SYSTEM_TAGS = {
54
+ starred: {
55
+ key: {
56
+ source: "org.dxos.plugin.magazine",
57
+ id: "starred"
58
+ },
59
+ label: "Starred",
60
+ hue: "amber"
61
+ },
62
+ archived: {
63
+ key: {
64
+ source: "org.dxos.plugin.magazine",
65
+ id: "archived"
66
+ },
67
+ label: "Archived",
68
+ hue: "neutral"
69
+ }
70
+ };
71
+ /** Per-Post mutable state stored on the Subscription (shared across magazines), keyed by Post id. */
72
+ var PostState$1 = Schema.Struct({
73
+ /** ISO 8601 timestamp when first opened. */
74
+ readAt: Schema.optional(Schema.String) });
75
+ /**
76
+ * Subscription feed schema: an RSS/Atom/AT Protocol subscription.
77
+ */
78
+ var Subscription = class extends Type.makeObject(DXN.make("org.dxos.type.subscription.feed", "0.1.0"))(Schema.Struct({
79
+ /** User-facing title of the feed. */
80
+ name: Schema.String.pipe(Schema.optional),
81
+ /** The URL of the RSS/Atom feed or AT Protocol handle/DID. */
82
+ url: Schema.String.pipe(Schema.optional),
83
+ /** Protocol type — determines which fetcher is used for sync. */
84
+ type: FeedType.pipe(Schema.optional),
85
+ /** Description of the feed. */
86
+ description: Schema.String.pipe(Schema.optional),
87
+ /** URL of the feed's associated website. */
88
+ link: Schema.String.pipe(Schema.optional),
89
+ /** URL of the feed's icon/image. */
90
+ iconUrl: Schema.String.pipe(Schema.optional),
91
+ /**
92
+ * Maximum number of (non-starred) Posts retained in the feed's queue when syncing.
93
+ * Older posts beyond this bound are dropped; starred posts are preserved regardless.
94
+ * Defaults to {@link DEFAULT_KEEP} when unset.
95
+ */
96
+ keep: Schema.Number.pipe(Schema.annotations({
97
+ title: "Keep",
98
+ description: "Number of synced items."
99
+ }), Schema.optional),
100
+ /** Opaque sync cursor — protocol-specific. */
101
+ cursor: Schema.String.pipe(FormInputAnnotation.set(false), Schema.optional),
102
+ /** Backing ECHO feed (queue) for Posts: immutable feed entries appended by sync. */
103
+ feed: Ref.Ref(Feed.Feed).pipe(FormInputAnnotation.set(false)),
104
+ /**
105
+ * Backing ECHO feed (queue) for fetched article bodies — one
106
+ * {@link PostContent} entry per Post whose content has been loaded.
107
+ *
108
+ * Feeds (not the {@link postState} side map) are the right home for big
109
+ * immutable payloads: they're append-only, lazily replicated, and don't
110
+ * inflate the Subscription document. The side map keeps only the small
111
+ * per-Post user state (read/archived/star/imageUrl).
112
+ *
113
+ * Optional for backwards compatibility with older Subscription documents
114
+ * that pre-date this feed; new subscriptions always have one via
115
+ * {@link makeSubscription}.
116
+ */
117
+ contentFeed: Ref.Ref(Feed.Feed).pipe(FormInputAnnotation.set(false), Schema.optional),
118
+ /**
119
+ * Per-Post mutable state keyed by Post id, shared across every Magazine that references the Post.
120
+ * Posts live immutably in the `feed` queue; their `readAt` marker lives here. (`snippet`/`imageUrl`
121
+ * are derived from the Post, or refined onto `contentFeed` entries — not stored here; star/archive
122
+ * are tags — see `tags`.)
123
+ */
124
+ postState: Ref.Ref(StateMap.StateMap).pipe(FormInputAnnotation.set(false)),
125
+ /**
126
+ * Per-Post tags keyed by tag uri → Post ids. Boolean flags (starred, archived — see
127
+ * {@link SYSTEM_TAGS}) are modelled as {@link Tag} objects so they
128
+ * participate in the space-wide tag system. Stored as a child {@link TagIndex} object.
129
+ */
130
+ tags: Ref.Ref(TagIndex.TagIndex).pipe(FormInputAnnotation.set(false))
131
+ }).pipe(LabelAnnotation.set(["name", "url"]), Annotation.IconAnnotation.set({
132
+ icon: "ph--rss--regular",
133
+ hue: "indigo"
134
+ }), FeedAnnotation.set(true), FactoryAnnotation.set(((values) => makeSubscription(values))))) {};
135
+ /** Checks if a value is a Subscription.Subscription object. */
136
+ var instanceOf$1 = (value) => Obj.instanceOf(Subscription, value);
137
+ /** Creates a Subscription.Subscription with backing ECHO feeds for posts and fetched content. */
138
+ var makeSubscription = (props = {}) => {
139
+ const postFeed = Feed.make();
140
+ const contentFeed = Feed.make();
141
+ const postState = StateMap.make();
142
+ const tags = TagIndex.make();
143
+ const subscription = Obj.make(Subscription, {
144
+ feed: Ref.make(postFeed),
145
+ contentFeed: Ref.make(contentFeed),
146
+ postState: Ref.make(postState),
147
+ tags: Ref.make(tags),
148
+ ...props
149
+ });
150
+ Obj.setParent(postFeed, subscription);
151
+ Obj.setParent(contentFeed, subscription);
152
+ Obj.setParent(postState, subscription);
153
+ Obj.setParent(tags, subscription);
154
+ return subscription;
155
+ };
156
+ /**
157
+ * A single post/entry within a subscription feed.
158
+ *
159
+ * Immutable feed-entry: every field below is set at sync time by the protocol
160
+ * fetcher and never written to again. Mutable state (read, archived, starred,
161
+ * fetched content, hero image) lives on
162
+ * {@link Subscription.Subscription.postState} keyed by Post id; curation
163
+ * outputs (snippet, rank) live on `Magazine.postState`.
164
+ */
165
+ var Post = class extends Type.makeObject(DXN.make("org.dxos.type.subscription.post", "0.1.0"))(Schema.Struct({
166
+ /** Source subscription feed; populated by `SyncSubscription` so curated posts can show provenance. */
167
+ source: Ref.Ref(Subscription).pipe(FormInputAnnotation.set(false), Schema.optional),
168
+ /** Post title. */
169
+ title: Schema.String.pipe(Schema.optional),
170
+ /** URL link to the original article. */
171
+ link: Schema.String.pipe(Schema.optional),
172
+ /** Plain-text or summary. */
173
+ description: Schema.String.pipe(Schema.optional),
174
+ /** Plain-text or HTML content. */
175
+ content: Schema.String.pipe(Schema.optional),
176
+ /** Author name. */
177
+ author: Schema.String.pipe(Schema.optional),
178
+ /** ISO 8601 publication date. */
179
+ published: Schema.String.pipe(Schema.optional),
180
+ /** Unique identifier (guid) from the feed. */
181
+ guid: Schema.String.pipe(Schema.optional)
182
+ }).pipe(LabelAnnotation.set(["title"]), Annotation.IconAnnotation.set({
183
+ icon: "ph--article--regular",
184
+ hue: "indigo"
185
+ }))) {};
186
+ /** Creates a Subscription.Post object. */
187
+ var makePost = (props = {}) => Obj.make(Post, props);
188
+ /**
189
+ * An entry in a Subscription's {@link Subscription.contentFeed} queue: the
190
+ * fetched body of a Post, linked back to the queue Post in the parallel `feed`
191
+ * queue via {@link post}.
192
+ *
193
+ * Lives in a queue (not on `Subscription.postState`) because fetched bodies
194
+ * can be many KB; storing them inline would inflate the Subscription document
195
+ * unboundedly and force every reader to download every body. The queue is
196
+ * lazily replicated and append-only — a natural fit for immutable content.
197
+ */
198
+ var PostContent = class extends Type.makeObject(DXN.make("org.dxos.type.subscription.postContent", "0.1.0"))(Schema.Struct({
199
+ /** Source Post (in the Subscription's `feed` queue). */
200
+ post: Ref.Ref(Post).pipe(FormInputAnnotation.set(false)),
201
+ /** Extracted article body, in Markdown. */
202
+ text: Schema.String,
203
+ /** Refined snippet derived from the full article (preferred over the description-derived one). */
204
+ snippet: Schema.optional(Schema.String),
205
+ /** Refined hero image derived from the full article (preferred over the description-derived one). */
206
+ imageUrl: Schema.optional(Schema.String),
207
+ /** ISO 8601 timestamp when the content was fetched. */
208
+ fetchedAt: Schema.String
209
+ }).pipe(Annotation.HiddenAnnotation.set(true))) {};
210
+ /** ISO timestamp the Post was first opened, or undefined. */
211
+ var getReadAt = (subscription, postId) => {
212
+ const stateMap = subscription?.postState.target;
213
+ return stateMap ? StateMap.bind(stateMap).get(postId).readAt : void 0;
214
+ };
215
+ /** Sets/clears the Post's read marker. */
216
+ var setReadAt = (subscription, postId, value) => {
217
+ const stateMap = subscription.postState.target;
218
+ if (stateMap) StateMap.bind(stateMap).patch(postId, { readAt: value });
219
+ };
220
+ /** Resolves the uri of an existing system Tag without creating one; `undefined` when absent. Async. */
221
+ var findSystemTagUri = async (db, which) => {
222
+ const [currentTag] = await db.query(Filter.foreignKeys(Tag.Tag, [SYSTEM_TAGS[which].key])).run();
223
+ if (currentTag) return Obj.getURI(currentTag).toString();
224
+ const legacyKey = {
225
+ source: "org.dxos.plugin.feed",
226
+ id: SYSTEM_TAGS[which].key.id
227
+ };
228
+ const [legacyTag] = await db.query(Filter.foreignKeys(Tag.Tag, [legacyKey])).run();
229
+ return legacyTag ? Obj.getURI(legacyTag).toString() : void 0;
230
+ };
231
+ /** Whether a Post carries the given (resolved) tag uri on its Subscription. Pure. */
232
+ var hasTag = (subscription, postId, tagUri) => {
233
+ const tagIndex = subscription?.tags.target;
234
+ return !!(tagIndex && tagUri) && TagIndex.bind(tagIndex).objects(tagUri).includes(postId);
235
+ };
236
+ /** Sets/clears a system tag (`starred`/`archived`) on a Post (find-or-creates the Tag object). Async. */
237
+ var setTag = async (subscription, postId, db, which, value) => {
238
+ const tag = await Tag.findOrCreate(db, SYSTEM_TAGS[which]);
239
+ const uri = Obj.getURI(tag).toString();
240
+ const tagIndex = subscription.tags.target;
241
+ if (!tagIndex) return;
242
+ const tags = TagIndex.bind(tagIndex);
243
+ if (value) tags.setTag(uri, postId);
244
+ else tags.unsetTag(uri, postId);
245
+ };
246
+ /** Resolves a Post's source Subscription synchronously if its `source` ref is loaded, else undefined. */
247
+ var getPostSubscription = (post) => post.source?.target;
248
+ /**
249
+ * Query for {@link PostContent} entries referencing a Post via the reverse-ref index.
250
+ * Scoped to the Subscription's post and content feeds.
251
+ */
252
+ var queryPostContentForPost = (subscription, post) => {
253
+ const postFeed = subscription.feed?.target;
254
+ const contentFeed = subscription.contentFeed?.target;
255
+ if (!postFeed || !contentFeed) return;
256
+ const postFeedUri = Obj.getURI(postFeed);
257
+ const contentFeedUri = Obj.getURI(contentFeed);
258
+ return Query.select(Filter.id(post.id)).referencedBy(PostContent, "post").from(Scope.feed(postFeedUri), Scope.feed(contentFeedUri));
259
+ };
260
+ /** Pick the newest PostContent when multiple entries reference the same Post. */
261
+ var pickLatestPostContent = (entries) => {
262
+ if (entries.length === 0) return;
263
+ return [...entries].sort((entryA, entryB) => entryB.fetchedAt.localeCompare(entryA.fetchedAt))[0];
264
+ };
265
+ /** Looks up PostContent for a Post (newest wins); undefined if absent. */
266
+ var findPostContent = async (subscription, post) => {
267
+ const db = Obj.getDatabase(subscription);
268
+ const query = queryPostContentForPost(subscription, post);
269
+ if (!db || !query) return;
270
+ return pickLatestPostContent(await db.query(query).run());
271
+ };
272
+ /** Returns the Subscription's `contentFeed`, lazily creating and attaching one when missing. */
273
+ var ensureContentFeed = (subscription) => {
274
+ const existing = subscription.contentFeed?.target;
275
+ if (existing) return existing;
276
+ const created = Feed.make();
277
+ Obj.update(subscription, (subscription) => {
278
+ const mutable = subscription;
279
+ mutable.contentFeed = Ref.make(created);
280
+ });
281
+ Obj.setParent(created, subscription);
282
+ return created;
283
+ };
284
+ /**
285
+ * Appends a {@link PostContent} entry (body + refined snippet/imageUrl) to a Subscription's
286
+ * `contentFeed`, lazily creating the feed on first use.
287
+ */
288
+ var appendPostContent = async (space, subscription, entry) => {
289
+ const echoFeed = ensureContentFeed(subscription);
290
+ const content = Obj.make(PostContent, {
291
+ post: Ref.fromURI(Obj.getURI(entry.post)),
292
+ text: entry.text,
293
+ ...entry.snippet ? { snippet: entry.snippet } : {},
294
+ ...entry.imageUrl ? { imageUrl: entry.imageUrl } : {},
295
+ fetchedAt: entry.fetchedAt ?? (/* @__PURE__ */ new Date()).toISOString()
296
+ });
297
+ await Feed.append(echoFeed, [content]).pipe(Effect.provide(Database.layer(space.db)), EffectEx.runAndForwardErrors);
298
+ };
299
+ //#endregion
300
+ //#region src/types/CreateSubscription.ts
301
+ var CreateSubscription_exports = /* @__PURE__ */ __exportAll({
302
+ HandleSchema: () => HandleSchema,
303
+ RssCreateBase: () => RssCreateBase,
304
+ StandardSiteCreateBase: () => StandardSiteCreateBase,
305
+ isHandle: () => isHandle,
306
+ isUrl: () => isUrl,
307
+ makeSubscriptionFromCreate: () => makeSubscriptionFromCreate
308
+ });
309
+ var HandleSchema = Schema.String.pipe(Schema.pattern(/^@?([\da-z-]+\.)+[a-z]{2,}$|^did:[a-z]+:[a-zA-Z0-9._%:-]+$/i));
310
+ var isHandle = Schema.is(HandleSchema);
311
+ var isUrl = Schema.is(Format.URL);
312
+ var StandardSiteCreateBase = Schema.Struct({
313
+ type: Schema.Literal("standard-site"),
314
+ handle: HandleSchema.annotations({
315
+ title: "Handle",
316
+ description: "atproto handle, e.g. dxos.org."
317
+ }),
318
+ publication: Schema.String.annotations({
319
+ title: "Publication",
320
+ description: "Choose a publication."
321
+ })
322
+ });
323
+ var RssCreateBase = Schema.Struct({
324
+ type: Schema.Literal("rss"),
325
+ url: Format.URL.annotations({
326
+ title: "URL",
327
+ description: "RSS feed URL."
328
+ }),
329
+ name: Schema.optional(Schema.String.annotations({ title: "Name" }))
330
+ });
331
+ /** Normalizes a create-form union member into the stored {@link Subscription.Subscription} fields. */
332
+ var makeSubscriptionFromCreate = (input) => {
333
+ switch (input.type) {
334
+ case "standard-site": return makeSubscription({
335
+ type: "standard-site",
336
+ url: input.publication
337
+ });
338
+ case "rss": return makeSubscription({
339
+ type: "rss",
340
+ url: input.url,
341
+ name: input.name
342
+ });
343
+ }
344
+ };
345
+ //#endregion
346
+ //#region src/types/Magazine.ts
347
+ var Magazine_exports = /* @__PURE__ */ __exportAll({
348
+ CreateMagazineSchema: () => CreateMagazineSchema,
349
+ CurationOutput: () => CurationOutput,
350
+ DEFAULT_INSTRUCTIONS: () => DEFAULT_INSTRUCTIONS,
351
+ Magazine: () => Magazine,
352
+ PostState: () => PostState,
353
+ SKILL_KEY: () => SKILL_KEY,
354
+ composeInstructions: () => composeInstructions,
355
+ getPostState: () => getPostState,
356
+ getRank: () => getRank,
357
+ instanceOf: () => instanceOf,
358
+ make: () => make,
359
+ patchPostState: () => patchPostState,
360
+ setRank: () => setRank
361
+ });
362
+ var SKILL_KEY = "org.dxos.skill.magazine";
363
+ /**
364
+ * Default editorial methodology seeded into a Magazine's curation Routine. Describes WHAT to curate
365
+ * (selection, dedup, snippet, hero image). The HOW (candidate input shape, tool usage, output
366
+ * contract) lives in the Magazine skill, not here.
367
+ */
368
+ var DEFAULT_INSTRUCTIONS = trim`
369
+ You curate articles for a Magazine around the Topic described below.
370
+
371
+ Select only candidates that clearly match the Topic — quality over quantity.
372
+
373
+ Never select duplicate articles. Two candidates are duplicates if they share a link or guid, or if
374
+ their titles and content describe the same story (e.g. the same article syndicated by different
375
+ feeds). Keep only one of each — prefer the most complete or authoritative source — and skip the rest.
376
+
377
+ For each candidate you select, also produce:
378
+ - A concise 1-2 sentence snippet (plain text, no markdown) capturing why the article is relevant to
379
+ the Topic. If you read the full article, use it to write a richer snippet.
380
+ - The best hero image URL for the article, when one is available.
381
+ `;
382
+ /** Per-Post magazine-scoped curation state, keyed by Post id. */
383
+ var PostState = Schema.Struct({
384
+ /** Agent-assigned relevance within this magazine (lower = more relevant). */
385
+ rank: Schema.optional(Schema.Number),
386
+ /** Agent-written concise snippet summarising the article in the context of this magazine's topic. */
387
+ snippet: Schema.optional(Schema.String),
388
+ /** Agent-selected hero image URL for this post in this magazine. */
389
+ imageUrl: Schema.optional(Schema.String)
390
+ });
391
+ /**
392
+ * Structured output contract of the curation Routine: the Posts the agent selected, each with
393
+ * agent-generated display values. Declared as the Routine's `output` ({@link make}) so the agent's
394
+ * `completeJob` carries this payload (a Void/Unknown default would silently drop it); {@link
395
+ * CurateMagazine} decodes the Routine result against the same schema.
396
+ */
397
+ var CurationOutput = Schema.Struct({ posts: Schema.Array(Schema.Struct({
398
+ id: Obj.ID,
399
+ /** Concise 1-2 sentence snippet summarising why this article is relevant to the magazine topic. */
400
+ snippet: Schema.optional(Schema.String),
401
+ /** Best image URL found for this article (from the post or fetched content). */
402
+ imageUrl: Schema.optional(Schema.String)
403
+ })) });
404
+ /**
405
+ * An agent-curated collection of articles drawn from one or more Feeds.
406
+ * Curation is driven by a {@link Routine.Routine} created with the magazine ({@link make}): its
407
+ * instructions hold the editorial brief and it references the Magazine skill (the tool/output
408
+ * contract). {@link CurateMagazine} runs the Routine to select matching Posts.
409
+ */
410
+ var Magazine = class extends Type.makeObject(DXN.make("org.dxos.type.magazine", "0.2.0"))(Schema.Struct({
411
+ /** User-facing title of the magazine. */
412
+ name: Schema.String.pipe(Schema.optional),
413
+ /** Feeds to pull content from. */
414
+ feeds: Schema.Array(Ref.Ref(Subscription)),
415
+ /** Curated Post refs (insertion order; UI displays newest-last reversed). */
416
+ posts: Schema.Array(Ref.Ref(Post)).pipe(FormInputAnnotation.set(false)),
417
+ /**
418
+ * Curation Instructions, created with the magazine ({@link make}). Holds the editorial brief and
419
+ * references the Magazine skill. Rendered inline by the properties form (the Instructions'
420
+ * own fields), so the brief is edited there without a custom surface.
421
+ * Optional for backward compatibility; {@link CurateMagazine} and the toolbar require it.
422
+ */
423
+ instructions: Ref.Ref(Instructions.Instructions).pipe(FormInlineAnnotation.set(true), Schema.optional),
424
+ /**
425
+ * Per-Post magazine-scoped curation state, keyed by Post id. Shared per-Post state (readAt,
426
+ * star/archive tags) lives on `Subscription`; snippet/imageUrl here are agent-written at
427
+ * curation time and take precedence over the RSS-derived defaults in display.
428
+ */
429
+ postState: Ref.Ref(StateMap.StateMap).pipe(FormInputAnnotation.set(false)),
430
+ /**
431
+ * Maximum number of (non-starred) curated Posts retained on the magazine after curation.
432
+ * Older posts beyond this bound are dropped; starred posts are preserved regardless.
433
+ * Defaults to {@link Subscription.DEFAULT_KEEP} when unset.
434
+ */
435
+ keep: Schema.Number.pipe(Schema.annotations({
436
+ title: "Keep",
437
+ description: "Number of items to keep."
438
+ }), Schema.optional)
439
+ }).pipe(LabelAnnotation.set(["name"]), Annotation.IconAnnotation.set({
440
+ icon: "ph--book-open-text--regular",
441
+ hue: "indigo"
442
+ }), AppAnnotation.SkillsAnnotation.set([SKILL_KEY]))) {};
443
+ /** Checks if a value is a Magazine object. */
444
+ var instanceOf = (value) => Obj.instanceOf(Magazine, value);
445
+ /**
446
+ * Creates a Magazine plus its curation Routine and per-Post state map as hidden children (all
447
+ * cascade-deleted with the magazine). The Routine holds the editorial brief (its instructions,
448
+ * seeded from {@link composeInstructions}) and references the Magazine skill by its registry DXN;
449
+ * {@link CurateMagazine} runs it and the agent resolves the skill at run time.
450
+ */
451
+ var make = (props = {}) => {
452
+ const postState = StateMap.make();
453
+ const magazine = Obj.make(Magazine, {
454
+ name: props.name,
455
+ feeds: props.feeds ?? [],
456
+ posts: props.posts ?? [],
457
+ keep: props.keep,
458
+ postState: Ref.make(postState)
459
+ });
460
+ const instructions = Instructions.make({
461
+ name: props.name ? `${props.name} curation` : "Magazine curation",
462
+ text: composeInstructions(props.instructions),
463
+ skills: [Ref.fromURI(Skill.registryURI(SKILL_KEY))],
464
+ objects: [Ref.make(magazine)],
465
+ output: CurationOutput
466
+ });
467
+ Obj.update(magazine, (magazine) => {
468
+ magazine.instructions = Ref.make(instructions);
469
+ });
470
+ Obj.setParent(instructions, magazine);
471
+ if (instructions.text.target) Obj.setParent(instructions.text.target, instructions);
472
+ Obj.setParent(postState, magazine);
473
+ return magazine;
474
+ };
475
+ /** Composes Routine instructions from the default editorial methodology and an optional topic focus. */
476
+ var composeInstructions = (topic) => {
477
+ const trimmed = topic?.trim();
478
+ return trimmed ? `${DEFAULT_INSTRUCTIONS}\n\n## Topic\n\n${trimmed}` : DEFAULT_INSTRUCTIONS;
479
+ };
480
+ /** Schema for the create-magazine dialog form. */
481
+ var CreateMagazineSchema = Schema.Struct({
482
+ name: Schema.optional(Schema.String.annotations({ title: "Name" })),
483
+ feeds: Schema.Array(Ref.Ref(Subscription)).annotations({ title: "Feeds" }),
484
+ instructions: Schema.optional(Schema.String.annotations({
485
+ title: "Topic",
486
+ description: "Describe what content to curate."
487
+ }))
488
+ });
489
+ /** Agent-assigned relevance of a Post within a Magazine, or undefined. */
490
+ var getRank = (magazine, postId) => {
491
+ const stateMap = magazine?.postState.target;
492
+ return stateMap ? StateMap.bind(stateMap).get(postId).rank : void 0;
493
+ };
494
+ /** Returns the full magazine-scoped {@link PostState} for a Post, or an empty record. */
495
+ var getPostState = (magazine, postId) => {
496
+ const stateMap = magazine?.postState.target;
497
+ return stateMap ? StateMap.bind(stateMap).get(postId) : {};
498
+ };
499
+ /** Merges partial state into a Post's magazine-scoped {@link PostState}. */
500
+ var patchPostState = (magazine, postId, state) => {
501
+ const stateMap = magazine.postState.target;
502
+ if (stateMap) StateMap.bind(stateMap).patch(postId, state);
503
+ };
504
+ /** Sets the magazine-scoped rank for a Post. */
505
+ var setRank = (magazine, postId, rank) => patchPostState(magazine, postId, { rank });
506
+ //#endregion
507
+ //#region src/types/FeedOperation.ts
508
+ var FeedOperation_exports = /* @__PURE__ */ __exportAll({
509
+ ClearMagazine: () => ClearMagazine,
510
+ CurateMagazine: () => CurateMagazine,
511
+ FetchArticleContent: () => FetchArticleContent,
512
+ LoadPostContent: () => LoadPostContent,
513
+ SyncFeed: () => SyncFeed
514
+ });
515
+ var makeKey = (name) => DXN.make(`${meta.profile.key}.operation.${name}`);
516
+ /** Fetches an RSS/Atom feed and appends new posts to the backing ECHO feed. */
517
+ var SyncFeed = Operation.make({
518
+ meta: {
519
+ key: makeKey("syncFeed"),
520
+ name: "Sync Feed",
521
+ description: "Fetches RSS/Atom feed and writes posts to the ECHO feed.",
522
+ icon: "ph--arrows-clockwise--regular"
523
+ },
524
+ services: [Database.Service],
525
+ input: Schema.Struct({ feed: Ref.Ref(Subscription) }),
526
+ output: Schema.Void
527
+ }).pipe(Operation.visible);
528
+ /**
529
+ * Fetches a Post's article page over HTTP and returns extracted plain text plus
530
+ * any image URLs found. Read-only; does not mutate the Post. Agent-facing tool
531
+ * (the surviving curation tool: the agent may call it to read a candidate's full
532
+ * text when title + description are insufficient to judge relevance).
533
+ */
534
+ var FetchArticleContent = Operation.make({
535
+ meta: {
536
+ key: makeKey("fetchArticleContent"),
537
+ name: "Fetch Article Content",
538
+ description: "Fetches and extracts text + image URLs from a Post's article page.",
539
+ icon: "ph--article--regular"
540
+ },
541
+ input: Schema.Struct({ post: Ref.Ref(Post).annotations({ description: "The Post to fetch content for. The Post must have a link." }) }),
542
+ output: Schema.Struct({
543
+ text: Schema.String.annotations({ description: "Extracted plain text from the article page." }),
544
+ imageUrls: Schema.Array(Schema.String).annotations({ description: "Image URLs found on the page (og:image first, then <img> src values)." })
545
+ }),
546
+ services: [Database.Service]
547
+ });
548
+ /**
549
+ * Fetches a Post's article page over HTTP and writes the extracted plain text
550
+ * and hero image URL to the source Subscription's content feed. Per-Post read/star/archive
551
+ * state on the Subscription is keyed by Post entity id.
552
+ * (the Post itself is an immutable queue item). Idempotent — skips if
553
+ * `content` is already set or the Post has no link. Used by the reader view
554
+ * to populate the full article on first open.
555
+ */
556
+ var LoadPostContent = Operation.make({
557
+ meta: {
558
+ key: makeKey("loadPostContent"),
559
+ name: "Load Post Content",
560
+ description: "Fetches and stores the full article content on a Post.",
561
+ icon: "ph--download--regular"
562
+ },
563
+ input: Schema.Struct({
564
+ post: Ref.Ref(Post).annotations({ description: "The Post to load content for." }),
565
+ force: Schema.optional(Schema.Boolean.annotations({ description: "Re-fetch and append fresh content even if an entry already exists (refresh)." }))
566
+ }),
567
+ output: Schema.Void
568
+ });
569
+ /**
570
+ * End-to-end magazine curation: syncs all referenced feeds (in parallel), then runs an in-memory
571
+ * routine (the magazine's topic instructions + the registry-resolved Magazine skill) through the
572
+ * agent to select matching posts, adds the selected posts mechanically, and finally enforces each
573
+ * feed's `keep` bound. Drives the MagazineArticle Curate button; schedulable via triggers.
574
+ */
575
+ var CurateMagazine = Operation.make({
576
+ meta: {
577
+ key: makeKey("curateMagazine"),
578
+ name: "Curate Magazine",
579
+ description: "Syncs feeds, selects matching posts via the magazine skill, and applies per-feed keep limits.",
580
+ icon: "ph--sparkle--regular"
581
+ },
582
+ input: Schema.Struct({ magazine: Ref.Ref(Magazine).annotations({ description: "The Magazine to curate." }) }),
583
+ output: Schema.Struct({
584
+ synced: Schema.Number.annotations({ description: "Number of feeds successfully synced." }),
585
+ curated: Schema.Number.annotations({ description: "Number of posts added to the magazine." })
586
+ }),
587
+ services: [Database.Service, Registry.Service]
588
+ }).pipe(Operation.visible);
589
+ /**
590
+ * Clears a Magazine's curated posts, preserving any that are starred. Drives the MagazineArticle
591
+ * Clear button.
592
+ */
593
+ var ClearMagazine = Operation.make({
594
+ meta: {
595
+ key: makeKey("clearMagazine"),
596
+ name: "Clear Magazine",
597
+ description: "Removes a Magazine's posts, keeping any that are starred.",
598
+ icon: "ph--trash--regular"
599
+ },
600
+ input: Schema.Struct({ magazine: Ref.Ref(Magazine).annotations({ description: "The Magazine to clear." }) }),
601
+ output: Schema.Void,
602
+ services: [Database.Service]
603
+ }).pipe(Operation.visible);
604
+ //#endregion
605
+ export { hasTag as _, LoadPostContent as a, __exportAll as b, Magazine_exports as c, Post as d, SYSTEM_TAGS as f, findSystemTagUri as g, findPostContent as h, FetchArticleContent as i, patchPostState as l, appendPostContent as m, CurateMagazine as n, SyncFeed as o, Subscription_exports as p, FeedOperation_exports as r, CurationOutput as s, ClearMagazine as t, CreateSubscription_exports as u, pickLatestPostContent as v, queryPostContentForPost as y };
606
+
607
+ //# sourceMappingURL=chunk-types.mjs.map