mulmoclaude 0.6.2 → 0.6.4

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 (182) hide show
  1. package/README.md +26 -0
  2. package/bin/mulmoclaude.js +11 -1
  3. package/client/assets/JsonEditor-D6WBWLoa.js +10 -0
  4. package/client/assets/JsonEditor-Di5xGeZY.css +1 -0
  5. package/client/assets/_plugin-vue_export-helper-BOai-rQB.js +1 -0
  6. package/client/assets/chunk-D8eiyYIV-LcKZGJv5.js +1 -0
  7. package/client/assets/{html2canvas-CDGcmOD3-Bkf2uOth.js → html2canvas-CDGcmOD3-XVrO-eyz.js} +1 -1
  8. package/client/assets/index-CyBr8Mkr.css +2 -0
  9. package/client/assets/index-zZIqEbNX.js +5106 -0
  10. package/client/assets/{index.es-DqtpmBm8-D9mAh_KQ.js → index.es-DqtpmBm8-DHT6q10o.js} +1 -1
  11. package/client/assets/material-symbols-outlined-DtIK7AQn.woff2 +0 -0
  12. package/client/assets/runtime-protocol-vue-D6kcV0wa.js +1 -0
  13. package/client/assets/{runtime-vue-BVUzgYGA.js → runtime-vue-fFYhnNg3.js} +1 -1
  14. package/client/assets/{vue-C8UuIO9J.js → vue-D4w8THF_.js} +1 -1
  15. package/client/assets/vue-i18n-CQbxVmNs.js +3 -0
  16. package/client/assets/vue.runtime.esm-bundler-BTyIdNAI.js +4 -0
  17. package/client/index.html +10 -10
  18. package/package.json +9 -8
  19. package/server/agent/backend/claude-code.ts +34 -0
  20. package/server/agent/backend/fake-echo.ts +370 -0
  21. package/server/agent/backend/index.ts +16 -1
  22. package/server/agent/config.ts +74 -24
  23. package/server/agent/index.ts +104 -80
  24. package/server/agent/mcpFailureMonitor.ts +167 -0
  25. package/server/agent/mcpPreflight.ts +185 -0
  26. package/server/agent/prompt.ts +50 -359
  27. package/server/agent/stdioHttpShim.ts +171 -0
  28. package/server/agent/stream.ts +12 -1
  29. package/server/api/routes/encore.ts +55 -0
  30. package/server/api/routes/files.ts +22 -0
  31. package/server/api/routes/mulmo-script.ts +19 -1
  32. package/server/api/routes/schedulerHandlers.ts +52 -4
  33. package/server/api/routes/sessions.ts +15 -0
  34. package/server/api/routes/skills.ts +263 -0
  35. package/server/build/dispatcher.mjs +299 -0
  36. package/server/encore/INVARIANTS.md +272 -0
  37. package/server/encore/boot.ts +39 -0
  38. package/server/encore/closure.ts +36 -0
  39. package/server/encore/cycle.ts +276 -0
  40. package/server/encore/dispatch.ts +103 -0
  41. package/server/encore/handlers/amend.ts +99 -0
  42. package/server/encore/handlers/appendNote.ts +74 -0
  43. package/server/encore/handlers/defineEncore.ts +42 -0
  44. package/server/encore/handlers/listTickets.ts +107 -0
  45. package/server/encore/handlers/markStepDone.ts +41 -0
  46. package/server/encore/handlers/markTargetSkipped.ts +33 -0
  47. package/server/encore/handlers/query.ts +138 -0
  48. package/server/encore/handlers/recordValues.ts +44 -0
  49. package/server/encore/handlers/resolveNotification.ts +121 -0
  50. package/server/encore/handlers/setup.ts +81 -0
  51. package/server/encore/handlers/shared.ts +137 -0
  52. package/server/encore/handlers/snooze.ts +87 -0
  53. package/server/encore/handlers/startObligationChat.ts +64 -0
  54. package/server/encore/handlers/startSetupChat.ts +50 -0
  55. package/server/encore/lock.ts +61 -0
  56. package/server/encore/notifier.ts +123 -0
  57. package/server/encore/obligation.ts +25 -0
  58. package/server/encore/paths.ts +78 -0
  59. package/server/encore/reconcile.ts +661 -0
  60. package/server/encore/tick.ts +191 -0
  61. package/server/encore/yaml-fm.ts +63 -0
  62. package/server/events/notifications.ts +19 -91
  63. package/server/index.ts +94 -9
  64. package/server/notifier/engine.ts +102 -1
  65. package/server/notifier/macosReminderAdapter.ts +30 -0
  66. package/server/notifier/runtime-api.ts +41 -1
  67. package/server/notifier/types.ts +15 -2
  68. package/server/plugins/runtime.ts +11 -2
  69. package/server/prompts/index.ts +39 -0
  70. package/server/prompts/system/journal-pointer.md +12 -0
  71. package/server/prompts/system/memory-management-atomic.md +33 -0
  72. package/server/prompts/system/memory-management-topic.md +60 -0
  73. package/server/prompts/system/news-concierge.md +24 -0
  74. package/server/prompts/system/sandbox-tools.md +10 -0
  75. package/server/prompts/system/sources-context.md +16 -0
  76. package/server/prompts/system/system.md +91 -0
  77. package/server/system/announceOptionalDeps.ts +57 -0
  78. package/server/system/appVersion.ts +34 -0
  79. package/server/system/config.ts +17 -1
  80. package/server/system/docker.ts +14 -6
  81. package/server/system/env.ts +18 -5
  82. package/server/system/optionalDeps.ts +129 -0
  83. package/server/utils/cli-flags.d.mts +14 -0
  84. package/server/utils/cli-flags.mjs +53 -0
  85. package/server/utils/files/encore-io.ts +111 -0
  86. package/server/utils/time.ts +6 -0
  87. package/server/workspace/helps/business.md +2 -2
  88. package/server/workspace/helps/encore-dsl.md +482 -0
  89. package/server/workspace/helps/index.md +15 -13
  90. package/server/workspace/helps/mulmoscript.md +3 -3
  91. package/server/workspace/helps/sandbox.md +2 -2
  92. package/server/workspace/hooks/dispatcher.ts +7 -5
  93. package/server/workspace/hooks/provision.ts +6 -3
  94. package/server/workspace/paths.ts +13 -4
  95. package/server/workspace/skills/catalog.ts +355 -0
  96. package/server/workspace/skills/external/catalog.ts +283 -0
  97. package/server/workspace/skills/external/clone.ts +129 -0
  98. package/server/workspace/skills/external/id.ts +194 -0
  99. package/server/workspace/skills/external/install.ts +417 -0
  100. package/server/workspace/skills/external/presets.ts +50 -0
  101. package/server/workspace/skills-preset.ts +29 -17
  102. package/server/workspace/workspace.ts +10 -5
  103. package/src/App.vue +37 -8
  104. package/src/components/FileContentRenderer.vue +102 -9
  105. package/src/components/JsonEditor.vue +160 -0
  106. package/src/components/NotificationBell.vue +35 -3
  107. package/src/components/PluginLauncher.vue +20 -41
  108. package/src/components/RightSidebar.vue +19 -0
  109. package/src/components/SettingsMcpTab.vue +58 -11
  110. package/src/components/SettingsModal.vue +22 -1
  111. package/src/components/StackView.vue +10 -1
  112. package/src/components/TodoExplorer.vue +16 -0
  113. package/src/components/todo/TodoKanbanView.vue +34 -6
  114. package/src/composables/useNotifications.ts +21 -1
  115. package/src/config/apiRoutes.ts +0 -6
  116. package/src/config/mcpCatalog.ts +12 -7
  117. package/src/config/mcpTypes.ts +5 -0
  118. package/src/config/roles.ts +52 -15
  119. package/src/config/systemFileDescriptors.ts +12 -0
  120. package/src/lang/de.ts +108 -12
  121. package/src/lang/en.ts +105 -11
  122. package/src/lang/es.ts +106 -11
  123. package/src/lang/fr.ts +106 -11
  124. package/src/lang/ja.ts +104 -11
  125. package/src/lang/ko.ts +105 -11
  126. package/src/lang/pt-BR.ts +106 -11
  127. package/src/lang/zh.ts +103 -11
  128. package/src/main.ts +1 -0
  129. package/src/plugins/_generated/metas.ts +4 -0
  130. package/src/plugins/_generated/registrations.ts +2 -0
  131. package/src/plugins/_generated/server-bindings.ts +5 -0
  132. package/src/plugins/encore/EncoreDashboard.vue +504 -0
  133. package/src/plugins/encore/EncoreRedirect.vue +116 -0
  134. package/src/plugins/encore/View.vue +36 -0
  135. package/src/plugins/encore/defineEncoreDefinition.ts +74 -0
  136. package/src/plugins/encore/defineEncoreMeta.ts +13 -0
  137. package/src/plugins/encore/index.ts +93 -0
  138. package/src/plugins/encore/manageEncoreDefinition.ts +100 -0
  139. package/src/plugins/encore/manageEncoreMeta.ts +36 -0
  140. package/src/plugins/manageSkills/View.vue +832 -30
  141. package/src/plugins/manageSkills/categories.ts +125 -0
  142. package/src/plugins/manageSkills/meta.ts +30 -0
  143. package/src/plugins/markdown/definition.ts +3 -3
  144. package/src/plugins/meta-types.ts +5 -0
  145. package/src/plugins/presentMulmoScript/Preview.vue +3 -3
  146. package/src/plugins/presentMulmoScript/View.vue +157 -33
  147. package/src/plugins/presentMulmoScript/meta.ts +4 -0
  148. package/src/plugins/scheduler/View.vue +45 -9
  149. package/src/plugins/scheduler/calendarDefinition.ts +6 -2
  150. package/src/plugins/scheduler/multiDayHelpers.ts +95 -0
  151. package/src/plugins/skill/View.vue +1 -5
  152. package/src/plugins/spreadsheet/View.vue +3 -3
  153. package/src/plugins/spreadsheet/definition.ts +1 -1
  154. package/src/plugins/textResponse/Preview.vue +14 -1
  155. package/src/plugins/textResponse/View.vue +39 -24
  156. package/src/plugins/wiki/components/WikiPageBody.vue +4 -0
  157. package/src/router/index.ts +11 -0
  158. package/src/router/pageRoutes.ts +1 -0
  159. package/src/types/encore-dsl/at-expression.ts +120 -0
  160. package/src/types/encore-dsl/at-resolver.ts +32 -0
  161. package/src/types/encore-dsl/cadence.ts +289 -0
  162. package/src/types/encore-dsl/schema.ts +288 -0
  163. package/src/types/notification.ts +2 -1
  164. package/src/types/session.ts +6 -0
  165. package/src/types/sse.ts +5 -0
  166. package/src/types/toolCallHistory.ts +7 -0
  167. package/src/utils/agent/eventDispatch.ts +26 -5
  168. package/src/utils/agent/mcpHint.ts +50 -0
  169. package/src/utils/image/htmlSrcAttrs.ts +117 -13
  170. package/src/utils/session/sessionEntries.ts +8 -32
  171. package/client/assets/PluginScopedRoot-YjvQq0Nn.js +0 -3
  172. package/client/assets/chunk-CernVdwh.js +0 -1
  173. package/client/assets/chunk-D8eiyYIV-CAXpUwLd.js +0 -1
  174. package/client/assets/index-BwrlMMHr.js +0 -5005
  175. package/client/assets/index-CvvNuegU.css +0 -2
  176. package/client/assets/material-symbols-outlined-BOZVWuR3.woff2 +0 -0
  177. package/client/assets/runtime-protocol-vue-C1To4M3t.js +0 -1
  178. package/client/assets/vue.runtime.esm-bundler-DQ8Kjjui.js +0 -4
  179. package/server/api/routes/notifications.ts +0 -195
  180. package/server/notifier/legacy-adapters.ts +0 -76
  181. package/server/workspace/hooks/dispatcher.mjs +0 -300
  182. package/src/composables/useSelectedResult.ts +0 -49
