mulmoclaude 0.9.2 → 0.9.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.
- package/bin/mulmoclaude.js +2 -1
- package/client/assets/{index-Dc0R-HW5.js → index-B3NxFcEH.js} +46 -46
- package/client/assets/{index-Dxo1Zdd-.css → index-BXb--as6.css} +1 -1
- package/client/assets/{marp-CSq0PPfK.js → marp-C9QDHFAJ.js} +1 -1
- package/client/index.html +2 -2
- package/package.json +11 -10
- package/server/api/routes/agent.ts +5 -1
- package/server/api/routes/chat-index.ts +5 -1
- package/server/api/routes/collections.ts +152 -1
- package/server/api/routes/config.ts +12 -0
- package/server/index.ts +14 -2
- package/server/prompts/system/system.md +7 -1
- package/server/remoteHost/firebase.ts +6 -0
- package/server/remoteHost/handlers/collectionPage.ts +15 -17
- package/server/remoteHost/handlers/getCollection.ts +2 -2
- package/server/remoteHost/handlers/getFeed.ts +2 -2
- package/server/remoteHost/handlers/getRemoteView.ts +37 -0
- package/server/remoteHost/handlers/getRemoteViewItems.ts +38 -0
- package/server/remoteHost/handlers/index.ts +10 -0
- package/server/remoteHost/handlers/ingestAttachments.ts +88 -0
- package/server/remoteHost/handlers/listAccountingBooks.ts +31 -0
- package/server/remoteHost/handlers/listCollections.ts +6 -1
- package/server/remoteHost/handlers/listSkills.ts +39 -0
- package/server/remoteHost/handlers/mutateRemoteView.ts +40 -0
- package/server/remoteHost/handlers/startChat.ts +103 -39
- package/server/system/config.ts +101 -4
- package/server/system/logs/aaa +737 -0
- package/server/system/logs/bb +446 -0
- package/server/utils/files/thumbnail-store.ts +97 -0
- package/server/workspace/chat-index/index.ts +29 -3
- package/server/workspace/chat-index/indexer.ts +187 -29
- package/server/workspace/chat-index/summarizer.ts +18 -10
- package/server/workspace/collections/index.ts +2 -1
- package/server/workspace/collections/remoteView.ts +290 -0
- package/server/workspace/journal/archivist-cli.ts +17 -3
- package/server/workspace/journal/dailyPass.ts +52 -2
- package/server/workspace/journal/index.ts +20 -4
- package/src/App.vue +62 -3
- package/src/components/FileTree.vue +21 -1
- package/src/components/FileTreePane.vue +41 -25
- package/src/components/FilesView.vue +4 -0
- package/src/components/RemoteHostControl.vue +18 -0
- package/src/components/SessionHistoryPanel.vue +24 -11
- package/src/components/SettingsChatIndexTab.vue +119 -0
- package/src/components/SettingsJournalTab.vue +117 -0
- package/src/components/SettingsModal.vue +12 -2
- package/src/composables/collections/uiHost.ts +15 -0
- package/src/composables/collections/useDynamicShortcutIcons.ts +93 -0
- package/src/composables/usePubSub.ts +40 -2
- package/src/composables/useSessionSync.ts +9 -0
- package/src/composables/useShowHiddenSystemFiles.ts +23 -0
- package/src/config/apiRoutes.ts +20 -0
- package/src/config/roles.ts +2 -2
- package/src/config/visibleWorkspaceDirs.ts +21 -0
- package/src/lang/de.ts +47 -0
- package/src/lang/en.ts +45 -0
- package/src/lang/es.ts +46 -0
- package/src/lang/fr.ts +47 -0
- package/src/lang/ja.ts +46 -0
- package/src/lang/ko.ts +45 -0
- package/src/lang/pt-BR.ts +46 -0
- package/src/lang/zh.ts +44 -0
- package/src/plugins/textResponse/View.vue +49 -14
- package/src/plugins/textResponse/utils.ts +37 -0
- package/src/utils/html/previewCsp.ts +7 -16
- package/src/utils/role/icon.ts +9 -2
- package/src/utils/session/sessionPreview.ts +29 -0
|
@@ -7,11 +7,17 @@ interface PubSubMessage {
|
|
|
7
7
|
|
|
8
8
|
type Callback = (data: unknown) => void;
|
|
9
9
|
type Unsubscribe = () => void;
|
|
10
|
+
type ReconnectHandler = () => void;
|
|
10
11
|
|
|
11
12
|
// On reconnect we re-emit every live subscription so the rooms list survives the bounce.
|
|
12
13
|
let socket: Socket | null = null;
|
|
13
14
|
|
|
14
15
|
const listeners = new Map<string, Set<Callback>>();
|
|
16
|
+
const reconnectHandlers = new Set<ReconnectHandler>();
|
|
17
|
+
// First `connect` is the initial establishment; every subsequent one is a
|
|
18
|
+
// reconnect and needs a state catch-up (missed events during the down window
|
|
19
|
+
// are lost because the pub/sub server has no replay buffer). See #1915.
|
|
20
|
+
let hasConnectedOnce = false;
|
|
15
21
|
|
|
16
22
|
function resendSubscriptions(sock: Socket): void {
|
|
17
23
|
for (const channel of listeners.keys()) {
|
|
@@ -19,6 +25,16 @@ function resendSubscriptions(sock: Socket): void {
|
|
|
19
25
|
}
|
|
20
26
|
}
|
|
21
27
|
|
|
28
|
+
function fireReconnectHandlers(): void {
|
|
29
|
+
for (const handler of reconnectHandlers) {
|
|
30
|
+
try {
|
|
31
|
+
handler();
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error("[usePubSub] reconnect handler threw:", err);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
function connect(): Socket {
|
|
23
39
|
if (socket) return socket;
|
|
24
40
|
|
|
@@ -28,7 +44,14 @@ function connect(): Socket {
|
|
|
28
44
|
transports: ["websocket"],
|
|
29
45
|
});
|
|
30
46
|
|
|
31
|
-
sock.on("connect", () =>
|
|
47
|
+
sock.on("connect", () => {
|
|
48
|
+
resendSubscriptions(sock);
|
|
49
|
+
if (hasConnectedOnce) {
|
|
50
|
+
fireReconnectHandlers();
|
|
51
|
+
} else {
|
|
52
|
+
hasConnectedOnce = true;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
32
55
|
|
|
33
56
|
sock.on("data", (msg: PubSubMessage) => {
|
|
34
57
|
const cbs = listeners.get(msg.channel);
|
|
@@ -46,6 +69,10 @@ function maybeDisconnect(): void {
|
|
|
46
69
|
if (!socket) return;
|
|
47
70
|
socket.disconnect();
|
|
48
71
|
socket = null;
|
|
72
|
+
// Reset so the next `connect()` cycle is a true initial connect again —
|
|
73
|
+
// catch-up handlers only make sense against state accumulated on this
|
|
74
|
+
// socket, not across an unsubscribe/resubscribe cycle.
|
|
75
|
+
hasConnectedOnce = false;
|
|
49
76
|
}
|
|
50
77
|
|
|
51
78
|
export function usePubSub() {
|
|
@@ -73,5 +100,16 @@ export function usePubSub() {
|
|
|
73
100
|
};
|
|
74
101
|
}
|
|
75
102
|
|
|
76
|
-
|
|
103
|
+
// Register a handler that fires on every reconnect (not the initial
|
|
104
|
+
// connect). Callers use this to catch up on missed events after the
|
|
105
|
+
// socket bounces — the pub/sub server has no replay buffer, so anything
|
|
106
|
+
// published during the down window is gone. See #1915.
|
|
107
|
+
function onReconnect(handler: ReconnectHandler): Unsubscribe {
|
|
108
|
+
reconnectHandlers.add(handler);
|
|
109
|
+
return () => {
|
|
110
|
+
reconnectHandlers.delete(handler);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { subscribe, onReconnect };
|
|
77
115
|
}
|
|
@@ -30,7 +30,15 @@ export function useSessionSync(opts: {
|
|
|
30
30
|
const { sessionMap, currentSessionId, fetchSessions, onCurrentSessionDeleted } = opts;
|
|
31
31
|
const { subscribe } = usePubSub();
|
|
32
32
|
|
|
33
|
+
// Monotonic sequence token — protects sessionMap from stale overwrites when
|
|
34
|
+
// two concurrent refreshes race (e.g. reconnect fires while a
|
|
35
|
+
// visibilitychange is mid-flight). Every call increments the token before
|
|
36
|
+
// awaiting; after the fetch resolves, we mutate only if our token is still
|
|
37
|
+
// the latest, so the older-but-slower response can never regress live
|
|
38
|
+
// state (e.g. re-flip isRunning back to true after session_finished).
|
|
39
|
+
let refreshToken = 0;
|
|
33
40
|
async function refreshSessionStates(): Promise<void> {
|
|
41
|
+
const myToken = ++refreshToken;
|
|
34
42
|
let summaries: SessionSummary[];
|
|
35
43
|
try {
|
|
36
44
|
summaries = await fetchSessions();
|
|
@@ -40,6 +48,7 @@ export function useSessionSync(opts: {
|
|
|
40
48
|
console.warn("[session-sync] failed to fetch sessions:", err);
|
|
41
49
|
return;
|
|
42
50
|
}
|
|
51
|
+
if (myToken !== refreshToken) return;
|
|
43
52
|
for (const summary of summaries) {
|
|
44
53
|
const live = sessionMap.get(summary.id);
|
|
45
54
|
if (!live) continue;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Composable: "show system files" toggle for the Files Explorer,
|
|
2
|
+
// persisted to localStorage. Default false — the Files pane hides
|
|
3
|
+
// agent-internal top-level dirs (`conversations/`, `feeds/`, etc.)
|
|
4
|
+
// until the user opts in. See #1896.
|
|
5
|
+
|
|
6
|
+
import { ref } from "vue";
|
|
7
|
+
|
|
8
|
+
const STORAGE_KEY = "filesView.showHiddenSystem";
|
|
9
|
+
|
|
10
|
+
function readStored(): boolean {
|
|
11
|
+
return localStorage.getItem(STORAGE_KEY) === "true";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useShowHiddenSystemFiles() {
|
|
15
|
+
const showHiddenSystem = ref<boolean>(readStored());
|
|
16
|
+
|
|
17
|
+
function setShowHiddenSystem(next: boolean): void {
|
|
18
|
+
showHiddenSystem.value = next;
|
|
19
|
+
localStorage.setItem(STORAGE_KEY, next ? "true" : "false");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { showHiddenSystem, setShowHiddenSystem };
|
|
23
|
+
}
|
package/src/config/apiRoutes.ts
CHANGED
|
@@ -293,6 +293,26 @@ const HOST_API_ROUTES = {
|
|
|
293
293
|
/** GET ?id=<viewId> → the custom view's HTML file (global-bearer auth),
|
|
294
294
|
* read from data/skills/:slug/views/. The parent renders it sandboxed. */
|
|
295
295
|
viewFile: "/api/collections/:slug/view-file",
|
|
296
|
+
/** GET ?id=<viewId>&locale=<tag> → a mobile (`target: "mobile"`) custom
|
|
297
|
+
* view wrapped into its sandboxed srcdoc (global-bearer auth) →
|
|
298
|
+
* { view, srcdoc, bytes }. Same builder as the command channel's
|
|
299
|
+
* `getRemoteView`, so the desktop phone-frame preview renders the exact
|
|
300
|
+
* artifact the phone receives (plans/feat-remote-custom-view.md). */
|
|
301
|
+
remoteView: "/api/collections/:slug/remote-view",
|
|
302
|
+
/** POST { op: "update"|"delete", id, patch? } → apply one mutate on behalf
|
|
303
|
+
* of a `target: "mobile"` view, authorized by that view's declared
|
|
304
|
+
* editableFields / allowDelete and enforced host-side (global-bearer auth).
|
|
305
|
+
* The desktop phone-frame preview's write channel — same builder the
|
|
306
|
+
* command channel's `mutateRemoteViewItem` uses, so preview === phone
|
|
307
|
+
* (plans/feat-remote-writable-view.md). */
|
|
308
|
+
remoteViewMutate: "/api/collections/:slug/remote-view/:viewId/mutate",
|
|
309
|
+
/** GET ?offset&limit&fields=<csv> → one page of a `target: "mobile"` view's
|
|
310
|
+
* records with its declared `imageFields` inlined as `data:` URL thumbnails
|
|
311
|
+
* (global-bearer auth) → { page, inlined, omitted }. Same builder as the
|
|
312
|
+
* command channel's `getRemoteViewItems`, so the desktop phone-frame preview
|
|
313
|
+
* pages the exact data (incl. real thumbnails) the phone will
|
|
314
|
+
* (plans/feat-remote-view-images.md). */
|
|
315
|
+
remoteViewItems: "/api/collections/:slug/remote-view/:viewId/items",
|
|
296
316
|
/** GET ?id=<viewId>&locale=<tag> → translation dict for one custom view
|
|
297
317
|
* (global-bearer auth) → { locale, dict }. `dict` is the host-picked
|
|
298
318
|
* flat map for the requested locale (fallback `"en"`, else `{}`); the
|
package/src/config/roles.ts
CHANGED
|
@@ -46,7 +46,7 @@ export const ROLES: Role[] = [
|
|
|
46
46
|
{
|
|
47
47
|
id: "general",
|
|
48
48
|
name: "General",
|
|
49
|
-
icon: "
|
|
49
|
+
icon: "auto_awesome",
|
|
50
50
|
prompt:
|
|
51
51
|
"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" +
|
|
52
52
|
"## Asking the user to choose\n\n" +
|
|
@@ -372,7 +372,7 @@ export const ROLES: Role[] = [
|
|
|
372
372
|
{
|
|
373
373
|
id: "debug",
|
|
374
374
|
name: "Debug",
|
|
375
|
-
icon: "
|
|
375
|
+
icon: "bug_report",
|
|
376
376
|
prompt:
|
|
377
377
|
"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" +
|
|
378
378
|
"## Asking the user to choose\n\n" +
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Top-level workspace directories that the Files Explorer surfaces by
|
|
2
|
+
// default. Everything else at the root (`conversations/`, `feeds/`,
|
|
3
|
+
// `.git/`, `.github/`, ad-hoc automation buckets, …) is treated as
|
|
4
|
+
// "system" and stays hidden until the user flips the "show system
|
|
5
|
+
// files" toggle. See #1896.
|
|
6
|
+
//
|
|
7
|
+
// The whitelist covers the buckets MulmoClaude WRITES USER-FACING
|
|
8
|
+
// CONTENT into:
|
|
9
|
+
// - data/ — wiki, calendar, contacts, attachments, feed records, ...
|
|
10
|
+
// - artifacts/ — charts, documents, html, svg, images, spreadsheets, ...
|
|
11
|
+
// - config/ — settings.json, mcp.json, roles/, helps/, marp themes
|
|
12
|
+
// The filter is applied only at the root — once a whitelisted dir is
|
|
13
|
+
// shown, everything beneath it is visible without further filtering.
|
|
14
|
+
// That way a plugin that lands `data/foo-plugin/` shows up naturally
|
|
15
|
+
// without needing a code change here.
|
|
16
|
+
|
|
17
|
+
export const VISIBLE_TOP_LEVEL_DIRS: readonly string[] = ["data", "artifacts", "config"];
|
|
18
|
+
|
|
19
|
+
export function isVisibleTopLevel(name: string): boolean {
|
|
20
|
+
return VISIBLE_TOP_LEVEL_DIRS.includes(name);
|
|
21
|
+
}
|
package/src/lang/de.ts
CHANGED
|
@@ -136,6 +136,9 @@ const deMessages = {
|
|
|
136
136
|
disconnectFailed: "Trennen fehlgeschlagen",
|
|
137
137
|
signInFailed: "Google-Anmeldung fehlgeschlagen",
|
|
138
138
|
statusFailed: "Status konnte nicht geladen werden",
|
|
139
|
+
description: "Mit Remote-Zugriff kann ein Mobilgerät auf die Sammlungen und Feeds dieser MulmoClaude-Instanz zugreifen.",
|
|
140
|
+
howTo: "Öffne auf deinem Smartphone {url} und melde dich mit demselben Google-Konto an.",
|
|
141
|
+
customViewHint: "Für eine mobiltaugliche Ansicht bitte Claude, statt einer normalen Custom View eine {keyword} zu bauen.",
|
|
139
142
|
},
|
|
140
143
|
sidebarHeader: {
|
|
141
144
|
home: "Zum neuesten Chat",
|
|
@@ -180,6 +183,9 @@ const deMessages = {
|
|
|
180
183
|
// "RO" = Read-Only. Englische Abkürzung bleibt erhalten, um als
|
|
181
184
|
// kompaktes Badge neben dem Label "Referenz" zu passen.
|
|
182
185
|
readOnlyBadge: "RO",
|
|
186
|
+
showSystemFiles: "Systemdateien anzeigen",
|
|
187
|
+
showSystemFilesTitle:
|
|
188
|
+
"Zeigt agent-interne Top-Level-Verzeichnisse (conversations/, feeds/ usw.) zusätzlich zu den Nutzer-Daten (data/, artifacts/, config/) an.",
|
|
183
189
|
},
|
|
184
190
|
fileTree: {
|
|
185
191
|
workspace: "(Arbeitsbereich)",
|
|
@@ -231,6 +237,8 @@ const deMessages = {
|
|
|
231
237
|
photos: "Fotos",
|
|
232
238
|
model: "Modell",
|
|
233
239
|
voice: "Sprache",
|
|
240
|
+
chatIndex: "Chat-Index",
|
|
241
|
+
journal: "Journal",
|
|
234
242
|
skills: "Skills",
|
|
235
243
|
roles: "Rollen",
|
|
236
244
|
},
|
|
@@ -293,6 +301,43 @@ const deMessages = {
|
|
|
293
301
|
loadError: "Einstellungen konnten nicht geladen werden",
|
|
294
302
|
saveError: "Speichern fehlgeschlagen",
|
|
295
303
|
},
|
|
304
|
+
chatIndexTab: {
|
|
305
|
+
description:
|
|
306
|
+
"Automatische KI-Titel und Zusammenfassungen für den Chat-Verlauf. Standardmäßig aus — Automatisierungs-Sessions (Scheduler / System-Worker) werden auch bei aktivierter Option immer übersprungen; menschliche Sessions kosten pro beendetem Turn genau einen Summarizer-Aufruf.",
|
|
307
|
+
modeLabel: "Chat-Index-Modell",
|
|
308
|
+
helperText: "Haiku ist günstiger; Sonnet liefert schärfere Titel bei langen, themenwechselnden Sessions.",
|
|
309
|
+
mode: {
|
|
310
|
+
off: "Aus",
|
|
311
|
+
haiku: "Haiku",
|
|
312
|
+
sonnet: "Sonnet",
|
|
313
|
+
},
|
|
314
|
+
status: {
|
|
315
|
+
off: "Indizierung ist AUS",
|
|
316
|
+
haiku: "Indizierung läuft mit Haiku",
|
|
317
|
+
sonnet: "Indizierung läuft mit Sonnet",
|
|
318
|
+
},
|
|
319
|
+
loadError: "Einstellungen konnten nicht geladen werden",
|
|
320
|
+
saveError: "Speichern fehlgeschlagen",
|
|
321
|
+
},
|
|
322
|
+
journalTab: {
|
|
323
|
+
description:
|
|
324
|
+
"Automatisiertes Tages-Journal — fasst kürzliche Chat-Sessions in journal/*.md zusammen und extrahiert dauerhafte Memory-Notizen. Standardmäßig aus. Automatisierungs-Sessions (Scheduler / System-Worker) werden unabhängig von dieser Einstellung immer ausgeschlossen.",
|
|
325
|
+
modeLabel: "Journal-Modell",
|
|
326
|
+
helperText:
|
|
327
|
+
"Haiku ist günstiger; Sonnet liefert reichhaltigere Tages- und Themen-Zusammenfassungen. Der stündliche Lauf startet nur, wenn dies gesetzt ist.",
|
|
328
|
+
mode: {
|
|
329
|
+
off: "Aus",
|
|
330
|
+
haiku: "Haiku",
|
|
331
|
+
sonnet: "Sonnet",
|
|
332
|
+
},
|
|
333
|
+
status: {
|
|
334
|
+
off: "Journal ist AUS",
|
|
335
|
+
haiku: "Journal läuft mit Haiku",
|
|
336
|
+
sonnet: "Journal läuft mit Sonnet",
|
|
337
|
+
},
|
|
338
|
+
loadError: "Einstellungen konnten nicht geladen werden",
|
|
339
|
+
saveError: "Speichern fehlgeschlagen",
|
|
340
|
+
},
|
|
296
341
|
// `<i18n-t>`-Slots — die Namen `envKey` / `envFile` werden in
|
|
297
342
|
// SettingsModal.vue als Inline-`<code>` gerendert, sodass die
|
|
298
343
|
// literalen Variablen- und Dateinamen unübersetzt bleiben.
|
|
@@ -949,6 +994,8 @@ const deMessages = {
|
|
|
949
994
|
cancel: "Abbrechen",
|
|
950
995
|
seededByPlugin: "von {pkg}",
|
|
951
996
|
seededByPluginTooltip: "Diese Nachricht wurde vom Plugin {pkg} erstellt und nicht von Ihnen gesendet.",
|
|
997
|
+
truncatedForRender:
|
|
998
|
+
"Diese Nachricht ist ungewöhnlich lang (insgesamt {total} Zeichen). Nur der erste Teil wird angezeigt – {omitted} Zeichen ausgeblendet, damit der Tab reaktionsfähig bleibt. Nutze „Kopieren“ für den vollständigen Text.",
|
|
952
999
|
},
|
|
953
1000
|
pluginSkill: {
|
|
954
1001
|
noDescription: "(keine Beschreibung)",
|
package/src/lang/en.ts
CHANGED
|
@@ -154,6 +154,9 @@ const enMessages = {
|
|
|
154
154
|
disconnectFailed: "Disconnect failed",
|
|
155
155
|
signInFailed: "Google sign-in failed",
|
|
156
156
|
statusFailed: "Failed to load status",
|
|
157
|
+
description: "Remote access lets a mobile device connect to this MulmoClaude's collections and feeds.",
|
|
158
|
+
howTo: "On your phone, open {url} and sign in with the same Google account.",
|
|
159
|
+
customViewHint: "For a mobile-friendly view, ask Claude to build a {keyword} (not a regular custom view).",
|
|
157
160
|
},
|
|
158
161
|
sidebarHeader: {
|
|
159
162
|
home: "Go to latest chat",
|
|
@@ -198,6 +201,8 @@ const enMessages = {
|
|
|
198
201
|
// "RO" = Read-Only. Kept short on purpose — rendered as a compact
|
|
199
202
|
// badge next to the Reference label.
|
|
200
203
|
readOnlyBadge: "RO",
|
|
204
|
+
showSystemFiles: "Show system files",
|
|
205
|
+
showSystemFilesTitle: "Show agent-internal top-level dirs (conversations/, feeds/, etc.) in addition to your user content (data/, artifacts/, config/).",
|
|
201
206
|
},
|
|
202
207
|
fileTree: {
|
|
203
208
|
workspace: "(workspace)",
|
|
@@ -249,6 +254,8 @@ const enMessages = {
|
|
|
249
254
|
photos: "Photos",
|
|
250
255
|
model: "Model",
|
|
251
256
|
voice: "Voice",
|
|
257
|
+
chatIndex: "Chat index",
|
|
258
|
+
journal: "Journal",
|
|
252
259
|
skills: "Skills",
|
|
253
260
|
roles: "Roles",
|
|
254
261
|
},
|
|
@@ -309,6 +316,42 @@ const enMessages = {
|
|
|
309
316
|
loadError: "Failed to load settings",
|
|
310
317
|
saveError: "Failed to save",
|
|
311
318
|
},
|
|
319
|
+
chatIndexTab: {
|
|
320
|
+
description:
|
|
321
|
+
"Background AI titles + summaries for your chat history. Off by default — automation sessions (scheduler / system workers) are always skipped even when on, and human sessions only pay one summarizer call each when a turn ends.",
|
|
322
|
+
modeLabel: "Chat index model",
|
|
323
|
+
helperText: "Haiku is cheaper; Sonnet gives sharper titles for long, topic-shifting sessions.",
|
|
324
|
+
mode: {
|
|
325
|
+
off: "Off",
|
|
326
|
+
haiku: "Haiku",
|
|
327
|
+
sonnet: "Sonnet",
|
|
328
|
+
},
|
|
329
|
+
status: {
|
|
330
|
+
off: "Indexing is OFF",
|
|
331
|
+
haiku: "Indexing with Haiku",
|
|
332
|
+
sonnet: "Indexing with Sonnet",
|
|
333
|
+
},
|
|
334
|
+
loadError: "Failed to load settings",
|
|
335
|
+
saveError: "Failed to save",
|
|
336
|
+
},
|
|
337
|
+
journalTab: {
|
|
338
|
+
description:
|
|
339
|
+
"Automated daily journal — summarises recent chat sessions into journal/*.md and extracts durable memory notes. Off by default. Automation sessions (scheduler / system workers) are always excluded regardless of this setting.",
|
|
340
|
+
modeLabel: "Journal model",
|
|
341
|
+
helperText: "Haiku is cheaper; Sonnet produces richer daily / topic summaries. The hourly pass runs only when this is set.",
|
|
342
|
+
mode: {
|
|
343
|
+
off: "Off",
|
|
344
|
+
haiku: "Haiku",
|
|
345
|
+
sonnet: "Sonnet",
|
|
346
|
+
},
|
|
347
|
+
status: {
|
|
348
|
+
off: "Journal is OFF",
|
|
349
|
+
haiku: "Journal running with Haiku",
|
|
350
|
+
sonnet: "Journal running with Sonnet",
|
|
351
|
+
},
|
|
352
|
+
loadError: "Failed to load settings",
|
|
353
|
+
saveError: "Failed to save",
|
|
354
|
+
},
|
|
312
355
|
// `<i18n-t>` slots — named `envKey` / `envFile` render as inline
|
|
313
356
|
// `<code>` in SettingsModal.vue, so the literal variable and file
|
|
314
357
|
// names stay untranslated while the surrounding copy is localised.
|
|
@@ -961,6 +1004,8 @@ const enMessages = {
|
|
|
961
1004
|
cancel: "Cancel",
|
|
962
1005
|
seededByPlugin: "from {pkg}",
|
|
963
1006
|
seededByPluginTooltip: "This message was seeded by the {pkg} plugin, not sent by you.",
|
|
1007
|
+
truncatedForRender:
|
|
1008
|
+
"This message is unusually long ({total} chars total). Only the first portion is rendered — {omitted} chars hidden to keep the tab responsive. Use Copy for the full raw text.",
|
|
964
1009
|
},
|
|
965
1010
|
pluginSkill: {
|
|
966
1011
|
noDescription: "(no description)",
|
package/src/lang/es.ts
CHANGED
|
@@ -139,6 +139,9 @@ const esMessages = {
|
|
|
139
139
|
disconnectFailed: "Error al desconectar",
|
|
140
140
|
signInFailed: "Error al iniciar sesión con Google",
|
|
141
141
|
statusFailed: "Error al cargar el estado",
|
|
142
|
+
description: "El acceso remoto permite que un dispositivo móvil se conecte a las colecciones y feeds de este MulmoClaude.",
|
|
143
|
+
howTo: "En tu teléfono, abre {url} e inicia sesión con la misma cuenta de Google.",
|
|
144
|
+
customViewHint: "Para una vista compatible con móviles, pide a Claude que cree una {keyword} (no una custom view normal).",
|
|
142
145
|
},
|
|
143
146
|
sidebarHeader: {
|
|
144
147
|
home: "Ir al chat más reciente",
|
|
@@ -183,6 +186,9 @@ const esMessages = {
|
|
|
183
186
|
// "RO" = Read-Only. Se mantiene la abreviatura en inglés para
|
|
184
187
|
// renderizarse como una insignia compacta junto al label Referencia.
|
|
185
188
|
readOnlyBadge: "RO",
|
|
189
|
+
showSystemFiles: "Mostrar archivos del sistema",
|
|
190
|
+
showSystemFilesTitle:
|
|
191
|
+
"Muestra los directorios raíz internos del agente (conversations/, feeds/, etc.) además del contenido del usuario (data/, artifacts/, config/).",
|
|
186
192
|
},
|
|
187
193
|
fileTree: {
|
|
188
194
|
workspace: "(área de trabajo)",
|
|
@@ -234,6 +240,8 @@ const esMessages = {
|
|
|
234
240
|
photos: "Fotos",
|
|
235
241
|
model: "Modelo",
|
|
236
242
|
voice: "Voz",
|
|
243
|
+
chatIndex: "Índice de chat",
|
|
244
|
+
journal: "Diario",
|
|
237
245
|
skills: "Skills",
|
|
238
246
|
roles: "Roles",
|
|
239
247
|
},
|
|
@@ -294,6 +302,42 @@ const esMessages = {
|
|
|
294
302
|
loadError: "Error al cargar los ajustes",
|
|
295
303
|
saveError: "Error al guardar",
|
|
296
304
|
},
|
|
305
|
+
chatIndexTab: {
|
|
306
|
+
description:
|
|
307
|
+
"Títulos y resúmenes automáticos generados por IA para tu historial de chat. Sale desactivado por defecto — las sesiones de automatización (scheduler / trabajadores del sistema) siempre se omiten aunque esté activado; las sesiones humanas solo pagan una llamada al resumidor al terminar cada turno.",
|
|
308
|
+
modeLabel: "Modelo del índice de chat",
|
|
309
|
+
helperText: "Haiku es más económico; Sonnet ofrece títulos más precisos en sesiones largas con cambios de tema.",
|
|
310
|
+
mode: {
|
|
311
|
+
off: "Desactivado",
|
|
312
|
+
haiku: "Haiku",
|
|
313
|
+
sonnet: "Sonnet",
|
|
314
|
+
},
|
|
315
|
+
status: {
|
|
316
|
+
off: "La indexación está DESACTIVADA",
|
|
317
|
+
haiku: "Indexando con Haiku",
|
|
318
|
+
sonnet: "Indexando con Sonnet",
|
|
319
|
+
},
|
|
320
|
+
loadError: "Error al cargar los ajustes",
|
|
321
|
+
saveError: "Error al guardar",
|
|
322
|
+
},
|
|
323
|
+
journalTab: {
|
|
324
|
+
description:
|
|
325
|
+
"Diario automático — resume las sesiones de chat recientes en journal/*.md y extrae notas de memoria duradera. Sale desactivado. Las sesiones de automatización (scheduler / trabajadores del sistema) se excluyen siempre, independientemente de esta configuración.",
|
|
326
|
+
modeLabel: "Modelo del diario",
|
|
327
|
+
helperText: "Haiku es más económico; Sonnet produce resúmenes diarios y por tema más ricos. El pase horario solo se ejecuta cuando esto está activado.",
|
|
328
|
+
mode: {
|
|
329
|
+
off: "Desactivado",
|
|
330
|
+
haiku: "Haiku",
|
|
331
|
+
sonnet: "Sonnet",
|
|
332
|
+
},
|
|
333
|
+
status: {
|
|
334
|
+
off: "El diario está DESACTIVADO",
|
|
335
|
+
haiku: "Diario en ejecución con Haiku",
|
|
336
|
+
sonnet: "Diario en ejecución con Sonnet",
|
|
337
|
+
},
|
|
338
|
+
loadError: "Error al cargar los ajustes",
|
|
339
|
+
saveError: "Error al guardar",
|
|
340
|
+
},
|
|
297
341
|
// Slots `<i18n-t>` — los nombres `envKey` / `envFile` se renderizan
|
|
298
342
|
// como `<code>` en línea en SettingsModal.vue, por lo que los
|
|
299
343
|
// literales de variable y nombre de archivo se mantienen sin
|
|
@@ -947,6 +991,8 @@ const esMessages = {
|
|
|
947
991
|
cancel: "Cancelar",
|
|
948
992
|
seededByPlugin: "desde {pkg}",
|
|
949
993
|
seededByPluginTooltip: "Este mensaje fue generado por el plugin {pkg}, no enviado por ti.",
|
|
994
|
+
truncatedForRender:
|
|
995
|
+
"Este mensaje es inusualmente largo ({total} caracteres en total). Solo se muestra la primera parte — {omitted} caracteres ocultos para mantener la pestaña receptiva. Usa Copiar para obtener el texto completo.",
|
|
950
996
|
},
|
|
951
997
|
pluginSkill: {
|
|
952
998
|
noDescription: "(sin descripción)",
|
package/src/lang/fr.ts
CHANGED
|
@@ -134,6 +134,9 @@ const frMessages = {
|
|
|
134
134
|
disconnectFailed: "Échec de la déconnexion",
|
|
135
135
|
signInFailed: "Échec de la connexion Google",
|
|
136
136
|
statusFailed: "Échec du chargement de l'état",
|
|
137
|
+
description: "L'accès distant permet à un appareil mobile de se connecter aux collections et aux flux de ce MulmoClaude.",
|
|
138
|
+
howTo: "Sur votre téléphone, ouvrez {url} et connectez-vous avec le même compte Google.",
|
|
139
|
+
customViewHint: "Pour une vue adaptée au mobile, demandez à Claude de créer une {keyword} (pas une custom view classique).",
|
|
137
140
|
},
|
|
138
141
|
sidebarHeader: {
|
|
139
142
|
home: "Aller à la dernière conversation",
|
|
@@ -178,6 +181,9 @@ const frMessages = {
|
|
|
178
181
|
// "RO" = Read-Only. Abréviation anglaise conservée volontairement
|
|
179
182
|
// pour tenir dans un badge compact à côté du libellé Référence.
|
|
180
183
|
readOnlyBadge: "RO",
|
|
184
|
+
showSystemFiles: "Afficher les fichiers système",
|
|
185
|
+
showSystemFilesTitle:
|
|
186
|
+
"Affiche les répertoires racine internes de l'agent (conversations/, feeds/, etc.) en plus des contenus utilisateur (data/, artifacts/, config/).",
|
|
181
187
|
},
|
|
182
188
|
fileTree: {
|
|
183
189
|
workspace: "(espace de travail)",
|
|
@@ -229,6 +235,8 @@ const frMessages = {
|
|
|
229
235
|
photos: "Photos",
|
|
230
236
|
model: "Modèle",
|
|
231
237
|
voice: "Voix",
|
|
238
|
+
chatIndex: "Index du chat",
|
|
239
|
+
journal: "Journal",
|
|
232
240
|
skills: "Skills",
|
|
233
241
|
roles: "Rôles",
|
|
234
242
|
},
|
|
@@ -289,6 +297,43 @@ const frMessages = {
|
|
|
289
297
|
loadError: "Échec du chargement des paramètres",
|
|
290
298
|
saveError: "Échec de l'enregistrement",
|
|
291
299
|
},
|
|
300
|
+
chatIndexTab: {
|
|
301
|
+
description:
|
|
302
|
+
"Titres et résumés générés par IA pour l'historique du chat. Désactivé par défaut — les sessions d'automatisation (scheduler / workers système) sont toujours ignorées même quand c'est activé ; les sessions humaines ne paient qu'un appel au résumeur à la fin de chaque tour.",
|
|
303
|
+
modeLabel: "Modèle de l'index de chat",
|
|
304
|
+
helperText: "Haiku est moins cher ; Sonnet donne des titres plus précis pour de longues sessions changeant de sujet.",
|
|
305
|
+
mode: {
|
|
306
|
+
off: "Désactivé",
|
|
307
|
+
haiku: "Haiku",
|
|
308
|
+
sonnet: "Sonnet",
|
|
309
|
+
},
|
|
310
|
+
status: {
|
|
311
|
+
off: "Indexation DÉSACTIVÉE",
|
|
312
|
+
haiku: "Indexation avec Haiku",
|
|
313
|
+
sonnet: "Indexation avec Sonnet",
|
|
314
|
+
},
|
|
315
|
+
loadError: "Échec du chargement des paramètres",
|
|
316
|
+
saveError: "Échec de l'enregistrement",
|
|
317
|
+
},
|
|
318
|
+
journalTab: {
|
|
319
|
+
description:
|
|
320
|
+
"Journal quotidien automatisé — résume les sessions de chat récentes dans journal/*.md et extrait des notes de mémoire persistante. Désactivé par défaut. Les sessions d'automatisation (scheduler / workers système) sont toujours exclues, quel que soit ce réglage.",
|
|
321
|
+
modeLabel: "Modèle du journal",
|
|
322
|
+
helperText:
|
|
323
|
+
"Haiku est moins cher ; Sonnet produit des résumés quotidiens et thématiques plus riches. Le passage horaire ne s'exécute que lorsque c'est activé.",
|
|
324
|
+
mode: {
|
|
325
|
+
off: "Désactivé",
|
|
326
|
+
haiku: "Haiku",
|
|
327
|
+
sonnet: "Sonnet",
|
|
328
|
+
},
|
|
329
|
+
status: {
|
|
330
|
+
off: "Journal DÉSACTIVÉ",
|
|
331
|
+
haiku: "Journal en cours avec Haiku",
|
|
332
|
+
sonnet: "Journal en cours avec Sonnet",
|
|
333
|
+
},
|
|
334
|
+
loadError: "Échec du chargement des paramètres",
|
|
335
|
+
saveError: "Échec de l'enregistrement",
|
|
336
|
+
},
|
|
292
337
|
// Slots `<i18n-t>` — les noms `envKey` / `envFile` sont rendus sous
|
|
293
338
|
// forme de `<code>` inline dans SettingsModal.vue ; les littéraux
|
|
294
339
|
// (nom de variable et nom de fichier) restent donc non traduits.
|
|
@@ -937,6 +982,8 @@ const frMessages = {
|
|
|
937
982
|
cancel: "Annuler",
|
|
938
983
|
seededByPlugin: "depuis {pkg}",
|
|
939
984
|
seededByPluginTooltip: "Ce message a été généré par le plugin {pkg}, et non envoyé par vous.",
|
|
985
|
+
truncatedForRender:
|
|
986
|
+
"Ce message est exceptionnellement long ({total} caractères au total). Seule la première partie est affichée — {omitted} caractères masqués pour garder l'onglet réactif. Utilisez « Copier » pour obtenir le texte complet.",
|
|
940
987
|
},
|
|
941
988
|
pluginSkill: {
|
|
942
989
|
noDescription: "(aucune description)",
|
package/src/lang/ja.ts
CHANGED
|
@@ -139,6 +139,9 @@ const jaMessages = {
|
|
|
139
139
|
disconnectFailed: "切断に失敗しました",
|
|
140
140
|
signInFailed: "Google サインインに失敗しました",
|
|
141
141
|
statusFailed: "状態の取得に失敗しました",
|
|
142
|
+
description: "リモートアクセスを有効にすると、モバイルデバイスからこの MulmoClaude のコレクションとフィードに接続できます。",
|
|
143
|
+
howTo: "モバイルから {url} を開き、同じ Google アカウントでサインインしてください。",
|
|
144
|
+
customViewHint: "モバイル向けのビューが必要な場合は、通常の custom view ではなく {keyword} を作るように Claude に依頼してください。",
|
|
142
145
|
},
|
|
143
146
|
sidebarHeader: {
|
|
144
147
|
home: "最新のチャットに移動",
|
|
@@ -181,6 +184,9 @@ const jaMessages = {
|
|
|
181
184
|
recent: "最近",
|
|
182
185
|
reference: "参照",
|
|
183
186
|
readOnlyBadge: "RO",
|
|
187
|
+
showSystemFiles: "システムファイルを表示",
|
|
188
|
+
showSystemFilesTitle:
|
|
189
|
+
"エージェント内部の top-level ディレクトリ (conversations/ や feeds/ など) をユーザーデータ (data/ artifacts/ config/) と合わせて表示します。",
|
|
184
190
|
},
|
|
185
191
|
fileTree: {
|
|
186
192
|
workspace: "(ワークスペース)",
|
|
@@ -232,6 +238,8 @@ const jaMessages = {
|
|
|
232
238
|
photos: "写真",
|
|
233
239
|
model: "モデル",
|
|
234
240
|
voice: "音声",
|
|
241
|
+
chatIndex: "チャットインデックス",
|
|
242
|
+
journal: "ジャーナル",
|
|
235
243
|
skills: "スキル",
|
|
236
244
|
roles: "ロール",
|
|
237
245
|
},
|
|
@@ -292,6 +300,42 @@ const jaMessages = {
|
|
|
292
300
|
loadError: "設定の読み込みに失敗しました",
|
|
293
301
|
saveError: "保存に失敗しました",
|
|
294
302
|
},
|
|
303
|
+
chatIndexTab: {
|
|
304
|
+
description:
|
|
305
|
+
"チャット履歴の AI タイトル/サマリー自動生成の設定です。デフォルトは off で、自動化系のセッション(scheduler / system worker)は on にしても常に除外されます。人間のセッションのみターン終了時に 1 回要約が走ります。",
|
|
306
|
+
modeLabel: "チャットインデックスのモデル",
|
|
307
|
+
helperText: "Haiku は安価。Sonnet は長く話題が移るセッションでタイトル品質が高くなります。",
|
|
308
|
+
mode: {
|
|
309
|
+
off: "オフ",
|
|
310
|
+
haiku: "Haiku",
|
|
311
|
+
sonnet: "Sonnet",
|
|
312
|
+
},
|
|
313
|
+
status: {
|
|
314
|
+
off: "インデックス作成: オフ",
|
|
315
|
+
haiku: "Haiku でインデックス作成中",
|
|
316
|
+
sonnet: "Sonnet でインデックス作成中",
|
|
317
|
+
},
|
|
318
|
+
loadError: "設定の読み込みに失敗しました",
|
|
319
|
+
saveError: "保存に失敗しました",
|
|
320
|
+
},
|
|
321
|
+
journalTab: {
|
|
322
|
+
description:
|
|
323
|
+
"ジャーナル日次パスの設定です。最近のチャットセッションを journal/*.md に要約し、恒久メモリ(memory.md)を抽出します。デフォルトは off。自動化系セッション(scheduler / system worker)はこの設定に関わらず常に除外されます。",
|
|
324
|
+
modeLabel: "ジャーナルのモデル",
|
|
325
|
+
helperText: "Haiku は安価。Sonnet は日次/トピックまとめの質が高くなります。毎時のパスはここが on の時のみ実行されます。",
|
|
326
|
+
mode: {
|
|
327
|
+
off: "オフ",
|
|
328
|
+
haiku: "Haiku",
|
|
329
|
+
sonnet: "Sonnet",
|
|
330
|
+
},
|
|
331
|
+
status: {
|
|
332
|
+
off: "ジャーナル: オフ",
|
|
333
|
+
haiku: "Haiku でジャーナル実行中",
|
|
334
|
+
sonnet: "Sonnet でジャーナル実行中",
|
|
335
|
+
},
|
|
336
|
+
loadError: "設定の読み込みに失敗しました",
|
|
337
|
+
saveError: "保存に失敗しました",
|
|
338
|
+
},
|
|
295
339
|
// `<i18n-t>` スロット — `envKey` / `envFile` は SettingsModal.vue で
|
|
296
340
|
// インラインの `<code>` として描画されるため、変数名とファイル名は
|
|
297
341
|
// 翻訳せずそのまま残します。
|
|
@@ -935,6 +979,8 @@ const jaMessages = {
|
|
|
935
979
|
cancel: "キャンセル",
|
|
936
980
|
seededByPlugin: "{pkg} から",
|
|
937
981
|
seededByPluginTooltip: "このメッセージは {pkg} プラグインによって作成されたもので、あなたが送信したものではありません。",
|
|
982
|
+
truncatedForRender:
|
|
983
|
+
"このメッセージは非常に長いため(全 {total} 文字)、描画のフリーズを防ぐため先頭のみ表示しています({omitted} 文字を省略)。全文はコピーボタンから取得できます。",
|
|
938
984
|
},
|
|
939
985
|
pluginSkill: {
|
|
940
986
|
noDescription: "(説明なし)",
|