@mulmoclaude/core 4.9.0 → 4.9.2

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 (87) hide show
  1. package/assets/helps/bug-report-faq.md +12 -0
  2. package/assets/helps/error-recovery.md +144 -29
  3. package/assets/helps/sandbox.md +2 -2
  4. package/dist/collection/index.cjs +3 -2
  5. package/dist/collection/index.cjs.map +1 -1
  6. package/dist/collection/index.js +3 -2
  7. package/dist/collection/index.js.map +1 -1
  8. package/dist/collection/registry/server/index.cjs +3 -3
  9. package/dist/collection/registry/server/index.js +3 -3
  10. package/dist/collection/server/index.cjs +2 -2
  11. package/dist/collection/server/index.js +2 -2
  12. package/dist/collection-watchers/index.cjs +4 -4
  13. package/dist/collection-watchers/index.js +4 -4
  14. package/dist/{discovery-BY-nMCuh.js → discovery-BkIKvdh0.js} +3 -3
  15. package/dist/discovery-BkIKvdh0.js.map +1 -0
  16. package/dist/{discovery-2TvulIz8.cjs → discovery-tvFo-bUJ.cjs} +3 -3
  17. package/dist/discovery-tvFo-bUJ.cjs.map +1 -0
  18. package/dist/{dist-D8zokgGo.js → dist-BzoA9pDR.js} +6 -1
  19. package/dist/dist-BzoA9pDR.js.map +1 -0
  20. package/dist/{dist-CsgSfWwR.cjs → dist-Gj7ygaW2.cjs} +6 -1
  21. package/dist/dist-Gj7ygaW2.cjs.map +1 -0
  22. package/dist/errorMessage-BQNpSYdT.js +1 -0
  23. package/dist/errorMessage-CT-va_Pv.cjs +1 -0
  24. package/dist/errors-C7TI_t_4.js +10 -0
  25. package/dist/errors-C7TI_t_4.js.map +1 -0
  26. package/dist/errors-CdXsfFCF.cjs +15 -0
  27. package/dist/errors-CdXsfFCF.cjs.map +1 -0
  28. package/dist/feeds/server/index.cjs +4 -4
  29. package/dist/feeds/server/index.js +4 -4
  30. package/dist/google/index.cjs +3 -2
  31. package/dist/google/index.cjs.map +1 -1
  32. package/dist/google/index.js +3 -2
  33. package/dist/google/index.js.map +1 -1
  34. package/dist/{listen-UZA68Upt.cjs → listen-BXthb-9C.cjs} +2 -2
  35. package/dist/{listen-UZA68Upt.cjs.map → listen-BXthb-9C.cjs.map} +1 -1
  36. package/dist/{listen-D5av7GzB.js → listen-Dca-NoBi.js} +2 -2
  37. package/dist/{listen-D5av7GzB.js.map → listen-Dca-NoBi.js.map} +1 -1
  38. package/dist/notifier/index.cjs +1 -1
  39. package/dist/notifier/index.js +1 -1
  40. package/dist/notifier/types.d.ts +20 -11
  41. package/dist/{notifier-DZJj0sOh.cjs → notifier-B65Mvngb.cjs} +12 -7
  42. package/dist/notifier-B65Mvngb.cjs.map +1 -0
  43. package/dist/{notifier-DhnwR82U.js → notifier-vAp5t6wL.js} +12 -7
  44. package/dist/notifier-vAp5t6wL.js.map +1 -0
  45. package/dist/{promptSafety-Bte62OvU.js → promptSafety-BpBTh5xO.js} +2 -2
  46. package/dist/{promptSafety-Bte62OvU.js.map → promptSafety-BpBTh5xO.js.map} +1 -1
  47. package/dist/{promptSafety-Cv-SoTd4.cjs → promptSafety-caJWd1ZQ.cjs} +2 -2
  48. package/dist/{promptSafety-Cv-SoTd4.cjs.map → promptSafety-caJWd1ZQ.cjs.map} +1 -1
  49. package/dist/remote-host/index.cjs +1 -1
  50. package/dist/remote-host/index.js +1 -1
  51. package/dist/remote-host/server/index.cjs +4 -3
  52. package/dist/remote-host/server/index.cjs.map +1 -1
  53. package/dist/remote-host/server/index.js +4 -3
  54. package/dist/remote-host/server/index.js.map +1 -1
  55. package/dist/{remote-host-CFnl1I-L.js → remote-host-Cjox2F2J.js} +2 -2
  56. package/dist/{remote-host-CFnl1I-L.js.map → remote-host-Cjox2F2J.js.map} +1 -1
  57. package/dist/{remote-host-EQPlccB9.cjs → remote-host-DhAHBYzN.cjs} +2 -2
  58. package/dist/{remote-host-EQPlccB9.cjs.map → remote-host-DhAHBYzN.cjs.map} +1 -1
  59. package/dist/remote-view/index.cjs +1 -1
  60. package/dist/remote-view/index.js +1 -1
  61. package/dist/scheduler/index.cjs +2 -1
  62. package/dist/scheduler/index.cjs.map +1 -1
  63. package/dist/scheduler/index.js +2 -1
  64. package/dist/scheduler/index.js.map +1 -1
  65. package/dist/{server-DXUt34Rt.cjs → server-Div1i_k5.cjs} +5 -4
  66. package/dist/{server-DXUt34Rt.cjs.map → server-Div1i_k5.cjs.map} +1 -1
  67. package/dist/{server-DyYwfNB6.js → server-Dk9x1VLG.js} +5 -4
  68. package/dist/{server-DyYwfNB6.js.map → server-Dk9x1VLG.js.map} +1 -1
  69. package/dist/utils/index.cjs +3 -10
  70. package/dist/utils/index.js +2 -9
  71. package/dist/whisper/index.cjs +2 -1
  72. package/dist/whisper/index.cjs.map +1 -1
  73. package/dist/whisper/index.js +2 -1
  74. package/dist/whisper/index.js.map +1 -1
  75. package/dist/wiki/index.cjs +1 -1
  76. package/dist/wiki/index.js +1 -1
  77. package/dist/workspace-setup/index.js +5 -0
  78. package/dist/workspace-setup/index.js.map +1 -1
  79. package/package.json +5 -5
  80. package/dist/discovery-2TvulIz8.cjs.map +0 -1
  81. package/dist/discovery-BY-nMCuh.js.map +0 -1
  82. package/dist/dist-CsgSfWwR.cjs.map +0 -1
  83. package/dist/dist-D8zokgGo.js.map +0 -1
  84. package/dist/notifier-DZJj0sOh.cjs.map +0 -1
  85. package/dist/notifier-DhnwR82U.js.map +0 -1
  86. package/dist/utils/index.cjs.map +0 -1
  87. package/dist/utils/index.js.map +0 -1
