mulmoclaude 0.3.0 → 0.5.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 (312) hide show
  1. package/bin/mulmoclaude.js +7 -24
  2. package/client/assets/html2canvas-Cx501zZr-DiKaqnKs.js +5 -0
  3. package/client/assets/{index-eHWB79u5.js → index-C94GcmNa.js} +203 -198
  4. package/client/assets/index-CY-WpQUm.css +2 -0
  5. package/client/assets/{index.es-D4YyL_Dg-BfRHLTZV.js → index.es-D4YyL_Dg-5ipqh8Pe.js} +5 -5
  6. package/client/assets/material-symbols-outlined-NzYEeyps.woff2 +0 -0
  7. package/client/index.html +2 -4
  8. package/package.json +17 -15
  9. package/server/agent/attachmentConverter.ts +2 -2
  10. package/server/agent/backend/claude-code.ts +170 -0
  11. package/server/agent/backend/index.ts +14 -0
  12. package/server/agent/backend/types.ts +65 -0
  13. package/server/agent/index.ts +31 -159
  14. package/server/agent/mcp-server.ts +88 -10
  15. package/server/agent/mcp-tools/index.ts +8 -7
  16. package/server/agent/mcp-tools/notify.ts +76 -0
  17. package/server/agent/mcp-tools/x.ts +12 -2
  18. package/server/agent/plugin-names.ts +10 -4
  19. package/server/agent/prompt.ts +187 -26
  20. package/server/agent/resumeFailover.ts +5 -5
  21. package/server/agent/sandboxMounts.ts +3 -3
  22. package/server/api/auth/bearerAuth.ts +3 -3
  23. package/server/api/auth/token.ts +2 -2
  24. package/server/api/routes/agent.ts +99 -4
  25. package/server/api/routes/chart.ts +13 -0
  26. package/server/api/routes/chat-index.ts +2 -1
  27. package/server/api/routes/config.ts +35 -8
  28. package/server/api/routes/files.ts +75 -24
  29. package/server/api/routes/html.ts +15 -2
  30. package/server/api/routes/image.ts +75 -20
  31. package/server/api/routes/mulmo-script.ts +33 -31
  32. package/server/api/routes/news.ts +146 -0
  33. package/server/api/routes/notifications.ts +58 -2
  34. package/server/api/routes/pdf.ts +2 -2
  35. package/server/api/routes/plugins.ts +73 -91
  36. package/server/api/routes/presentHtml.ts +9 -0
  37. package/server/api/routes/roles.ts +12 -2
  38. package/server/api/routes/scheduler.ts +20 -11
  39. package/server/api/routes/schedulerTasks.ts +58 -21
  40. package/server/api/routes/sessions.ts +15 -4
  41. package/server/api/routes/sessionsCursor.ts +4 -4
  42. package/server/api/routes/skills.ts +26 -5
  43. package/server/api/routes/sources.ts +8 -7
  44. package/server/api/routes/todos.ts +30 -0
  45. package/server/api/routes/todosColumnsHandlers.ts +13 -27
  46. package/server/api/routes/todosHandlers.ts +1 -1
  47. package/server/api/routes/todosItemsHandlers.ts +14 -14
  48. package/server/api/routes/wiki/frontmatter.ts +86 -0
  49. package/server/api/routes/wiki.ts +335 -75
  50. package/server/api/sandboxStatus.ts +1 -1
  51. package/server/events/notifications.ts +32 -8
  52. package/server/events/pub-sub/index.ts +3 -3
  53. package/server/events/relay-client.ts +26 -16
  54. package/server/events/resolveRelayBridgeOptions.ts +125 -0
  55. package/server/index.ts +72 -49
  56. package/server/system/config.ts +5 -5
  57. package/server/system/credentials.ts +7 -5
  58. package/server/system/env.ts +15 -5
  59. package/server/system/macosNotify.ts +152 -0
  60. package/server/utils/errors.ts +11 -2
  61. package/server/utils/fetch.ts +54 -0
  62. package/server/utils/files/atomic.ts +18 -17
  63. package/server/utils/files/image-store.ts +19 -13
  64. package/server/utils/files/journal-io.ts +2 -2
  65. package/server/utils/files/json.ts +5 -5
  66. package/server/utils/files/markdown-image-fill.ts +131 -0
  67. package/server/utils/files/markdown-store.ts +22 -6
  68. package/server/utils/files/naming.ts +20 -10
  69. package/server/utils/files/reference-dirs-io.ts +3 -3
  70. package/server/utils/files/roles-io.ts +4 -4
  71. package/server/utils/files/safe.ts +14 -14
  72. package/server/utils/files/scheduler-overrides-io.ts +2 -2
  73. package/server/utils/files/spreadsheet-store.ts +15 -10
  74. package/server/utils/files/workspace-io.ts +12 -12
  75. package/server/utils/gemini.ts +30 -4
  76. package/server/utils/gitignore.ts +9 -9
  77. package/server/utils/id.ts +40 -8
  78. package/server/utils/json.ts +5 -5
  79. package/server/utils/logBackgroundError.ts +12 -3
  80. package/server/utils/logPreview.ts +24 -0
  81. package/server/utils/markdown.ts +5 -5
  82. package/server/utils/port.d.mts +6 -0
  83. package/server/utils/port.mjs +48 -0
  84. package/server/utils/promptMeta.ts +32 -0
  85. package/server/utils/request.ts +12 -6
  86. package/server/utils/slug.ts +65 -4
  87. package/server/utils/spawn.ts +1 -1
  88. package/server/utils/types.ts +2 -2
  89. package/server/workspace/chat-index/index.ts +1 -1
  90. package/server/workspace/chat-index/summarizer.ts +5 -5
  91. package/server/workspace/custom-dirs.ts +5 -5
  92. package/server/workspace/helps/gemini.md +57 -0
  93. package/server/workspace/helps/index.md +2 -1
  94. package/server/workspace/helps/sources.md +42 -0
  95. package/server/workspace/helps/wiki.md +40 -5
  96. package/server/workspace/journal/archivist-cli.ts +121 -0
  97. package/server/workspace/journal/{archivist.ts → archivist-schemas.ts} +12 -120
  98. package/server/workspace/journal/dailyPass.ts +78 -38
  99. package/server/workspace/journal/diff.ts +2 -2
  100. package/server/workspace/journal/index.ts +56 -5
  101. package/server/workspace/journal/memoryExtractor.ts +1 -1
  102. package/server/workspace/journal/optimizationPass.ts +4 -5
  103. package/server/workspace/journal/paths.ts +8 -24
  104. package/server/workspace/journal/state.ts +18 -8
  105. package/server/workspace/news/reader.ts +248 -0
  106. package/server/workspace/paths.ts +4 -3
  107. package/server/workspace/reference-dirs.ts +3 -3
  108. package/server/workspace/skills/parser.ts +6 -6
  109. package/server/workspace/skills/scheduler.ts +5 -4
  110. package/server/workspace/skills/user-tasks.ts +3 -2
  111. package/server/workspace/skills/writer.ts +3 -3
  112. package/server/workspace/sources/arxivDiscovery.ts +2 -2
  113. package/server/workspace/sources/classifier.ts +1 -1
  114. package/server/workspace/sources/fetchers/rss.ts +5 -5
  115. package/server/workspace/sources/fetchers/rssParser.ts +4 -4
  116. package/server/workspace/sources/interests.ts +3 -3
  117. package/server/workspace/sources/paths.ts +6 -6
  118. package/server/workspace/sources/pipeline/fetch.ts +59 -13
  119. package/server/workspace/sources/pipeline/index.ts +59 -7
  120. package/server/workspace/sources/pipeline/notify.ts +13 -5
  121. package/server/workspace/sources/pipeline/plan.ts +11 -9
  122. package/server/workspace/sources/pipeline/summarize.ts +1 -1
  123. package/server/workspace/sources/pipeline/write.ts +5 -5
  124. package/server/workspace/sources/rateLimiter.ts +1 -1
  125. package/server/workspace/sources/sourceState.ts +9 -4
  126. package/server/workspace/sources/types.ts +9 -0
  127. package/server/workspace/sources/urls.ts +1 -1
  128. package/server/workspace/tool-trace/classify.ts +4 -4
  129. package/server/workspace/workspace.ts +7 -7
  130. package/src/App.vue +477 -251
  131. package/src/components/CanvasViewToggle.vue +12 -10
  132. package/src/components/ChatInput.vue +112 -105
  133. package/src/components/FileContentHeader.vue +10 -7
  134. package/src/components/FileContentRenderer.vue +37 -10
  135. package/src/components/FileTree.vue +34 -4
  136. package/src/components/FileTreePane.vue +32 -27
  137. package/src/components/FilesView.vue +5 -3
  138. package/src/components/FilterChip.vue +22 -0
  139. package/src/components/LockStatusPopup.vue +19 -13
  140. package/src/components/NewsView.vue +252 -0
  141. package/src/components/NotificationBell.vue +35 -9
  142. package/src/components/NotificationToast.vue +4 -1
  143. package/src/components/PageChatComposer.vue +101 -0
  144. package/src/components/PluginLauncher.vue +36 -62
  145. package/src/components/RightSidebar.vue +13 -10
  146. package/src/components/RoleSelector.vue +3 -2
  147. package/src/components/SessionHeaderControls.vue +63 -0
  148. package/src/components/SessionHistoryExpandButton.vue +30 -0
  149. package/src/components/SessionHistoryPanel.vue +64 -93
  150. package/src/components/SessionHistoryToggleButton.vue +40 -0
  151. package/src/components/SessionRoleIcon.vue +72 -0
  152. package/src/components/SessionSidebar.vue +96 -0
  153. package/src/components/SessionTabBar.vue +44 -51
  154. package/src/components/SettingsMcpTab.vue +361 -52
  155. package/src/components/SettingsModal.vue +203 -72
  156. package/src/components/SettingsReferenceDirsTab.vue +72 -51
  157. package/src/components/SettingsWorkspaceDirsTab.vue +74 -51
  158. package/src/components/SidebarHeader.vue +50 -16
  159. package/src/components/SourcesManager.vue +900 -0
  160. package/src/components/SourcesView.vue +45 -0
  161. package/src/components/StackView.vue +84 -48
  162. package/src/components/SuggestionsPanel.vue +25 -36
  163. package/src/components/SystemFileBanner.vue +106 -0
  164. package/src/components/ThinkingIndicator.vue +41 -0
  165. package/src/components/TodoExplorer.vue +72 -22
  166. package/src/components/todo/TodoAddDialog.vue +17 -12
  167. package/src/components/todo/TodoEditDialog.vue +7 -2
  168. package/src/components/todo/TodoEditPanel.vue +15 -10
  169. package/src/components/todo/TodoKanbanView.vue +16 -6
  170. package/src/components/todo/TodoListView.vue +14 -3
  171. package/src/components/todo/TodoTableView.vue +36 -5
  172. package/src/composables/favicon/conditions.ts +76 -0
  173. package/src/composables/favicon/resolveColor.ts +93 -0
  174. package/src/composables/favicon/types.ts +61 -0
  175. package/src/composables/useAppApi.ts +23 -0
  176. package/src/composables/useChatScroll.ts +5 -5
  177. package/src/composables/useCurrentRole.ts +32 -0
  178. package/src/composables/useDynamicFavicon.ts +174 -58
  179. package/src/composables/useEventListeners.ts +7 -12
  180. package/src/composables/useFaviconState.ts +93 -12
  181. package/src/composables/useFileSelection.ts +25 -6
  182. package/src/composables/useHealth.ts +76 -7
  183. package/src/composables/useLayoutMode.ts +27 -0
  184. package/src/composables/useNewsItems.ts +38 -0
  185. package/src/composables/useNewsReadState.ts +75 -0
  186. package/src/composables/useNotifications.ts +76 -13
  187. package/src/composables/usePendingCalls.ts +11 -1
  188. package/src/composables/useRoles.ts +6 -10
  189. package/src/composables/useRunElapsed.ts +80 -0
  190. package/src/composables/useSessionDerived.ts +21 -5
  191. package/src/composables/useSessionHistory.ts +7 -17
  192. package/src/composables/useSidePanelVisible.ts +25 -0
  193. package/src/composables/useViewLayout.ts +16 -37
  194. package/src/config/apiRoutes.ts +19 -6
  195. package/src/config/historyFilters.ts +30 -0
  196. package/src/config/mcpCatalog.ts +285 -0
  197. package/src/config/mcpTypes.ts +26 -0
  198. package/src/config/roles.ts +19 -51
  199. package/src/config/systemFileDescriptors.ts +170 -0
  200. package/src/config/toolNames.ts +6 -1
  201. package/src/config/workspacePaths.ts +1 -0
  202. package/src/index.css +14 -0
  203. package/src/lang/de.ts +706 -0
  204. package/src/lang/en.ts +726 -0
  205. package/src/lang/es.ts +712 -0
  206. package/src/lang/fr.ts +704 -0
  207. package/src/lang/ja.ts +707 -0
  208. package/src/lang/ko.ts +709 -0
  209. package/src/lang/pt-BR.ts +702 -0
  210. package/src/lang/zh.ts +705 -0
  211. package/src/lib/vue-i18n.ts +97 -0
  212. package/src/main.ts +3 -0
  213. package/src/plugins/canvas/View.vue +104 -186
  214. package/src/plugins/canvas/definition.ts +0 -8
  215. package/src/plugins/canvas/index.ts +3 -2
  216. package/src/plugins/chart/Preview.vue +1 -1
  217. package/src/plugins/chart/View.vue +9 -4
  218. package/src/plugins/chart/index.ts +3 -2
  219. package/src/plugins/editImage/index.ts +3 -2
  220. package/src/plugins/generateImage/index.ts +3 -2
  221. package/src/plugins/manageRoles/Preview.vue +4 -1
  222. package/src/plugins/manageRoles/View.vue +67 -46
  223. package/src/plugins/manageRoles/index.ts +3 -2
  224. package/src/plugins/manageSkills/Preview.vue +8 -3
  225. package/src/plugins/manageSkills/View.vue +39 -34
  226. package/src/plugins/manageSkills/index.ts +3 -2
  227. package/src/plugins/manageSource/Preview.vue +1 -1
  228. package/src/plugins/manageSource/View.vue +3 -687
  229. package/src/plugins/manageSource/index.ts +3 -2
  230. package/src/plugins/markdown/Preview.vue +1 -1
  231. package/src/plugins/markdown/View.vue +164 -73
  232. package/src/plugins/markdown/definition.ts +6 -4
  233. package/src/plugins/markdown/index.ts +3 -2
  234. package/src/plugins/presentForm/Preview.vue +99 -0
  235. package/src/plugins/presentForm/View.vue +675 -0
  236. package/src/plugins/presentForm/definition.ts +127 -0
  237. package/src/plugins/presentForm/index.ts +18 -0
  238. package/src/plugins/presentForm/plugin.ts +94 -0
  239. package/src/plugins/presentForm/types.ts +109 -0
  240. package/src/plugins/presentHtml/Preview.vue +1 -1
  241. package/src/plugins/presentHtml/View.vue +7 -4
  242. package/src/plugins/presentHtml/index.ts +3 -2
  243. package/src/plugins/presentMulmoScript/Preview.vue +1 -1
  244. package/src/plugins/presentMulmoScript/View.vue +36 -26
  245. package/src/plugins/presentMulmoScript/index.ts +3 -2
  246. package/src/plugins/scheduler/AutomationsPreview.vue +37 -0
  247. package/src/plugins/scheduler/AutomationsView.vue +23 -0
  248. package/src/plugins/scheduler/CalendarView.vue +23 -0
  249. package/src/plugins/scheduler/LegacySchedulerView.vue +32 -0
  250. package/src/plugins/scheduler/Preview.vue +7 -4
  251. package/src/plugins/scheduler/TasksTab.vue +119 -28
  252. package/src/plugins/scheduler/View.vue +75 -32
  253. package/src/plugins/scheduler/automationsDefinition.ts +58 -0
  254. package/src/plugins/scheduler/calendarDefinition.ts +46 -0
  255. package/src/plugins/scheduler/formatSchedule.ts +93 -0
  256. package/src/plugins/scheduler/index.ts +68 -14
  257. package/src/plugins/scheduler/legacyShape.ts +34 -0
  258. package/src/plugins/spreadsheet/Preview.vue +9 -5
  259. package/src/plugins/spreadsheet/View.vue +43 -57
  260. package/src/plugins/spreadsheet/engine/responseDecoder.ts +2 -1
  261. package/src/plugins/spreadsheet/index.ts +3 -2
  262. package/src/plugins/textResponse/Preview.vue +15 -58
  263. package/src/plugins/textResponse/View.vue +42 -45
  264. package/src/plugins/textResponse/utils.ts +25 -0
  265. package/src/plugins/todo/Preview.vue +11 -6
  266. package/src/plugins/todo/View.vue +27 -13
  267. package/src/plugins/todo/composables/useTodos.ts +3 -1
  268. package/src/plugins/todo/index.ts +3 -2
  269. package/src/plugins/ui-image/ImagePreview.vue +6 -3
  270. package/src/plugins/ui-image/ImageView.vue +7 -4
  271. package/src/plugins/wiki/Preview.vue +5 -2
  272. package/src/plugins/wiki/View.vue +539 -92
  273. package/src/plugins/wiki/index.ts +5 -2
  274. package/src/plugins/wiki/route.ts +121 -0
  275. package/src/router/guards.ts +43 -24
  276. package/src/router/index.ts +53 -26
  277. package/src/router/pageRoutes.ts +23 -0
  278. package/src/tools/index.ts +12 -5
  279. package/src/tools/legacyPluginNames.ts +13 -0
  280. package/src/types/notification.ts +31 -6
  281. package/src/types/vue-i18n.d.ts +20 -0
  282. package/src/utils/agent/eventDispatch.ts +3 -6
  283. package/src/utils/agent/formatElapsed.ts +37 -0
  284. package/src/utils/agent/request.ts +22 -1
  285. package/src/utils/canvas/layoutMode.ts +26 -0
  286. package/src/utils/canvas/sidePanelVisible.ts +19 -0
  287. package/src/utils/dom/scrollIntoViewByTestId.ts +38 -0
  288. package/src/utils/errors.ts +9 -2
  289. package/src/utils/files/filename.ts +24 -0
  290. package/src/utils/filesPreview/schedulerPreview.ts +9 -3
  291. package/src/utils/id.ts +18 -0
  292. package/src/utils/image/cacheBust.ts +16 -0
  293. package/src/utils/image/resolve.ts +16 -0
  294. package/src/utils/markdown/taskList.ts +175 -0
  295. package/src/utils/mcp/interpolateSpec.ts +97 -0
  296. package/src/utils/notification/dispatch.ts +51 -15
  297. package/src/utils/path/workspaceLinkRouter.ts +99 -0
  298. package/src/utils/session/mergeSessions.ts +5 -0
  299. package/src/utils/sources/filter.ts +69 -0
  300. package/src/vite-env.d.ts +9 -0
  301. package/client/assets/chunk-vKJrgz-R-C_I3GbVV.js +0 -1
  302. package/client/assets/html2canvas-Cx501zZr-BF5dYYkY.js +0 -5
  303. package/client/assets/index-Bm70FDU2.css +0 -1
  304. package/client/assets/typeof-DBp4T-Ny-BC0P-2DM.js +0 -1
  305. package/server/workspace/journal/linkRewrite.ts +0 -4
  306. package/src/components/ToolResultsPanel.vue +0 -77
  307. package/src/composables/useCanvasViewMode.ts +0 -121
  308. package/src/plugins/scheduler/definition.ts +0 -57
  309. package/src/utils/canvas/viewMode.ts +0 -46
  310. package/src/utils/role/plugins.ts +0 -12
  311. package/src/utils/session/seedRoleDefault.ts +0 -35
  312. /package/client/assets/{purify.es-Fx1Nqyry-PeS5RUhs.js → purify.es-Fx1Nqyry-BwJECkqS.js} +0 -0
