@mulmoclaude/core 1.2.1 → 1.4.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 (39) hide show
  1. package/README.md +49 -0
  2. package/assets/helps/google-calendar-collection.md +13 -2
  3. package/assets/helps/google.md +94 -0
  4. package/assets/helps/index.md +1 -0
  5. package/dist/collection/registry/server/index.cjs +3 -2
  6. package/dist/collection/registry/server/index.cjs.map +1 -1
  7. package/dist/collection/registry/server/index.js +3 -2
  8. package/dist/collection/registry/server/index.js.map +1 -1
  9. package/dist/collection/server/index.cjs +1 -1
  10. package/dist/collection/server/index.js +1 -1
  11. package/dist/collection-watchers/index.cjs +1 -1
  12. package/dist/collection-watchers/index.js +1 -1
  13. package/dist/feeds/server/index.cjs +2 -2
  14. package/dist/feeds/server/index.js +2 -2
  15. package/dist/files/index.cjs +3 -0
  16. package/dist/files/index.cjs.map +1 -1
  17. package/dist/files/index.d.ts +1 -0
  18. package/dist/files/index.js +2 -1
  19. package/dist/files/index.js.map +1 -1
  20. package/dist/files/relPath.d.ts +23 -0
  21. package/dist/google/calendar.d.ts +28 -0
  22. package/dist/google/collectionSync.d.ts +88 -4
  23. package/dist/google/index.cjs +235 -17
  24. package/dist/google/index.cjs.map +1 -1
  25. package/dist/google/index.d.ts +3 -3
  26. package/dist/google/index.js +223 -18
  27. package/dist/google/index.js.map +1 -1
  28. package/dist/google/tasks.d.ts +21 -0
  29. package/dist/relPath-CgGi4-Nv.cjs +46 -0
  30. package/dist/relPath-CgGi4-Nv.cjs.map +1 -0
  31. package/dist/relPath-DW8MC8VO.js +33 -0
  32. package/dist/relPath-DW8MC8VO.js.map +1 -0
  33. package/dist/{server-BZJCw2HU.js → server-D_6FLygK.js} +6 -2
  34. package/dist/server-D_6FLygK.js.map +1 -0
  35. package/dist/{server-w5ZZRLju.cjs → server-gEOeV_Nv.cjs} +6 -2
  36. package/dist/server-gEOeV_Nv.cjs.map +1 -0
  37. package/package.json +10 -1
  38. package/dist/server-BZJCw2HU.js.map +0 -1
  39. package/dist/server-w5ZZRLju.cjs.map +0 -1
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @mulmoclaude/core
2
+
3
+ Shared server-side core for **MulmoClaude** and **MulmoTerminal** — the
4
+ subsystems the two hosts always ship together, consolidated behind subpath
5
+ exports so they cannot drift apart.
6
+
7
+ Not a general-purpose library: it exists so one implementation of collections,
8
+ wiki, feeds, Google integration, scheduling and the rest serves both hosts.
9
+ Every host specific (paths, logging, notification transport, …) is injected
10
+ rather than imported, which is what lets the same code run under either.
11
+
12
+ ## Subpath exports
13
+
14
+ | Area | Entries |
15
+ | --- | --- |
16
+ | Collections | `./collection`, `./collection/server`, `./collection/paths`, `./collection/registry`, `./collection/registry/server`, `./collection-watchers` |
17
+ | Knowledge | `./wiki`, `./wiki/server`, `./wiki/paths`, `./feeds`, `./feeds/server`, `./feeds/paths` |
18
+ | Google | `./google` — OAuth (loopback + PKCE), token store, Calendar / Tasks / Drive REST |
19
+ | Runtime | `./scheduler`, `./notifier`, `./skill-bridge`, `./file-change`, `./workspace-setup`, `./artifacts` |
20
+ | Remote | `./remote-host`, `./remote-host/server`, `./remote-view` |
21
+ | Voice | `./whisper`, `./whisper/client` |
22
+ | Plugin support | `./plugin-vue`, `./plugin-vue/i18n` |
23
+ | Utilities | `./utils`, `./files`, `./fetch` |
24
+
25
+ **Server-only**, except the browser-safe entries: `./artifacts`,
26
+ `./whisper/client`, `./workspace-setup/slug`, `./translation/client`,
27
+ `./remote-view`, `./remote-host` and `./plugin-vue`.
28
+
29
+ The package also ships `assets/helps/*` — the help documents the agent reads at
30
+ runtime — which is why a change there alone still warrants a release.
31
+
32
+ ## About MulmoClaude and MulmoTerminal
33
+
34
+ - **[MulmoClaude](https://github.com/receptron/mulmoclaude)** — an AI-native
35
+ application platform built on Claude Code. Chat summons the right GUI for each
36
+ task (documents, charts, forms, wikis, spreadsheets, 3D scenes), and
37
+ everything your assistant accumulates stays as plain files in your own
38
+ workspace, on your own machine.
39
+ - **[MulmoTerminal](https://github.com/receptron/mulmoterminal)** — run a whole
40
+ team of coding agents from your browser. Many Claude Code / Codex sessions at
41
+ once in a grid, colour-coded so you see which are working, which need you and
42
+ which are done, plus git worktrees, one-click PRs and cost readouts. One `npx`
43
+ command, no Electron, no config.
44
+
45
+ 📖 **User guide**: <https://receptron.github.io/mulmoterminal/> (日本語 / English)
46
+
47
+ ## License
48
+
49
+ MIT
@@ -5,8 +5,10 @@ Add a `googleCalendar` block to its `schema.json` and the host pulls changed
5
5
  events on a schedule and writes them as records — **without calling you**. No
6
6
  tool call, no tokens spent per sync, so hourly syncing is free.
7
7
 
8
- This is the only calendar mechanism: there is no calendar tool and no bundled
9
- calendar collection. You author the schema when the user asks for one.
8
+ This is the mechanism for *keeping a collection fresh*. For one-off reads and
9
+ for creating / editing / deleting events, use the `google` tool — see
10
+ [The `google` tool](google.md). There is no bundled calendar collection: you
11
+ author the schema when the user asks for one.
10
12
 
11
13
  ## Requirements
12
14
 
@@ -57,6 +59,15 @@ Declaring it in `map` is a schema error.
57
59
  Use `datetime` (not `date`) for start/end when events have real clock times —
58
60
  the calendar day view then draws each record as a proportional time block.
59
61
 
62
+ ## When sync runs
63
+
64
+ - **On creation** — the first sync starts as soon as the schema lands, so the
65
+ collection is not empty while the user waits for the schedule. The same
66
+ applies when you add a `googleCalendar` block to an existing collection.
67
+ - **Hourly** after that, in the background.
68
+ - **On demand** — the collection view has a Sync button. Tell the user about it
69
+ if they want the calendar refreshed right now.
70
+
60
71
  ## What sync does
61
72
 
62
73
  - New or edited events are written, keyed by event id (existing records are
@@ -0,0 +1,94 @@
1
+ # The `google` tool — Calendar, Tasks and Drive
2
+
3
+ One tool, one `kind` per operation, against the Google account the user linked
4
+ on this machine. The refresh token is stored locally in `~/.config/mulmo/` and
5
+ goes only to Google, to mint access tokens — never to claude.ai or any other
6
+ service. This works with no claude.ai Google connector involved.
7
+
8
+ Call `kind: "status"` when unsure whether the account is linked. If a call fails
9
+ with "Google account not linked", ask the user to link it in settings and retry
10
+ the original call — do not fall back to guessing.
11
+
12
+ ## Two mechanisms, different jobs
13
+
14
+ | You want | Use |
15
+ | --- | --- |
16
+ | Read or change specific events / tasks / files, right now | this tool |
17
+ | A collection that mirrors a calendar and keeps itself fresh | a `googleCalendar` block — see [Google Calendar sync](google-calendar-collection.md) |
18
+
19
+ The collection route costs no tokens per refresh, so prefer it for anything
20
+ recurring. Use this tool for one-off work and for everything the collection
21
+ route cannot do (creating, editing and deleting).
22
+
23
+ ## Calendar
24
+
25
+ Events default to the user's **primary** calendar. Pass `calendarId` — obtained
26
+ from `calendarListCalendars` — to target another.
27
+
28
+ | kind | What it does |
29
+ | --- | --- |
30
+ | `calendarListCalendars` | The calendars the user has added/subscribed to: `id`, `summary`, `primary`, colours, `accessRole` |
31
+ | `calendarColors` | Palettes mapping a `colorId` to hex, for events and for calendars |
32
+ | `calendarListEvents` | Upcoming events. Optional `calendarId`, `timeMin`, `maxResults` (1-50, default 10) |
33
+ | `calendarSync` | Only what CHANGED since the last sync, via a stored token. Returns counts plus a capped sample |
34
+ | `calendarCreateEvent` | Create. Requires `summary`, `start`, `end`; optional `description`, `calendarId`, `colorId` |
35
+ | `calendarUpdateEvent` | Edit in place. Requires `eventId` + at least one of `summary`, `start`, `end`, `description`, `colorId` |
36
+ | `calendarDeleteEvent` | Delete. Requires `eventId` |
37
+
38
+ **Date-times must carry a timezone offset** — `2026-07-17T09:00:00+09:00`, not
39
+ `2026-07-17` and not `2026-07-17T09:00:00`. Calendar rejects the others with an
40
+ opaque 400.
41
+
42
+ **Editing is a patch.** Fields you omit keep their current value, so changing a
43
+ title needs `eventId` + `summary` and nothing else. `description: ""` clears the
44
+ body. Moving one end of an event still has to leave the start before the end.
45
+
46
+ **`eventId` comes from `calendarListEvents` or `calendarSync`** — never invent
47
+ one. For a recurring event those kinds return per-occurrence ids, so editing or
48
+ deleting one affects that single occurrence.
49
+
50
+ **Deleting is not reversible** and removes the event for every attendee. Confirm
51
+ with the user before calling `calendarDeleteEvent`, and say which event you are
52
+ about to remove.
53
+
54
+ ## Tasks
55
+
56
+ Operate on the user's default task list unless `taskListId` is given.
57
+
58
+ | kind | What it does |
59
+ | --- | --- |
60
+ | `taskListsList` | The user's task lists (`id`, `title`). Only needed for a non-default list |
61
+ | `tasksList` | List tasks. Optional `taskListId`, `maxResults` (1-50, default 10), `showCompleted` (default false) |
62
+ | `tasksCreate` | Add a task. Requires `title`; optional `notes`, `due`, `taskListId` |
63
+ | `tasksUpdate` | Edit. Requires `taskId` + at least one of `title`, `notes`, `due`. `notes: ""` clears them; `due` can be changed but **not** cleared |
64
+ | `tasksComplete` | Mark done. Requires `taskId` |
65
+ | `tasksDelete` | Delete. Requires `taskId` — not reversible, so confirm first |
66
+
67
+ `tasksUpdate` does not change status: `tasksComplete` owns that transition.
68
+
69
+ **Google stores a DATE only for `due`** — the time part is accepted and then
70
+ ignored, so never promise the user a time of day on a task.
71
+
72
+ ## Drive
73
+
74
+ In practice this app sees **only the files it created itself**, never the user's
75
+ wider Drive. Never claim to have searched their Drive.
76
+
77
+ (The `drive.file` scope also covers files the user hands to an app through a
78
+ Google Picker, but this app has no Picker — so app-created is the whole set.)
79
+
80
+ | kind | What it does |
81
+ | --- | --- |
82
+ | `driveList` | Files this app created. Optional `maxResults` (1-50, default 10) |
83
+ | `driveCreate` | Create a text file. Requires `name`, `content`; optional `mimeType` (default `text/plain`) |
84
+ | `driveRead` | Read one of this app's files. Requires `fileId`. Text only |
85
+
86
+ ## Failure modes
87
+
88
+ - **"Google account not linked"** — the user has not linked, or the token was
89
+ revoked. Ask them to link in settings; do not retry blindly.
90
+ - **HTTP 403 naming an API** — that API is not enabled for the user's Cloud
91
+ project. The message says which one.
92
+ - **HTTP 400 on a create/update** — almost always a date-time without an offset,
93
+ or a start that is not before the end.
94
+ - **HTTP 410 on delete** — the event was already gone.
@@ -72,6 +72,7 @@ See [Wiki](config/helps/wiki.md) for details on how it works.
72
72
  - [Remote host](config/helps/remote-host.md) — drive MulmoClaude from a phone at mulmoserver.web.app: Google sign-in connect, host online vs. offline (queued chats, 7-day expiry), photo attachments, and the security model
73
73
  - [Feeds](config/helps/feeds.md) — register a self-refreshing data feed (RSS/Atom/JSON) by authoring `feeds/<slug>/schema.json`: schema shape, the `ingest` block, raw-item field mapping, and `maxItems` retention
74
74
  - [Google Calendar sync](config/helps/google-calendar-collection.md) — mirror a Google calendar into a collection with a `googleCalendar` block: field mapping, why the primary field holds the event id, and how deletions propagate
75
+ - [The `google` tool](config/helps/google.md) — every `kind` for Calendar, Tasks and Drive: reading, creating, editing and deleting events and tasks, the timezone-offset rule, patch semantics, and what `drive.file` scope cannot see
75
76
  - [GitHub repositories in the workspace](config/helps/github.md) — clone-destination rules under `github/<name>/` and how to handle existing directories with matching or different remotes
76
77
  - [Collection skills](config/helps/collection-skills.md) — build a data app (model + UI + relations + computed fields + action buttons) by authoring a `schema.json` collection skill: the DSL, field types, derived formulas, actions, records
77
78
  - [Custom views](config/helps/custom-view.md) — give a collection a view the built-ins don't cover (year/quarter overview, Gantt): an HTML file under `views/`, registered in `schema.json`, rendered in a sandboxed iframe over the records
@@ -2,10 +2,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("../../../rolldown-runtime-D6vf50IK.cjs");
3
3
  const require_dist = require("../../../dist-pWpC-b04.cjs");
4
4
  const require_atomic = require("../../../atomic-C_7YpMiM.cjs");
5
+ const require_relPath = require("../../../relPath-CgGi4-Nv.cjs");
5
6
  const require_utils_fetch = require("../../../utils/fetch.cjs");
6
7
  const require_discovery = require("../../../discovery--kRUWed0.cjs");
7
8
  const require_templatePath = require("../../../templatePath-27vUZowm.cjs");
8
- const require_server = require("../../../server-w5ZZRLju.cjs");
9
+ const require_server = require("../../../server-gEOeV_Nv.cjs");
9
10
  const require_skill_bridge_index = require("../../../skill-bridge/index.cjs");
10
11
  const require_types = require("../../../types-CNqkLT4M.cjs");
11
12
  let node_fs = require("node:fs");
@@ -905,7 +906,7 @@ async function writeCollectionExport(params) {
905
906
  });
906
907
  return {
907
908
  ok: true,
908
- outputPath: node_path.default.relative(wsRoot, outDir).split(node_path.default.sep).join("/"),
909
+ outputPath: require_relPath.toPosixRelPath(node_path.default.relative(wsRoot, outDir)),
909
910
  fileCount: bundleCount + 1,
910
911
  seedCount: seed.count,
911
912
  seedSkipped: seed.skipped,