@@ -56,6 +56,18 @@ settings is the user's opt-in. The RemoteHost channel must also be connected —
56
56
  what supplies the Firebase auth, so with the phone link down the send is a no-op by design. A user
57
57
  who never connected a phone has nothing to receive the push regardless of the setting.
58
58
 
59
+ ## MulmoClaude is answering with a different model than I expected
60
+
61
+ configKey: chatModel
62
+ source: server/agent/config.ts
63
+
64
+ Read `chatModel` from the live settings. Absent means MulmoClaude passes no `--model` at all and the
65
+ CLI resolves the model from `~/.claude/settings.json` — the same file the VS Code and Cursor Claude
66
+ Code extensions write their `/model` pick to, so a switch made in another editor changes MulmoClaude
67
+ too, with nothing on screen to say so. Setting the key from Settings → Model is what pins MulmoClaude
68
+ independently of that shared file. A session already running keeps its model until the next turn, so
69
+ "it changed partway through a conversation" is the expected shape of this, not a second bug.
70
+
59
71
  ## My chats never get titles or summaries
60
72
 
61
73
  configKey: chatIndex
@@ -124,11 +124,17 @@ Report body:
124
124
 
125
125
  ```markdown
126
126
  ## What happened
127
+
127
128
  ## What I expected
129
+
128
130
  ## Steps to reproduce
131
+
129
132
  1.
133
+
130
134
  ## Environment
135
+
131
136
  (paste the diagnostics report here)
137
+
132
138
  ## Attachments
133
139
  ```