@@ -1,44 +1,25 @@
1
- // View-layout state: tracks whether the app is in a "stack" layout
2
- // (full-width canvas) or "single" (sidebar + canvas), remembers the
3
- // last chat-oriented view mode, and derives displayedCurrentSessionId
4
- // (blank in plugin views so no tab appears "current").
5
-
6
- import { computed, ref, watch, type ComputedRef, type Ref } from "vue";
7
- import { CANVAS_VIEW, type CanvasViewMode } from "../utils/canvas/viewMode";
8
-
9
- const CHAT_VIEWS = [CANVAS_VIEW.single, CANVAS_VIEW.stack] as const;
10
- type ChatViewMode = (typeof CHAT_VIEWS)[number];
11
-
12
- function isChatView(mode: string): mode is ChatViewMode {
13
- return (CHAT_VIEWS as readonly string[]).includes(mode);
14
- }
1
+ // View-layout state. Derives one value the template cares about:
2
+ //
3
+ // - isStackLayout: true whenever the canvas column should be full-width
4
+ // (no sidebar). This is the case for /chat in stack mode AND for
5
+ // every non-chat page (/files, /todos, /wiki, etc.). Only /chat in
6
+ // single mode shows the left sidebar.
7
+ //
8
+ // Also flips activePane between "sidebar" and "main" so arrow-key
9
+ // navigation follows whichever side of the layout is visible.
10
+
11
+ import { computed, watch, type ComputedRef, type Ref } from "vue";
12
+ import { LAYOUT_MODES, type LayoutMode } from "../utils/canvas/layoutMode";
15
13
 