@@ -0,0 +1,123 @@
1
+ // Encore-scoped notifier wrapper.
2
+ //
3
+ // Closes over:
4
+ // - `pluginPkg`: a constant identity string so every Encore-owned
5
+ // bell entry is tagged uniformly, and `clearForPlugin` can
6
+ // enforce plugin-scoped clearing.
7
+ // - lifecycle: every Encore bell entry uses `lifecycle: "action"`
8
+ // so the host's NotificationBell.vue does NOT auto-clear on
9
+ // user click — clearing is owned by the LLM (markStepDone /
10
+ // markTargetSkipped close the underlying step which clears the
11
+ // bell). The host's `validateActionCoherence` rejects
12
+ // `action` + `info`, so the wrapper also maps DSL `info` (and
13
+ // `warning`) severities to host `nudge` at the publish
14
+ // boundary.
15
+ //
16
+ // Pure passthrough otherwise — no caching, no batching, no other
17
+ // semantics. Tick + handlers import this module rather than
18
+ // reaching for the raw host engine.
19
+
20
+ import * as engine from "../notifier/engine.js";
21
+ import type { Severity } from "../../src/types/encore-dsl/schema.js";
22
+
23
+ /** Identity string used as `pluginPkg` on every Encore bell entry.
24
+ * Stable across versions; lives next to the apiNamespace ("encore")
25
+ * and the tool name ("manageEncore") as part of the plugin's
26
+ * identity. */
27
+ export const ENCORE_PLUGIN_PKG = "encore" as const;
28
+
29
+ export interface PublishArgs {
30
+ severity: Severity;
31
+ title: string;
32
+ body?: string;
33
+ navigateTarget: string;
34
+ pluginData?: unknown;
35
+ }
36
+
37
+ /** Map Encore's DSL-facing severity vocabulary
38
+ * (`info | warning | urgent`, picked for clarity in plain-language
39
+ * prompts the LLM composes against) to the host notifier's
40
+ * vocabulary (`info | nudge | urgent`).
41
+ *
42
+ * We deliberately avoid the host's `info` severity entirely:
43
+ * Encore always uses `lifecycle: "action"` so the LLM (not the
44
+ * bell) owns when the entry goes away — the user clicks the
45
+ * bell, lands in a chat, talks with the LLM, and the LLM calls
46
+ * `markStepDone` / `markTargetSkipped` to clear. The host's
47
+ * publish-time coherence check rejects `action` + `info`, so we
48
+ * map DSL `info` to host `nudge` (the mid-intensity bucket). We
49
+ * lose the visual distinction between info and warning at the
50
+ * bell level; the LLM still differentiates them in title / body /
51
+ * conversation tone. */
52
+ function toHostSeverity(severity: Severity): "nudge" | "urgent" {
53
+ if (severity === "urgent") return "urgent";
54
+ return "nudge";
55
+ }
56
+
57
+ /** Publish an Encore notification. Always emits
58
+ * `lifecycle: "action"` so the host's bell does NOT auto-clear on
59
+ * click — Encore owns the clear via markStepDone /
60
+ * markTargetSkipped. Returns the host-assigned notification id. */
61
+ export async function publish(args: PublishArgs): Promise<{ id: string }> {
62
+ return engine.publish({
63
+ pluginPkg: ENCORE_PLUGIN_PKG,
64
+ severity: toHostSeverity(args.severity),
65
+ lifecycle: "action",
66
+ title: args.title,
67
+ body: args.body,
68
+ navigateTarget: args.navigateTarget,
69
+ pluginData: args.pluginData,
70
+ });
71
+ }
72
+
73
+ /** In-place update of an Encore notification's presentation —
74
+ * same id, same `pluginPkg`, same `lifecycle`, same `createdAt`,
75
+ * new severity / title / body. The reconciler's trim path uses
76
+ * this to flush DSL-driven content drift (an `amendDefinition`
77
+ * edited a `displayName`, the bundle shrunk so the body's member
78
+ * count changed, the cadence pushed us into a higher-severity
79
+ * phase) without flickering the bell entry through a clear +
80
+ * publish — which would litter history with `cleared` records
81
+ * and assign a fresh id every time. Mirrors the DSL → host
82
+ * vocabulary mapping in `publish` so a phase escalation from
83
+ * `info` to `urgent` ends up at host `nudge` → `urgent` rather
84
+ * than confusing the validator.
85
+ *
86
+ * No-op on unknown / cross-plugin ids, and on patches that would
87
+ * invalidate the entry (e.g. info severity on the action
88
+ * lifecycle we always use). Caller treats the failure modes
89
+ * uniformly — same isolation property as `clear`. */
90
+ export async function update(
91
+ entryId: string,
92
+ patch: {
93
+ severity?: Severity;
94
+ title?: string;
95
+ body?: string;
96
+ },
97
+ ): Promise<void> {
98
+ await engine.updateForPlugin(ENCORE_PLUGIN_PKG, entryId, {
99
+ ...(patch.severity !== undefined ? { severity: toHostSeverity(patch.severity) } : {}),
100
+ ...(patch.title !== undefined ? { title: patch.title } : {}),
101
+ ...(patch.body !== undefined ? { body: patch.body } : {}),
102
+ });
103
+ }
104
+
105
+ /** Clear an Encore notification. No-ops on unknown / cross-plugin
106
+ * ids — matches host `clearForPlugin` semantics, plugin can't
107
+ * dismiss another plugin's entries. */
108
+ export async function clear(entryId: string): Promise<void> {
109
+ await engine.clearForPlugin(ENCORE_PLUGIN_PKG, entryId);
110
+ }
111
+
112
+ /** True iff a live bell with this id still exists in the notifier
113
+ * AND belongs to Encore. Used by the reconciler to detect "ghost
114
+ * tickets" — a ticket whose bell was dismissed out-of-band by the
115
+ * host UI (or wiped by a crashed active.json) so that the next
116
+ * tick republishes instead of trusting ticket-existence as proof
117
+ * of bell-existence. Cross-plugin entries (theoretically
118
+ * impossible since the notifier ids are namespaced, but defense
119
+ * in depth) read as not-ours. */
120
+ export async function bellExists(entryId: string): Promise<boolean> {
121
+ const entry = await engine.get(entryId);
122
+ return entry !== undefined && entry.pluginPkg === ENCORE_PLUGIN_PKG;
123
+ }
@@ -0,0 +1,25 @@
1
+ // Helpers for the obligation `index.md` file (DSL frontmatter +
2
+ // free-form body). Symmetric with cycle.ts's parse/serialize.
3
+
4
+ import { parseEncoreFrontmatter, serializeEncoreFrontmatter } from "./yaml-fm.js";
5
+ import { EncoreDslInput, type EncoreDsl } from "../../src/types/encore-dsl/schema.js";
6
+
7
+ /** Parse an obligation's index.md raw markdown into (dsl, body).
8
+ * Re-runs the Zod validator so a hand-edited / corrupted file
9
+ * surfaces as a parse error rather than passing garbage downstream. */
10
+ export function parseIndexFile(raw: string): { dsl: EncoreDsl; body: string } {
11
+ const parsed = parseEncoreFrontmatter(raw);
12
+ if (!parsed.hasHeader) {
13
+ throw new Error("obligation index.md: missing YAML frontmatter");
14
+ }
15
+ const dsl = EncoreDslInput.parse(parsed.meta);
16
+ return { dsl, body: parsed.body };
17
+ }
18
+
19
+ /** Serialize a DSL + body back to markdown. The DSL's
20
+ * `EncoreDslInput.parse` output preserves all declared fields
21
+ * including the server-generated `id` and `createdAt`, so this is
22
+ * a straight YAML dump. */
23
+ export function serializeIndexFile(dsl: EncoreDsl, body: string): string {
24
+ return serializeEncoreFrontmatter(dsl as unknown as Record<string, unknown>, body);
25
+ }
@@ -0,0 +1,78 @@
1
+ // Workspace-relative path helpers for the Encore plugin. Pure
2
+ // string composition — no fs here; the io layer joins these with
3
+ // WORKSPACE_PATHS.encore to get absolute paths.
4
+ //
5
+ // Layout under data/plugins/encore/:
6
+ //
7
+ // obligations/<obligationId>/index.md ← DSL + free-form body
8
+ // obligations/<obligationId>/<cycleId>.md ← per-cycle state + body
9
+ // tickets/<pendingId>.json ← live-bell tickets (chat-on-mount)
10
+ //
11
+ // `obligationId` and `cycleId` flow through the kebab-id validator
12
+ // upstream (DSL schema) and the cadence id formatter — never raw
13
+ // user input, so the path-traversal hardening accounting-io.ts
14
+ // needs is unnecessary here. We still keep a safety assertion at
15
+ // each join to catch any future regression.
16
+
17
+ import path from "node:path";
18
+
19
+ const SAFE_SEGMENT = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
20
+
21
+ function assertSafeSegment(label: string, value: string): void {
22
+ if (!SAFE_SEGMENT.test(value)) {
23
+ throw new Error(`encore: invalid ${label} ${JSON.stringify(value)} (must match ${SAFE_SEGMENT.source})`);
24
+ }
25
+ }
26
+
27
+ export const OBLIGATIONS_DIRNAME = "obligations";
28
+ export const TICKETS_DIRNAME = "tickets";
29
+
30
+ /** "obligations" — relative to the plugin root. */
31
+ export function obligationsDir(): string {
32
+ return OBLIGATIONS_DIRNAME;
33
+ }
34
+
35
+ /** "obligations/<id>" — directory holding index.md + cycle files. */
36
+ export function obligationDir(obligationId: string): string {
37
+ assertSafeSegment("obligationId", obligationId);
38
+ return path.join(OBLIGATIONS_DIRNAME, obligationId);
39
+ }
40
+
41
+ /** "obligations/<id>/index.md" — the DSL document. */
42
+ export function obligationIndexPath(obligationId: string): string {
43
+ return path.join(obligationDir(obligationId), "index.md");
44
+ }
45
+
46
+ /** "obligations/<id>/<cycleId>.md" — the per-cycle state file. */
47
+ export function cycleFilePath(obligationId: string, cycleId: string): string {
48
+ assertSafeSegment("cycleId", cycleId);
49
+ return path.join(obligationDir(obligationId), `${cycleId}.md`);
50
+ }
51
+
52
+ /** "tickets/<pendingId>.json" — the live-bell ticket (carries the
53
+ * seed prompt for chat-on-mount, the severity baseline for
54
+ * escalation diff, and the chatSessionId binding once the user
55
+ * has clicked the bell at least once). */
56
+ export function ticketPath(pendingId: string): string {
57
+ assertSafeSegment("pendingId", pendingId);
58
+ return path.join(TICKETS_DIRNAME, `${pendingId}.json`);
59
+ }
60
+
61
+ /** Slugify a display name into a kebab-case id. Deterministic,
62
+ * ASCII-only, safe for use as a filesystem segment. Used by setup
63
+ * to generate an obligation id from the user-supplied
64
+ * displayName. */
65
+ export function slugify(displayName: string): string {
66
+ const slug = displayName
67
+ .toLowerCase()
68
+ .normalize("NFKD")
69
+ .replace(/[̀-ͯ]/g, "") // strip diacritics
70
+ .replace(/[^a-z0-9]+/g, "-") // collapse non-alphanumerics
71
+ .replace(/^-/, "") // trim leading dash (only one possible: collapse-step above guarantees no consecutive dashes)
72
+ .replace(/-$/, ""); // trim trailing dash
73
+ if (!slug) return "obligation";
74
+ // Slug must start with a letter (KEBAB regex in schema). If the
75
+ // first char ended up as a digit, prefix "o-".
76
+ if (!/^[a-z]/.test(slug)) return `o-${slug}`;
77
+ return slug;
78
+ }