134
140
 
@@ -280,7 +286,7 @@ naming the file:
280
286
  quotes, unquoted key.
281
287
  - `role file does not match the role schema, skipping` — the `issues`
282
288
  field names each field, e.g. `icon: Invalid input: expected string,
283
- received undefined`. All of `id`, `name`, `icon`, `prompt`,
289
+ received undefined`. All of `id`, `name`, `icon`, `prompt`,
284
290
  `availablePlugins` are required; `availablePlugins` must be an array
285
291
  even for one entry.
286
292
  - `role file is empty, skipping` — zero-length or whitespace only.
@@ -328,7 +334,7 @@ it:
328
334
  `my role.json`, rejected as `Invalid role id 'my role'.` Neither name
329
335
  reaches the role. Renaming is the only fix.
330
336
  - `… the id is not a usable role id` — the reverse, e.g. `"id": "my
331
- role"` in `designer.json`. `delete designer` still works, and renaming
337
+ role"` in `designer.json`. `delete designer` still works, and renaming
332
338
  to `my role.json` would take that away. Change the `id`.
333
339
  - `… neither is a usable role id` — pick one id that matches the pattern
334
340
  and use it for the file name and the `id` together.
@@ -543,9 +549,10 @@ user's file by re-encoding it.
543
549
  A collection whose schema declares `storage: { type: "sqlite", path: … }`
544
550
  keeps its records in a single SQLite database file, read/written through
545
551
  Node's BUILT-IN `node:sqlite` module — no npm dependency. That module
546
- exists only in **Node.js >= 22.5**, while the app itself runs on >= 20.12,
547
- so on an older runtime ONLY sqlite-backed collections break (file and
548
- dataSource collections keep working) and every operation fails with
552
+ exists only in **Node.js >= 22.5**. The app's own floor is >= 22.19, so a
553
+ supported runtime always has it and this failure means a Node built without
554
+ the module. Only sqlite-backed collections break (file and dataSource
555
+ collections keep working); every operation fails with
549
556
  `sqlite storage needs the node:sqlite module (Node.js >= 22.5) — this
550
557
  runtime cannot load it`.
551
558
 
@@ -926,12 +933,12 @@ They are genuinely different failures — a permanent load failure, a startup ra
926
933
  and guessing between them is what makes this expensive. Since #2842 the log answers it directly,
927
934
  so read these three before forming a theory:
928
935
 