16
14
  export function useViewLayout(opts: {
17
- canvasViewMode: Ref<CanvasViewMode> | ComputedRef<CanvasViewMode>;
18
- setCanvasViewMode: (mode: CanvasViewMode) => void;
19
- currentSessionId: Ref<string>;
15
+ layoutMode: Ref<LayoutMode> | ComputedRef<LayoutMode>;
16
+ isChatPage: Ref<boolean> | ComputedRef<boolean>;
20
17
  activePane: Ref<"sidebar" | "main">;
21
18
  }) {
22
- const { canvasViewMode, setCanvasViewMode, currentSessionId, activePane } = opts;
23
-
24
- const isStackLayout = computed(() => canvasViewMode.value !== CANVAS_VIEW.single);
25
-
26
- const lastChatViewMode = ref<ChatViewMode>(isChatView(canvasViewMode.value) ? canvasViewMode.value : CANVAS_VIEW.stack);
27
-
28
- watch(canvasViewMode, (mode) => {
29
- if (isChatView(mode)) lastChatViewMode.value = mode;
30
- });
31
-
32
- function restoreChatViewForSession(): void {
33
- if (!isChatView(canvasViewMode.value)) {
34
- setCanvasViewMode(lastChatViewMode.value);
35
- }
36
- }
19
+ const { layoutMode, isChatPage, activePane } = opts;
37
20
 
38
- const displayedCurrentSessionId = computed(() => (isChatView(canvasViewMode.value) ? currentSessionId.value : ""));
21
+ const isStackLayout = computed(() => !(isChatPage.value && layoutMode.value === LAYOUT_MODES.single));
39
22
 
40
- // Keep arrow-key navigation tied to the canvas when the sidebar
41
- // list doesn't exist (Stack layout has no ToolResultsPanel).
42
23
  watch(
43
24
  isStackLayout,
44
25
  (stack) => {
@@ -49,7 +30,5 @@ export function useViewLayout(opts: {
49
30
 
50
31
  return {
51
32
  isStackLayout,
52
- restoreChatViewForSession,
53
- displayedCurrentSessionId,
54
33
  };
55
34
  }
@@ -12,7 +12,7 @@
12
12
  // **Express params**: patterns like `:id` / `:filename` are kept as
13
13
  // Express-compatible strings. Client-side URL builders (e.g. a
14
14
  // `todoItem(id)` helper) are deliberately NOT added here until the
15
- // frontend migration lands — see plans/refactor-api-routes-constants.md.
15
+ // frontend migration lands — see plans/done/refactor-api-routes-constants.md.
16
16
  //
17
17
  // **Adding a new endpoint**: add it here first, then reference the
18
18
  // constant from the router file. Keep the nesting shallow and the
@@ -41,7 +41,7 @@ export const API_ROUTES = {
41
41
  rebuild: "/api/chat-index/rebuild",
42
42
  },
43
43
 
44
- // Single source of truth: @mulmobridge/protocol. See plans/messaging_transports.md.
44
+ // Single source of truth: @mulmobridge/protocol. See plans/done/messaging_transports.md.
45
45
  chatService: CHAT_SERVICE_ROUTES,
46
46
 
47
47
  config: {
@@ -71,7 +71,10 @@ export const API_ROUTES = {
71
71
  generate: "/api/generate-image",
72
72
  edit: "/api/edit-image",
73
73
  upload: "/api/images",
74
- update: "/api/images/:filename",
74
+ // Body carries the workspace-relative path so the route doesn't
75
+ // have to reconstruct one from a basename — required after #764
76
+ // sharded image storage by YYYY/MM.
77
+ update: "/api/images/update",
75
78
  },
76
79
 
77
80
  mcpTools: {
@@ -81,7 +84,7 @@ export const API_ROUTES = {
81
84
 
82
85
  notifications: {
83
86
  // PoC endpoint for scheduled push fan-out (Web pub-sub + bridge).
84
- // Scaffolding for #144 / #142 — see plans/feat-notification-push-scaffold.md.
87
+ // Scaffolding for #144 / #142 — see plans/done/feat-notification-push-scaffold.md.
85
88
  test: "/api/notifications/test",
86
89
  },
87
90
 
@@ -110,9 +113,13 @@ export const API_ROUTES = {
110
113
  // Names match the plugin tool name or the short verb the plugin uses.
111
114
  plugins: {
112
115
  presentDocument: "/api/present-document",
113
- updateMarkdown: "/api/markdowns/:filename",
116
+ // Body carries the workspace-relative path so the route doesn't
117
+ // have to reconstruct one from a basename — required after #764
118
+ // sharded artifact storage by YYYY/MM. Same shape as
119
+ // image.update.
120
+ updateMarkdown: "/api/markdowns/update",
114
121
  presentSpreadsheet: "/api/present-spreadsheet",
115
- updateSpreadsheet: "/api/spreadsheets/:filename",
122
+ updateSpreadsheet: "/api/spreadsheets/update",
116
123
  mindmap: "/api/mindmap",
117
124
  quiz: "/api/quiz",
118
125
  form: "/api/form",
@@ -156,6 +163,12 @@ export const API_ROUTES = {
156
163
  manage: "/api/sources/manage",
157
164
  },
158
165
 
166
+ news: {
167
+ items: "/api/news/items",
168
+ itemBody: "/api/news/items/:id/body",
169
+ readState: "/api/news/read-state",
170
+ },
171
+
159
172
  todos: {
160
173
  list: "/api/todos",
161
174
  dispatch: "/api/todos",
@@ -0,0 +1,30 @@
1
+ // Filter keys for the session-history panel. Kept here (not in
2
+ // `types/session.ts`) because `all` and `unread` are UI concepts — not
3
+ // session-origin values — even though the four origin filters reuse
4
+ // `SESSION_ORIGINS` verbatim so a single source of truth stays per
5
+ // concept.
6
+
7
+ import { SESSION_ORIGINS } from "../types/session";
8
+
9
+ export const HISTORY_FILTERS = {
10
+ all: "all",
11
+ unread: "unread",
12
+ human: SESSION_ORIGINS.human,
13
+ scheduler: SESSION_ORIGINS.scheduler,
14
+ skill: SESSION_ORIGINS.skill,
15
+ bridge: SESSION_ORIGINS.bridge,
16
+ } as const;
17
+
18
+ export type HistoryFilter = (typeof HISTORY_FILTERS)[keyof typeof HISTORY_FILTERS];
19
+
20
+ // Display order for the pill row. `all` is always first; `unread` sits
21
+ // between `all` and the origin filters to mirror the existing
22
+ // hand-written order in SessionHistoryPanel.
23
+ export const HISTORY_FILTER_ORDER: readonly HistoryFilter[] = [
24
+ HISTORY_FILTERS.all,
25
+ HISTORY_FILTERS.unread,
26
+ HISTORY_FILTERS.human,
27
+ HISTORY_FILTERS.scheduler,
28
+ HISTORY_FILTERS.skill,
29
+ HISTORY_FILTERS.bridge,
30
+ ] as const;
@@ -0,0 +1,285 @@
1
+ // Curated catalog of pre-configured MCP servers (#823 Phases 1+2).
2
+ //
3
+ // Goal: a checkbox toggle in Settings → MCP tab that installs / removes
4
+ // a known-good server with sane defaults. The general user shouldn't
5
+ // have to read a README to wire up Memory or a calendar.
6
+ //
7
+ // Phase 1 (#825) shipped 2 config-free entries (Memory / Sequential
8
+ // Thinking) — Apple-native / Screenshot were explored but dropped
9
+ // at merge because no community package was stable enough to pin.
10
+ // Phase 2 adds 6 more in the docs / info-gathering / general-task
11
+ // buckets and wires up the per-server config form (api keys, paths,
12
+ // etc.) — fields described by `configSchema` are interpolated into
13
+ // the spec template at install time via `interpolateMcpSpec`.
14
+ //
15
+ // Selection criteria:
16
+ // - 🟢 catalogue value > Claude Code built-in coverage
17
+ // Built-ins (`Read` / `Write` / `Edit` / `WebFetch` / `WebSearch` /
18
+ // `Bash`) already cover filesystem, fetch, and search; entries
19
+ // duplicating those are out (#823 §"価値マトリクス").
20
+ // - safe defaults: no auth required, or one-time API key the user
21
+ // can paste during install.
22
+ //
23
+ // **community package names are best-effort** — Slack, Google Maps,
24
+ // and Open-Meteo MCPs vary by maintainer activity; PR reviewers
25
+ // should pin the exact package + version on merge after checking
26
+ // weekly downloads / last commit.
27
+
28
+ import type { McpServerSpec } from "./mcpTypes";
29
+
30
+ export interface McpConfigField {
31
+ /** Env var name (stdio) or placeholder name referenced as `${KEY}` in
32
+ * the spec template (works for url / headers on http too). */
33
+ key: string;
34
+ /** i18n key for the form label above the input. */
35
+ label: string;
36
+ kind: "secret" | "text" | "path" | "url" | "select";
37
+ /** Raw placeholder text shown inside the input. Technical hints like
38
+ * `sk-…` or `xoxb-…` aren't localised; use `helpText` for prose. */
39
+ placeholder?: string;
40
+ required: boolean;
41
+ /** Direct link to the provider's "how to get this" page. Rendered
42
+ * next to the label as a 🔑 affordance. */
43
+ helpUrl?: string;
44
+ /** i18n key for inline help text under the field. */
45
+ helpText?: string;
46
+ /** For kind: "select" only. */
47
+ options?: string[];
48
+ }
49
+
50
+ export interface McpCatalogEntry {
51
+ /** Catalog id; also used as `McpServerEntry.id` when installed. */
52
+ id: string;
53
+ /** i18n key for the display name (e.g. "Memory"). */
54
+ displayName: string;
55
+ /** i18n key for a 1-sentence general-user description. */
56
+ description: string;
57
+ /** UI grouping. General is default-expanded; Developer is collapsed. */
58
+ audience: "general" | "developer";
59
+ /** 📦 npm package or GitHub repo — main project page. */
60
+ upstreamUrl: string;
61
+ /** 📚 provider's setup / onboarding guide (optional, often same as upstream). */
62
+ setupGuideUrl?: string;
63
+ /** Server spec template. `${VAR}` placeholders refer to configSchema keys. */
64
+ spec: McpServerSpec;
65
+ /** Per-entry form fields. Phase 1 entries are all empty. */
66
+ configSchema: McpConfigField[];
67
+ /** Coarse risk hint shown as a badge next to the entry name. */
68
+ riskLevel: "low" | "medium" | "high";
69
+ }
70
+
71
+ // Phase 1 ships the two upstream-pinned entries; Phase 2 adds six
72
+ // more with `configSchema` form-driven setup. The official
73
+ // `@modelcontextprotocol/*` packages are pinned by the upstream
74
+ // Anthropic team; community packages added in Phase 2 should be
75
+ // re-verified at every release.
76
+ export const MCP_CATALOG: McpCatalogEntry[] = [
77
+ {
78
+ id: "memory",
79
+ displayName: "settingsMcpTab.catalog.entry.memory.displayName",
80
+ description: "settingsMcpTab.catalog.entry.memory.description",
81
+ audience: "general",
82
+ upstreamUrl: "https://github.com/modelcontextprotocol/servers/tree/main/src/memory",
83
+ spec: {
84
+ type: "stdio",
85
+ command: "npx",
86
+ args: ["-y", "@modelcontextprotocol/server-memory"],
87
+ },
88
+ configSchema: [],
89
+ riskLevel: "low",
90
+ },
91
+ {
92
+ id: "sequential-thinking",
93
+ displayName: "settingsMcpTab.catalog.entry.sequentialThinking.displayName",
94
+ description: "settingsMcpTab.catalog.entry.sequentialThinking.description",
95
+ audience: "general",
96
+ upstreamUrl: "https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking",
97
+ spec: {
98
+ type: "stdio",
99
+ command: "npx",
100
+ args: ["-y", "@modelcontextprotocol/server-sequential-thinking"],
101
+ },
102
+ configSchema: [],
103
+ riskLevel: "low",
104
+ },
105
+ // Apple-native + screenshot entries explored during the #823
106
+ // design were intentionally dropped from Phase 1 (#825) because no
107
+ // community package was stable enough to pin. They land in a
108
+ // follow-up once a maintained package is selected.
109
+
110
+ // ── Phase 2 entries (#823) ────────────────────────────────────
111
+
112
+ // Library docs lookup. Up-to-date docs for popular libraries
113
+ // fetched at runtime — beats the model's training-cutoff
114
+ // memory for fast-moving frameworks.
115
+ {
116
+ id: "context7",
117
+ displayName: "settingsMcpTab.catalog.entry.context7.displayName",
118
+ description: "settingsMcpTab.catalog.entry.context7.description",
119
+ audience: "general",
120
+ upstreamUrl: "https://github.com/upstash/context7",
121
+ spec: {
122
+ type: "stdio",
123
+ command: "npx",
124
+ args: ["-y", "@upstash/context7-mcp"],
125
+ },
126
+ configSchema: [],
127
+ riskLevel: "low",
128
+ },
129
+
130
+ // GitHub repo wiki lookup over HTTP. Hosted by Cognition;
131
+ // no install / no auth — the model can ask "what is X repo
132
+ // about" and get a structured summary.
133
+ {
134
+ id: "deepwiki",
135
+ displayName: "settingsMcpTab.catalog.entry.deepwiki.displayName",
136
+ description: "settingsMcpTab.catalog.entry.deepwiki.description",
137
+ audience: "general",
138
+ upstreamUrl: "https://docs.devin.ai/work-with-devin/deepwiki-mcp",
139
+ spec: {
140
+ type: "http",
141
+ url: "https://mcp.deepwiki.com/sse",
142
+ },
143
+ configSchema: [],
144
+ riskLevel: "low",
145
+ },
146
+
147
+ // Notion workspace access. Official Notion MCP server uses an
148
+ // OPENAPI_MCP_HEADERS env var that wraps the bearer token in
149
+ // JSON; the user only fills the bare API key and we build the
150
+ // header here. See https://github.com/makenotion/notion-mcp-server.
151
+ {
152
+ id: "notion",
153
+ displayName: "settingsMcpTab.catalog.entry.notion.displayName",
154
+ description: "settingsMcpTab.catalog.entry.notion.description",
155
+ audience: "general",
156
+ upstreamUrl: "https://github.com/makenotion/notion-mcp-server",
157
+ setupGuideUrl: "https://www.notion.so/help/create-integrations-with-the-notion-api",
158
+ spec: {
159
+ type: "stdio",
160
+ command: "npx",
161
+ args: ["-y", "@notionhq/notion-mcp-server"],
162
+ env: {
163
+ OPENAPI_MCP_HEADERS: '{"Authorization":"Bearer ${NOTION_API_KEY}","Notion-Version":"2022-06-28"}',
164
+ },
165
+ },
166
+ configSchema: [
167
+ {
168
+ key: "NOTION_API_KEY",
169
+ label: "settingsMcpTab.catalog.entry.notion.field.apiKey.label",
170
+ kind: "secret",
171
+ placeholder: "secret_...",
172
+ required: true,
173
+ helpUrl: "https://www.notion.so/my-integrations",
174
+ helpText: "settingsMcpTab.catalog.entry.notion.field.apiKey.help",
175
+ },
176
+ ],
177
+ riskLevel: "medium",
178
+ },
179
+
180
+ // Slack channel + message access. TODO(reviewer): the official
181
+ // @modelcontextprotocol/server-slack package is archived but still
182
+ // resolves on npm; check community forks (e.g. mcp-server-slack)
183
+ // for active maintenance before merge.
184
+ {
185
+ id: "slack",
186
+ displayName: "settingsMcpTab.catalog.entry.slack.displayName",
187
+ description: "settingsMcpTab.catalog.entry.slack.description",
188
+ audience: "general",
189
+ upstreamUrl: "https://github.com/modelcontextprotocol/servers/tree/main/src/slack",
190
+ setupGuideUrl: "https://api.slack.com/quickstart",
191
+ spec: {
192
+ type: "stdio",
193
+ command: "npx",
194
+ args: ["-y", "@modelcontextprotocol/server-slack"],
195
+ env: {
196
+ SLACK_BOT_TOKEN: "${SLACK_BOT_TOKEN}",
197
+ SLACK_TEAM_ID: "${SLACK_TEAM_ID}",
198
+ },
199
+ },
200
+ configSchema: [
201
+ {
202
+ key: "SLACK_BOT_TOKEN",
203
+ label: "settingsMcpTab.catalog.entry.slack.field.botToken.label",
204
+ kind: "secret",
205
+ placeholder: "xoxb-...",
206
+ required: true,
207
+ helpUrl: "https://api.slack.com/apps",
208
+ helpText: "settingsMcpTab.catalog.entry.slack.field.botToken.help",
209
+ },
210
+ {
211
+ key: "SLACK_TEAM_ID",
212
+ label: "settingsMcpTab.catalog.entry.slack.field.teamId.label",
213
+ kind: "text",
214
+ placeholder: "T01ABC23DEF",
215
+ required: true,
216
+ helpUrl: "https://api.slack.com/methods/team.info",
217
+ helpText: "settingsMcpTab.catalog.entry.slack.field.teamId.help",
218
+ },
219
+ ],
220
+ riskLevel: "medium",
221
+ },
222
+
223
+ // Google Maps — places search + directions. TODO(reviewer):
224
+ // @modelcontextprotocol/server-google-maps is also archived;
225
+ // verify a maintained alternative if a healthier package exists.
226
+ {
227
+ id: "google-maps",
228
+ displayName: "settingsMcpTab.catalog.entry.googleMaps.displayName",
229
+ description: "settingsMcpTab.catalog.entry.googleMaps.description",
230
+ audience: "general",
231
+ upstreamUrl: "https://github.com/modelcontextprotocol/servers/tree/main/src/google-maps",
232
+ setupGuideUrl: "https://developers.google.com/maps/documentation/javascript/get-api-key",
233
+ spec: {
234
+ type: "stdio",
235
+ command: "npx",
236
+ args: ["-y", "@modelcontextprotocol/server-google-maps"],
237
+ env: {
238
+ GOOGLE_MAPS_API_KEY: "${GOOGLE_MAPS_API_KEY}",
239
+ },
240
+ },
241
+ configSchema: [
242
+ {
243
+ key: "GOOGLE_MAPS_API_KEY",
244
+ label: "settingsMcpTab.catalog.entry.googleMaps.field.apiKey.label",
245
+ kind: "secret",
246
+ placeholder: "AIza...",
247
+ required: true,
248
+ helpUrl: "https://console.cloud.google.com/google/maps-apis/credentials",
249
+ helpText: "settingsMcpTab.catalog.entry.googleMaps.field.apiKey.help",
250
+ },
251
+ ],
252
+ riskLevel: "low",
253
+ },
254
+
255
+ // Weather forecast / current conditions via Open-Meteo. Open-Meteo
256
+ // is keyless for non-commercial use, so this entry is config-free.
257
+ // TODO(reviewer): pick the most-active community package — as of
258
+ // 2026-04 candidates include `mcp-server-open-meteo` and
259
+ // `@cloud-rocket/mcp-server-open-meteo`.
260
+ {
261
+ id: "weather-open-meteo",
262
+ displayName: "settingsMcpTab.catalog.entry.weatherOpenMeteo.displayName",
263
+ description: "settingsMcpTab.catalog.entry.weatherOpenMeteo.description",
264
+ audience: "general",
265
+ upstreamUrl: "https://open-meteo.com/",
266
+ spec: {
267
+ type: "stdio",
268
+ command: "npx",
269
+ args: ["-y", "mcp-server-open-meteo"],
270
+ },
271
+ configSchema: [],
272
+ riskLevel: "low",
273
+ },
274
+ ];
275
+
276
+ /** Look up by id. Returns null when the id isn't in the catalog
277
+ * (i.e. the server was added by hand via Custom servers). */
278
+ export function findCatalogEntry(entryId: string): McpCatalogEntry | null {
279
+ return MCP_CATALOG.find((entry) => entry.id === entryId) ?? null;
280
+ }
281
+
282
+ /** Set of `${KEY}` names the spec template requires the user to fill. */
283
+ export function requiredKeysOf(entry: McpCatalogEntry): Set<string> {
284
+ return new Set(entry.configSchema.filter((field) => field.required).map((field) => field.key));
285
+ }
@@ -0,0 +1,26 @@
1
+ // Shared MCP server-config types. Mirrors `server/system/config.ts`'s
2
+ // `McpServerEntry` shape so the front-end can carry it without
3
+ // importing the server module. Catalog (`mcpCatalog.ts`) and the
4
+ // MCP settings tab both consume these.
5
+
6
+ export interface HttpSpec {
7
+ type: "http";
8
+ url: string;
9
+ headers?: Record<string, string>;
10
+ enabled?: boolean;
11
+ }
12
+
13
+ export interface StdioSpec {
14
+ type: "stdio";
15
+ command: string;
16
+ args?: string[];
17
+ env?: Record<string, string>;
18
+ enabled?: boolean;
19
+ }
20
+
21
+ export type McpServerSpec = HttpSpec | StdioSpec;
22
+
23
+ export interface McpServerEntry {
24
+ id: string;
25
+ spec: McpServerSpec;
26
+ }
@@ -28,34 +28,43 @@ export const ROLES: Role[] = [
28
28
  icon: "star",
29
29
  prompt:
30
30
  "You are a helpful assistant with access to the user's workspace. Help with tasks, answer questions, and use available tools when appropriate.\n\n" +
31
+ "## Asking the user to choose\n\n" +
32
+ "When the user must pick from a small set of options, toggle features, or answer yes/no, call presentForm with the appropriate fields (radio for one-of, checkbox for many-of, text/textarea for free-form). Group related questions into one form. Prefer this strongly over phrasing the choice in plain prose — the form gives the user clickable controls and sends the answers back as a markdown bullet list.\n\n" +
33
+ "Mark every field the user must answer as `required: true`. The form blocks submission until required fields are filled, which prevents the LLM from receiving partial responses.\n\n" +
31
34
  "## Wiki\n\n" +
32
35
  "A personal knowledge wiki lives at `data/wiki/` in the workspace. You can build and query it:\n\n" +
33
36
  "- **Ingest**: fetch or read the source, save raw to `data/wiki/sources/<slug>.md`, create/update pages in `data/wiki/pages/`, update `data/wiki/index.md`, append to `data/wiki/log.md`. Call manageWiki with action='index' when done.\n" +
34
37
  "- **Query**: call manageWiki with action='index' to show the catalog, or action='page' to show a specific page. Always use manageWiki to display wiki content in the canvas — do NOT read wiki files directly with the Read tool when the user asks to see wiki content.\n" +
35
38
  "- **Lint**: call manageWiki with action='lint_report', then fix issues found.\n\n" +
36
- "Page format: YAML frontmatter (title, created, updated, tags) + markdown body + `[[wiki links]]` for cross-references. Slugs are lowercase hyphen-separated. Always keep `data/wiki/index.md` current and append to `data/wiki/log.md` after any change. Read `config/helps/wiki.md` for full details.",
39
+ "Page format: YAML frontmatter (title, created, updated, tags) + markdown body + `[[wiki links]]` for cross-references. Slugs are lowercase hyphen-separated. Always keep `data/wiki/index.md` current and append to `data/wiki/log.md` after any change. The page-list section of `index.md` is a flat, recency-ordered log: prepend new pages at the top, and when a page is updated (content, description, tags, or rename) move its entry to the top — don't group by category. The Tags section (if present) still needs its per-tag page lists updated on add / rename / delete, but the tag order itself is not reordered by recency. Read `config/helps/wiki.md` for full details.",
37
40
  availablePlugins: [
38
41
  "manageTodoList",
39
- "manageScheduler",
42
+ "manageCalendar",
43
+ "manageAutomations",
40
44
  "manageWiki",
41
45
  "manageSkills",
42
46
  "manageSource",
43
47
  "presentDocument",
48
+ "presentForm",
44
49
  "createMindMap",
45
50
  "presentHtml",
46
51
  "presentChart",
47
52
  "readXPost",
48
53
  "searchX",
54
+ "notify",
49
55
  "switchRole",
50
56
  ],
51
57
  queries: [
52
58
  "Tell me about this app, MulmoClaude.",
53
- "What is wiki in this app and how to use it?",
59
+ "What is the wiki in this app and how do I use it?",
60
+ "Tell me about the sandbox feature of this app.",
61
+ "What is the role of the Gemini API key in this app?",
54
62
  "How do I use the Telegram bridge to talk to MulmoClaude from my phone?",
55
63
  "Show my wiki index",
56
64
  "Lint my wiki",
57
65
  "Show my todo list",
58
- "Show me the scheduler",
66
+ "Show me my calendar",
67
+ "Show my scheduled actions",
59
68
  ],
60
69
  },
61
70
  {
@@ -79,6 +88,7 @@ export const ROLES: Role[] = [
79
88
  "presentChart",
80
89
  "readXPost",
81
90
  "searchX",
91
+ "notify",
82
92
  "manageSkills",
83
93
  "manageSource",
84
94
  "switchRole",
@@ -89,6 +99,7 @@ export const ROLES: Role[] = [
89
99
  "Create a 5-slide presentation on the current state of AI in business.",
90
100
  "Fetch AAPL's revenue and net profit for the last several quarters and visualize the trends using D3.js.",
91
101
  "Fetch NVDA's latest financial data and present it as a modern financial infographic with a left-to-right Sankey diagram using D3.js.",
102
+ "Get the weekly closing prices of the Magnificent 7 stocks for the last five years, and multiply each by the number of shares outstanding to compute the market cap. Then plot them on a single graph so we can compare their market caps over time.",
92
103
  "Perform relevant search on X about OpenAI and Anthropic, pick top ten interesting topics from them and show the list to me. Then, create a presentation about each article, one by one.",
93
104
  ],
94
105
  },
@@ -148,6 +159,7 @@ export const ROLES: Role[] = [
148
159
  "Turn this drawing into Ghibli style image",
149
160
  "Generate an image of a big fat cat",
150
161
  "Simulate 100 fish boids using p5.js — they should flock together but avoid the mouse cursor",
162
+ "Create a new puzzle game in HTML. I like Sokoban, Samegame, Vexed, and 2048, but don't copy them — invent something different from any of them.",
151
163
  ],
152
164
  },
153
165
  {
@@ -261,56 +273,14 @@ export const ROLES: Role[] = [
261
273
  "Tell a pirate adventure featuring a daring captain and her first mate across three islands. Use a cinematic photography style.",
262
274
  ],
263
275
  },
264
- {
265
- id: "roleManager",
266
- name: "Role Manager",
267
- icon: "manage_accounts",
268
- prompt:
269
- "You are a role management assistant. Help the user create, update, and delete custom roles. " +
270
- "When asked to list or show roles, call manageRoles with action='list' to display them in the canvas. " +
271
- "When creating a role, ask the user for the role name, purpose, and any specific instructions, then choose appropriate plugins from the available set and write a clear system prompt. " +
272
- "Always call manageRoles with action='list' after creating, updating, or deleting a role so the user can see the updated list.",
273
- availablePlugins: ["manageRoles", "switchRole"],
274
- queries: ["Show my custom roles", "Create a new role for me"],
275
- },
276
- {
277
- id: "sourceManager",
278
- name: "Source Manager",
279
- icon: "rss_feed",
280
- prompt:
281
- "You are an information-source curator. Help the user register, review, and rebuild their information-source registry (RSS feeds, GitHub repos, arXiv queries).\n\n" +
282
- "When asked to show or list sources, call manageSource with action='list' so the canvas displays them.\n\n" +
283
- "When registering a source, ask for the canonical URL (RSS feed URL, GitHub repo URL, or arXiv listing URL), infer fetcherKind from it ('rss' for feeds, 'github-releases' or 'github-issues' depending on user intent, 'arxiv' for arxiv.org), and populate fetcherParams accordingly:\n" +
284
- "- rss: { rss_url: <feed URL> }\n" +
285
- "- github-releases / github-issues: { github_repo: '<owner>/<name>' }\n" +
286
- "- arxiv: { arxiv_query: <search query, e.g. cat:cs.CL> }\n\n" +
287
- "Let the auto-classifier pick categories by default (omit the categories field) unless the user explicitly specifies some.\n\n" +
288
- "When asked to rebuild / refresh / aggregate today's brief, call manageSource with action='rebuild'.\n\n" +
289
- "After any register / remove / rebuild, call manageSource with action='list' to render the updated registry — except when the action's own response already includes the refreshed list (the server returns it for every action, so you usually don't need a second call).\n\n" +
290
- "## Data layout\n\n" +
291
- "The pipeline reads and writes these files (all under the workspace root):\n" +
292
- "- `sources/<slug>.md` — source config (YAML frontmatter: title, url, fetcherKind, fetcherParams, schedule, categories, maxItemsPerFetch, addedAt, notes)\n" +
293
- "- `sources/_state/<slug>.json` — runtime state (lastFetchedAt, cursor, consecutiveFailures, nextAttemptAt)\n" +
294
- "- `news/daily/YYYY/MM/DD.md` — the aggregated daily brief (markdown body + trailing fenced JSON block listing items)\n" +
295
- "- `news/archive/<slug>/YYYY/MM.md` — per-source monthly archive; lossless (no cross-source dedup)\n\n" +
296
- 'When the user asks questions like "summarize last week\'s AI news", "what\'s new on HN today", or "show me articles about <topic>", **read the relevant daily / archive files directly with the Read tool** rather than re-running the pipeline — the data is already there. Use Glob to enumerate date ranges when needed.',
297
- availablePlugins: ["manageSource", "switchRole"],
298
- queries: [
299
- "Show my information sources",
300
- "Register the Hacker News RSS feed (https://news.ycombinator.com/rss)",
301
- "Register the anthropics/claude-code GitHub releases",
302
- "Register an arXiv query for cs.CL new submissions",
303
- "Rebuild today's brief",
304
- ],
305
- },
306
276
  ];
307
277
 
308
278
  export const BUILTIN_ROLES = ROLES;
309
279
 
310
280
  // String-literal constants for every built-in role id. Use these
311
- // instead of inline `"general"` / `"sourceManager"` etc. so that
312
- // renaming a role id is one place to change and `BuiltInRoleId`
313
- // catches typos at compile time.
281
+ // instead of inline `"general"` / `"office"` etc. so that renaming a
282
+ // role id is one place to change and `BuiltInRoleId` catches typos at
283
+ // compile time.
314
284
  //
315
285
  // Test `test/config/test_roles.ts` asserts these keys/values stay in
316
286
  // sync with `ROLES[].id` — adding a new role to ROLES without
@@ -322,8 +292,6 @@ export const BUILTIN_ROLE_IDS = {
322
292
  artist: "artist",
323
293
  tutor: "tutor",
324
294
  storyteller: "storyteller",
325
- roleManager: "roleManager",
326
- sourceManager: "sourceManager",
327
295
  } as const;
328
296
 
329
297
  export type BuiltInRoleId = (typeof BUILTIN_ROLE_IDS)[keyof typeof BUILTIN_ROLE_IDS];