929
- | Log line | What it tells you |
930
- |---|---|
931
- | `spawning agent … broker=tsx` | This install is on the SLOW path: the bundle is missing, so the broker is transcoded from source on every spawn (seconds to tens of seconds over a Windows/macOS bind mount). A `broker bundle missing` warn accompanies it once per process. |
932
- | `[mcp] broker ready bootMs=… initializeMs=…` | The broker DID connect, and how long it took. `broker cold boot is slow` replaces it past 5 s. |
933
- | `brokerEverReady=false reason=never-ready` on the retry warn | No beacon arrived for that chat, and the host kept looking until the beacon's own delivery budget was spent — the broker did not come up at all. The turn is NOT replayed: a replay would sit out another full connect wait and end in the same error. |
934
- | `reason=ready-during-wait` on the retry warn | The beacon arrived while the host waited, so the broker lost the race by a moment and IS connected now. The turn is replayed, which is what fixes this one. |
936
+ | Log line | What it tells you |
937
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
938
+ | `spawning agent … broker=tsx` | This install is on the SLOW path: the bundle is missing, so the broker is transcoded from source on every spawn (seconds to tens of seconds over a Windows/macOS bind mount). A `broker bundle missing` warn accompanies it once per process. |
939
+ | `[mcp] broker ready bootMs=… initializeMs=…` | The broker DID connect, and how long it took. `broker cold boot is slow` replaces it past 5 s. |
940
+ | `brokerEverReady=false reason=never-ready` on the retry warn | No beacon arrived for that chat, and the host kept looking until the beacon's own delivery budget was spent — the broker did not come up at all. The turn is NOT replayed: a replay would sit out another full connect wait and end in the same error. |
941
+ | `reason=ready-during-wait` on the retry warn | The beacon arrived while the host waited, so the broker lost the race by a moment and IS connected now. The turn is replayed, which is what fixes this one. |
935
942
  | `brokerEverStarted=` on the `MCP tools were unavailable` warn | Whether the broker PROCESS ever existed, which is a different question from whether it answered. `true` with `brokerEverReady=false` means it launched and never finished booting — the boot is the problem (the mount, the `tsx` path). `false` means it never launched — the spawn is the problem. Diagnostic only, and not authenticated: under Docker everything needed to forge it sits in the per-session MCP config inside the workspace mount, so read it as evidence about a healthy install rather than as proof against a hostile one. |
936
943
 
937
944
  ### Fix
@@ -968,7 +975,7 @@ so read these three before forming a theory:
968
975
 
969
976
  - The `google` tool (or a `google.calendar.*` remote command) fails with **"Google account not linked on this host"**.
970
977
  - **"Google sign-in service unreachable"** or **"Google sign-in service returned HTTP …"**.
971
- - **"multiple client_secret_*.json files found"**.
978
+ - **"multiple client_secret\_*.json files found"**.
972
979
  - **"Google Calendar API: HTTP 403"** with a hint about enabling the API.
973
980
  - **"Google Calendar API: HTTP 403 — Request had insufficient authentication scopes"** when pushing
974
981
  a collection to a calendar that is NOT in the account's own calendar list.
@@ -1121,8 +1128,7 @@ Pass the file instead. `putItems` accepts **`itemsFile`** — an absolute path t
1121
1128
  a JSON file holding the array of record objects, read by the host:
1122
1129
 
1123
1130
  ```jsonc
1124
- { "action": "putItems", "slug": "slots", "mode": "create",
1125
- "itemsFile": "/absolute/path/to/generated-slots.json" }
1131
+ { "action": "putItems", "slug": "slots", "mode": "create", "itemsFile": "/absolute/path/to/generated-slots.json" }
1126
1132
  ```
1127
1133
 
1128
1134
  Write the generated file **under the workspace**. Paths outside it are refused:
@@ -1144,17 +1150,17 @@ Rules that make it fail cleanly rather than silently:
1144
1150
 
1145
1151
  Reading the refusal you got:
1146
1152
 
1147
- | Message | What it means |
1148
- | --- | --- |
1149
- | `must be an ABSOLUTE path` | You passed a relative path. Pass the full one. |
1150
- | `must be inside the workspace` | The file is outside the workspace (or a symlink out of it). Regenerate it under the workspace. |
1151
- | `is a symbolic link` | Symlinks are never followed. Pass the real path. |
1152
- | `changed while it was being opened` | The file was replaced mid-call. Finish writing it, then call putItems. |
1153
- | `grew while it was being read` | The file was still being written. Wait for the script to finish, then call putItems. |
1154
- | `could not read \`itemsFile\`` | The host cannot see that path — the usual cause is a file written to a temp dir outside the mount. Write it under the workspace. |
1155
- | `is not a regular file` | The path is a directory, device, or fifo. |
1156
- | `could not be read as JSON` | The file exists and was read, but does not parse. This is YOUR file's shape, not a host problem — check the script that wrote it (a truncated write, a trailing comma, log output mixed into the file). |
1157
- | `must hold a non-empty JSON array of record objects` | It parsed, but is `[]`, an object, or an array of scalars. The file must be `[{…}, {…}]` — the same row objects you would have passed as `items`. |
1153
+ | Message | What it means |
1154
+ | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1155
+ | `must be an ABSOLUTE path` | You passed a relative path. Pass the full one. |
1156
+ | `must be inside the workspace` | The file is outside the workspace (or a symlink out of it). Regenerate it under the workspace. |
1157
+ | `is a symbolic link` | Symlinks are never followed. Pass the real path. |
1158
+ | `changed while it was being opened` | The file was replaced mid-call. Finish writing it, then call putItems. |
1159
+ | `grew while it was being read` | The file was still being written. Wait for the script to finish, then call putItems. |
1160
+ | `could not read \`itemsFile\`` | The host cannot see that path — the usual cause is a file written to a temp dir outside the mount. Write it under the workspace. |
1161
+ | `is not a regular file` | The path is a directory, device, or fifo. |
1162
+ | `could not be read as JSON` | The file exists and was read, but does not parse. This is YOUR file's shape, not a host problem — check the script that wrote it (a truncated write, a trailing comma, log output mixed into the file). |
1163
+ | `must hold a non-empty JSON array of record objects` | It parsed, but is `[]`, an object, or an array of scalars. The file must be `[{…}, {…}]` — the same row objects you would have passed as `items`. |
1158
1164
 
1159
1165
  Do NOT spawn the MCP bridge yourself. A hand-written JSON-RPC client fails
1160
1166
  invisibly and can leave a partially written collection that nothing reports.
@@ -1196,10 +1202,14 @@ the calendar can place. So format the string, never convert it:
1196
1202
 
1197
1203
  ```js
1198
1204
  // WRONG — appends `Z` and shifts the hours by the generating machine's offset
1199
- { startAt: new Date(`${day}T08:00`).toISOString() } // "2026-08-17T15:00:00.000Z"
1205
+ {
1206
+ startAt: new Date(`${day}T08:00`).toISOString();
1207
+ } // "2026-08-17T15:00:00.000Z"
1200
1208
 
1201
1209
  // RIGHT — the clock you meant, written as the clock
1202
- { startAt: `${day}T08:00` } // "2026-08-17T08:00"
1210
+ {
1211
+ startAt: `${day}T08:00`;
1212
+ } // "2026-08-17T08:00"
1203
1213
  ```
1204
1214
 
1205
1215
  The conversion is the more expensive half: had the format passed, a Tokyo court's
@@ -1249,7 +1259,7 @@ second line, with the plugin-load errors above it, is what a bug report needs.
1249
1259
  ### Symptoms
1250
1260
 
1251
1261
  - Reading or writing a collection fails with `shared collection unavailable:
1252
- connect remote-host first`.
1262
+ connect remote-host first`.
1253
1263
  - A collection whose `schema.json` declares `"storage": { "type": "firestore" }`
1254
1264
  never appears in the list at all.
1255
1265
  - Reads and writes fail with `permission-denied` from Firestore even though the
@@ -1269,7 +1279,7 @@ The backend deliberately fails loudly instead of returning nothing.
1269
1279
 
1270
1280
  2. **The collection never appears** — discovery REFUSED the schema, and the
1271
1281
  reason is in the server log under `collections` (`schema.json rejected after
1272
- validation, skipping`). For a shared collection the usual reason is the app
1282
+ validation, skipping`). For a shared collection the usual reason is the app
1273
1283
  declaration: `apps/{aid}/collections/{cid}/items` needs an `aid`, which comes
1274
1284
  from `app.json` at the repository root, not from the schema.
1275
1285
 
@@ -1382,6 +1392,14 @@ treatment, and the workspace mounted if you want it to follow the port.
1382
1392
  message.
1383
1393
  - The platform token (bot token, app token) was revoked or regenerated.
1384
1394
  - The bridge process is not running at all. Check before assuming anything above.
1395
+ Since #3084 a bridge that died says why on its last line — `[<transport>]
1396
+ unhandled rejection — exiting: …` or `[<transport>] uncaught exception —
1397
+ exiting: …`, naming the transport. A bridge stopped on purpose names the
1398
+ signal: Ctrl-C prints `[<transport>] SIGINT — shutting down`, while a plain
1399
+ `kill <pid>` sends SIGTERM and prints `[<transport>] SIGTERM — shutting down`.
1400
+ **No such line and the process gone** means either an older npm build (they
1401
+ had no handlers at all, so a missed `await` left only a stack trace) or a kill
1402
+ no handler can catch (`kill -9` / SIGKILL, or the OOM killer).
1385
1403
 
1386
1404
  ### What to collect if none of it explains the silence
1387
1405
 
@@ -1391,6 +1409,54 @@ the server's `[server] listening port=…` line, and whether
1391
1409
  port, and did the bridge agree" — which is what every one of these turns out to
1392
1410
  be.
1393
1411
 
1412
+ ## A webhook bridge exits at startup, or never binds its port
1413
+
1414
+ ### Symptoms
1415
+
1416
+ One of the webhook bridges — `line`, `line-works`, `google-chat`, `messenger`,
1417
+ `teams`, `twilio-sms`, `viber`, `webhook`, `whatsapp` — exits immediately after
1418
+ being started, printing one of:
1419
+
1420
+ ```text
1421
+ Port 3002 is already in use. Set LINE_BRIDGE_PORT to a free port, or LINE_BRIDGE_PORT=0 to let the OS pick one.
1422
+ LINE_BRIDGE_PORT="302a" is not a usable port. Set it to an integer from 0 to 65535 (LINE_BRIDGE_PORT=0 asks the OS for a free port), or unset it to use 3002.
1423
+ ```
1424
+
1425
+ Both name the env var to change, and each bridge has its own — `WEBHOOK_PORT`,
1426
+ `TWILIO_WEBHOOK_PORT`, `VIBER_WEBHOOK_PORT` and so on. Read the message rather
1427
+ than guessing the name.
1428
+
1429
+ ### "Already in use" is usually the server, not a second bridge
1430
+
1431
+ The server's port walk (3002-3021) covers the whole bridge band (3002-3013), so
1432
+ a server that found 3001 busy and moved forward can be sitting on a bridge's
1433
+ default. Check what the server actually bound before moving the bridge:
1434
+
1435
+ ```bash
1436
+ cat "${MULMOCLAUDE_WORKSPACE_PATH:-$HOME/mulmoclaude}/.server-port"
1437
+ lsof -nP -iTCP:3002 -sTCP:LISTEN
1438
+ ```
1439
+
1440
+ Two ways out, both fine:
1441
+
1442
+ - Give the bridge a port outside the server's band: `LINE_BRIDGE_PORT=3200`.
1443
+ - Let the OS choose: `LINE_BRIDGE_PORT=0`. The startup banner then names the
1444
+ port it actually got — read the banner, not the env var, when tunnelling to it
1445
+ (`Webhook listening on http://localhost:52431/webhook`).
1446
+
1447
+ ### Before #3084 both of these were silent
1448
+
1449
+ A bridge of that vintage reads its port as `Number(process.env.X) || <default>`
1450
+ and calls a bare `app.listen`. So a **typo ran on the default without a word**
1451
+ (`302a` → `NaN` → falsy → the default), `X=0` was impossible (falsy too), and a
1452
+ busy port surfaced as an unhandled `EADDRINUSE` with no mention of which env var
1453
+ to change. If neither message above appears and the bridge simply dies, or it is
1454
+ answering on a port you did not ask for, that is the old build: reinstall it
1455
+ (`npm i -g @mulmobridge/<platform>@latest`).
1456
+
1457
+ A bridge that starts but never replies is a different failure — see "A messaging
1458
+ bridge's bot does not reply, and nothing errors" above.
1459
+
1394
1460
  ## `renderShapeScript` says Chromium is not installed
1395
1461
 
1396
1462
  `renderShapeScript` rasterises a ShapeScript model by driving Puppeteer's
@@ -1420,3 +1486,52 @@ The same message with `(launch failed: …)` appended means the browser is
1420
1486
  installed but would not start — usually a sandbox with no permission to
1421
1487
  spawn it. Report the parenthesised reason to the user rather than the
1422
1488
  install hint alone.
1489
+
1490
+ ## The server refuses to start — "MulmoClaude is already running against this workspace"
1491
+
1492
+ ### Symptoms
1493
+
1494
+ - `yarn dev`, `yarn server` or `npx mulmoclaude` exits immediately with:
1495
+ `MulmoClaude is already running against this workspace at http://localhost:<port>`
1496
+ - It happens even with a free port named explicitly (`PORT=3100 yarn dev`).
1497
+
1498
+ ### Why
1499
+
1500
+ Two servers over one workspace overwrite each other's `.session-token`. After
1501
+ that a stateless plugin dispatch authenticates cleanly against the *wrong*
1502
+ server, while the session-scoped `/api/internal/tool-result` push lands where
1503
+ the session does not exist and is dropped — so plugin views simply never render
1504
+ on one of the two and nothing reports an error. The guard refuses that setup
1505
+ rather than letting it happen quietly (#3079).
1506
+
1507
+ The check reads `<workspace>/.server-port` and probes the port it names, so it
1508
+ is about the WORKSPACE, not the port: a busy 3001 held by some other program
1509
+ still walks forward as before.
1510
+
1511
+ ### Fix
1512
+
1513
+ Usually the message is right and there is already a server to use — open the URL
1514
+ it printed.
1515
+
1516
+ To run a genuinely separate second instance, give it its own workspace (no flag
1517
+ needed, this is the supported shape):
1518
+
1519
+ ```bash
1520
+ MULMOCLAUDE_WORKSPACE_PATH=~/mulmoclaude-scratch PORT=3100 yarn dev
1521
+ ```
1522
+
1523
+ If the first server was killed hard (`kill -9`, a crashed container) the sidecar
1524
+ can name a port something else has since taken; the probe treats a non-MulmoClaude
1525
+ answer as "nobody there", so that case does not stop a launch. A stop therefore
1526
+ means a real instance answered.
1527
+
1528
+ To share one workspace between two servers anyway — accepting the token stomping:
1529
+
1530
+ ```bash
1531
+ MULMOCLAUDE_ALLOW_MULTIPLE_INSTANCES=1 yarn dev
1532
+ ```
1533
+
1534
+ Use the env var for `yarn dev`. The `--allow-multiple-instances` flag works on
1535
+ `npx mulmoclaude` and `yarn server`, but **not** on `yarn dev`: that is a compound
1536
+ `a && b && c` script, yarn appends extra args to the last command only, and the
1537
+ guard that stops the launch runs in the first one.
@@ -23,11 +23,11 @@ The container runs with `--cap-drop ALL` and as the host user's UID/GID, so it h
23
23
 
24
24
  ## Disabling the Sandbox
25
25
 
26
- Set the environment variable `DISABLE_SANDBOX=1` to always run the agent directly on the host, even when Docker is available. Equivalently, pass the `--disable-sandbox` CLI flag — `yarn dev --disable-sandbox` or `npx mulmoclaude --disable-sandbox`. The flag form is handy on Windows PowerShell (no inline `VAR=value` syntax), in IDE / launcher run configs, and for quick ad-hoc debugging. Both set the same internal switch; the env var stays supported in parallel.
26
+ Set the environment variable `DISABLE_SANDBOX=1` to always run the agent directly on the host, even when Docker is available. Equivalently, pass the `--disable-sandbox` CLI flag — `npx mulmoclaude --disable-sandbox` or `yarn server --disable-sandbox` (**not** `yarn dev`, whose compound script drops trailing args; use the env var there). The flag form is handy on Windows PowerShell (no inline `VAR=value` syntax), in IDE / launcher run configs, and for quick ad-hoc debugging. Both set the same internal switch; the env var stays supported in parallel.
27
27
 
28
28
  ## Debug aids (opt-in env vars)
29
29
 
30
- These flags exist for development / debugging only. Off by default so production runs aren't surprised. Each has an equivalent `--flag` CLI form (drop the `=1`, kebab-case the name) accepted by both `yarn dev` and `npx mulmoclaude` — e.g. `DISABLE_SANDBOX=1` ≡ `--disable-sandbox`, `PERSIST_TOOL_CALLS=1` ≡ `--persist-tool-calls`, `DISABLE_MACOS_REMINDER_NOTIFICATIONS=1` ≡ `--disable-macos-reminders`, `JOURNAL_FORCE_RUN_ON_STARTUP=1` ≡ `--journal-force-run`, `CHAT_INDEX_FORCE_RUN_ON_STARTUP=1` ≡ `--chat-index-force-run`. Secret-bearing vars (auth token, API keys) have no flag form on purpose — argv is visible via `ps` / shell history.
30
+ These flags exist for development / debugging only. Off by default so production runs aren't surprised. Each has an equivalent `--flag` CLI form (drop the `=1`, kebab-case the name) accepted by `npx mulmoclaude` and `yarn server` — but **not** `yarn dev`, which drops trailing args — e.g. `DISABLE_SANDBOX=1` ≡ `--disable-sandbox`, `PERSIST_TOOL_CALLS=1` ≡ `--persist-tool-calls`, `DISABLE_MACOS_REMINDER_NOTIFICATIONS=1` ≡ `--disable-macos-reminders`, `JOURNAL_FORCE_RUN_ON_STARTUP=1` ≡ `--journal-force-run`, `CHAT_INDEX_FORCE_RUN_ON_STARTUP=1` ≡ `--chat-index-force-run`. Secret-bearing vars (auth token, API keys) have no flag form on purpose — argv is visible via `ps` / shell history.
31
31
 
32
32
  - `DISABLE_SANDBOX=1` — see above. Bypasses the Docker sandbox.
33
33
  - `PERSIST_TOOL_CALLS=1` — also persist `tool_call` events to the session jsonl alongside `tool_result`. Useful for reading the args sent to a tool after the run is over (page refresh / server restart). Off by default because args can be large and may carry payload bytes (inline images, full MulmoScript JSON) you didn't expect to land in the jsonl. See [issue #1096](https://github.com/receptron/mulmoclaude/issues/1096) for the rationale.
@@ -1,9 +1,10 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../dist-CsgSfWwR.cjs");
2
+ const require_dist = require("../dist-Gj7ygaW2.cjs");
3
3
  const require_itemId = require("../itemId-CGT2J7YK.cjs");
4
- const require_promptSafety = require("../promptSafety-Cv-SoTd4.cjs");
4
+ const require_promptSafety = require("../promptSafety-caJWd1ZQ.cjs");
5
5
  const require_project = require("../project-C1ep9pvo.cjs");
6
6
  const require_iconGlyph = require("../iconGlyph-fSBp6k4J.cjs");
7
+ require("../errorMessage-CT-va_Pv.cjs");
7
8
  //#region src/collection/core/presentCollection.ts
8
9
  var TOOL_NAME = "presentCollection";
9
10
  /** Stamp a host's opaque project scope onto a card payload. The ONLY way a