@murmurv2/cli 2.11.0 → 2.12.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 (40) hide show
  1. package/README.md +37 -12
  2. package/package.json +2 -1
  3. package/runtime/bin/murmur-svc.exe +0 -0
  4. package/runtime/npm-runtime-manifest.json +97 -61
  5. package/runtime/package.json +1 -1
  6. package/runtime/packages/setup/bin/murmur.mjs +5 -3
  7. package/runtime/packages/setup/dist/src/cli.d.ts +1 -1
  8. package/runtime/packages/setup/dist/src/cli.js +49 -9
  9. package/runtime/packages/setup/dist/src/clients.js +8 -2
  10. package/runtime/packages/setup/dist/src/commands.d.ts +3 -1
  11. package/runtime/packages/setup/dist/src/commands.js +17 -6
  12. package/runtime/packages/setup/dist/src/config.d.ts +2 -0
  13. package/runtime/packages/setup/dist/src/config.js +61 -0
  14. package/runtime/packages/setup/dist/src/doctor.d.ts +12 -0
  15. package/runtime/packages/setup/dist/src/doctor.js +19 -2
  16. package/runtime/packages/setup/dist/src/invitation-server.d.ts +2 -0
  17. package/runtime/packages/setup/dist/src/invitation-server.js +45 -0
  18. package/runtime/packages/setup/dist/src/message-status.d.ts +4 -0
  19. package/runtime/packages/setup/dist/src/message-status.js +10 -0
  20. package/runtime/packages/setup/dist/src/onboarding.d.ts +19 -6
  21. package/runtime/packages/setup/dist/src/onboarding.js +46 -22
  22. package/runtime/packages/setup/dist/src/outbox-attention.js +3 -21
  23. package/runtime/packages/setup/dist/src/platform/darwin.js +7 -1
  24. package/runtime/packages/setup/dist/src/platform/linux.js +21 -16
  25. package/runtime/packages/setup/dist/src/platform/windows.js +67 -3
  26. package/runtime/packages/setup/dist/src/status.d.ts +17 -2
  27. package/runtime/packages/setup/dist/src/status.js +78 -18
  28. package/runtime/packages/setup/dist/src/types.d.ts +11 -1
  29. package/runtime/packages/setup/dist/src/verdict.js +4 -2
  30. package/runtime/packages/setup/dist/src/wake-attention.d.ts +11 -0
  31. package/runtime/packages/setup/dist/src/wake-attention.js +44 -0
  32. package/runtime/packages/setup/package.json +1 -1
  33. package/runtime/scripts/codex-app-server-wake.mjs +169 -32
  34. package/runtime/scripts/daemon-contacts.mjs +56 -0
  35. package/runtime/scripts/daemon-flush-tick.mjs +25 -0
  36. package/runtime/scripts/daemon-link-watch.mjs +60 -0
  37. package/runtime/scripts/daemon-observation.mjs +74 -18
  38. package/runtime/scripts/murmur-daemon.mjs +45 -31
  39. package/runtime/scripts/wake-drain-claude.mjs +69 -32
  40. package/runtime/scripts/wake-monitor.mjs +46 -18
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # Murmur CLI
2
2
 
3
- Install once, join with a private invitation file, and connect an AI client to
4
- Murmur's encrypted messaging mesh. The executable is `murmur`.
3
+ Set up your Identity, exchange an Invitation and a Reply, and connect your
4
+ Assistant to Murmur. The executable is `murmur`.
5
5
 
6
- The public npm release is pending. After `@murmurv2/cli@2.11.0` is published,
7
- use the command below. Until publication is confirmed, use a GitHub release
8
- asset; older public registry packages do not contain the current fixes.
9
- Maintainers rehearsing a release use only their coordinator-approved registry.
6
+ `@murmurv2/cli@2.12.0` is published on npm (28 Sep 2026). `@murmurv2/*` packages
7
+ published before that release are frozen and do not contain the current fixes;
8
+ install the pinned version below or use a GitHub release asset. Step-by-step
9
+ installation of the desktop app is on https://murmurconnect.com/#install.
10
10
 
11
11
  ```sh
12
- npm install --global @murmurv2/cli@2.11.0
12
+ npm install --global @murmurv2/cli@2.12.0
13
13
  murmur version --json
14
14
  ```
15
15
 
@@ -19,7 +19,19 @@ The tarball includes the CLI, daemon, MCP entry, and prebuilt Windows x64 servic
19
19
  helper. It does not include a desktop application. On Windows PowerShell use
20
20
  `npm.cmd` and `murmur.cmd` if execution policy blocks the PowerShell shims.
21
21
 
22
- Run the following with the same absolute profile path on each line:
22
+ Use the same absolute profile path for every command below.
23
+
24
+ To create an Invitation, use `murmur invite --data-dir /absolute/profile`.
25
+ It prints one `MURMUR:` line. Add `--out /private/invitation.txt` for a private
26
+ file copy; `--json` returns the line in `invitation` and the
27
+ `containsBrokerCredential` flag. If that flag is true, an application must explain
28
+ that the Invitation contains a Server access key and obtain confirmation before
29
+ copying it. Send it personally to your colleague.
30
+ If the profile uses a private Server address, ask for that Server's public address
31
+ and add `--broker nats://server.example.com:4222`. The Invitation uses this address;
32
+ the Service keeps its existing settings. A private override is also refused.
33
+
34
+ To accept an Invitation:
23
35
 
24
36
  ```sh
25
37
  murmur join --agent-id YOUR-AGENT --invite-file /private/invite.txt --reply-out /private/reply.txt --data-dir /absolute/profile
@@ -30,10 +42,16 @@ murmur clients configure --client codex-cli --data-dir /absolute/profile
30
42
  murmur doctor --peer HOST-AGENT --data-dir /absolute/profile --json
31
43
  ```
32
44
 
33
- The invitation host must import your reply file and reload its own peer
34
- configuration before the roundtrip check can succeed. Keep the invitation and
35
- reply outside the profile, in an existing private directory. Do not paste them
36
- into chat or edit `agent-config.json` manually.
45
+ For an application that accepts pasted lines, use `join --invite-stdin` and
46
+ `add-peer --reply-stdin`, sending the line on the subprocess input stream, never
47
+ as a command argument. `join` prints the Reply as one `MURMUR:` line;
48
+ `--reply-out` is optional. With `--json`, the Reply is in `reply`.
49
+
50
+ The inviting person imports the Reply with `add-peer`. A 2.12 Service reads
51
+ changed Contacts automatically; no manual restart is needed. The command reports
52
+ a pending reload, not proof that the running Service has applied it. Start the
53
+ Service if it is not running, then check the connection. Keep optional files
54
+ outside the Identity folder, in an existing private directory.
37
55
 
38
56
  Choose an installed client reported by `clients detect`; configuration preserves
39
57
  unrelated settings and refuses conflicting Murmur entries. Reload that client,
@@ -51,3 +69,10 @@ prefix in place while its service and client configuration refer to it.
51
69
 
52
70
  [`docs/setup-onboarding.md`](https://github.com/alexfrmn/murmur/blob/main/docs/setup-onboarding.md)
53
71
  documents the shared commands and their evidence limits.
72
+
73
+ On Windows, `murmur logs path --data-dir <profile> --json` verifies the native
74
+ Service's profile before returning its existing readable folder under
75
+ `%ProgramData%\Murmur\logs\<service-name>`. The response uses
76
+ `murmur.logs/1` with `source: "native"`. Missing or unverified Services and folders
77
+ are refused; the command does not create directories or change the Service.
78
+ Pass the same `--service-name` used during installation when it was customized.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@murmurv2/cli",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "type": "module",
5
5
  "main": "runtime/packages/setup/dist/src/index.js",
6
6
  "types": "runtime/packages/setup/dist/src/index.d.ts",
@@ -33,6 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "description": "Murmur CLI — invite-based setup, background service, client configuration and diagnostics.",
36
+ "mcpName": "io.github.alexfrmn/murmur",
36
37
  "files": [
37
38
  "bin/murmur-npm.mjs",
38
39
  "runtime",
Binary file
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "schema": "murmur.npm-cli/1",
3
- "sourceCommit": "91279e5249e265cfe54dcd0904d9ae92fbb18ec5",
3
+ "sourceCommit": "e7f389c97146dd305a19099eeb1ea00eda56c423",
4
4
  "sourceDirty": false,
5
- "declaredVersion": "2.11.0",
6
- "sourceLockSha256": "4317a76743610366f9b5846993c7c201bc2c0c4fcabfda2d5448e7ff921a9647",
5
+ "declaredVersion": "2.12.0",
6
+ "sourceLockSha256": "7e3f544f7c022f5f608051e88175d7cf2770d05668e2a992675c98e1cc3d91fb",
7
7
  "windowsHelper": {
8
8
  "component": "windows-service",
9
9
  "platform": "windows",
10
10
  "arch": "amd64",
11
- "version": "2.11.0",
12
- "sourceCommit": "91279e5249e265cfe54dcd0904d9ae92fbb18ec5",
13
- "sha256": "877f76eb7791c5a83b1a33dce0eaa7aa497eabdee2f877d750d695355cac76ab",
14
- "size": 3128320,
11
+ "version": "2.12.0",
12
+ "sourceCommit": "e7f389c97146dd305a19099eeb1ea00eda56c423",
13
+ "sha256": "7bb31d2080d23c5e8bcf690f03560259e9ffd421b6e6c7b2ccffb61e9b03a760",
14
+ "size": 3145216,
15
15
  "nativeVersionExecuted": false
16
16
  },
17
17
  "files": {
18
18
  "package.json": {
19
- "sha256": "7670e3b33c8ef783813b1b8860726f9dd2ba2bcdc7c49da05f2780d89fdc0d6b",
19
+ "sha256": "0c78cdd67aa02fefa10be5eecc0df994c5f83702d059659c84b5145ef540cbc7",
20
20
  "size": 83
21
21
  },
22
22
  "packages/setup/package.json": {
23
- "sha256": "ac61a66e834fcbad44a2fbed34dc2f7573309f1245bdd8e83dd9540803758df2",
23
+ "sha256": "7b0ffea9e6209e96737be35da3c282cadb9db183c685fc69d0baa4015760fdab",
24
24
  "size": 132
25
25
  },
26
26
  "packages/setup/dist/src/appdata.d.ts": {
@@ -32,44 +32,44 @@
32
32
  "size": 2678
33
33
  },
34
34
  "packages/setup/dist/src/cli.d.ts": {
35
- "sha256": "6da2fbea536a227db1e8b1d7646d4554cd6e071b05240d5489203eaf007c72e2",
36
- "size": 418
35
+ "sha256": "45ddc7e1eac91a7eb922339b3f01a39a28cf027789309b477eb4ffcfdd020682",
36
+ "size": 462
37
37
  },
38
38
  "packages/setup/dist/src/cli.js": {
39
- "sha256": "13ab60762776c1750da857762f3957a08340e41c651cab6274f3a678b0480d31",
40
- "size": 8745
39
+ "sha256": "91a5d9f7eaf505a2d4a4f55064d2eb219bda51bbc9de516d22c6304948ff87f3",
40
+ "size": 11014
41
41
  },
42
42
  "packages/setup/dist/src/clients.d.ts": {
43
43
  "sha256": "74291be39ef9cffab6d483e38d955cdc0100e9d5ba0d734d77cad8d2f1fc01fb",
44
44
  "size": 4380
45
45
  },
46
46
  "packages/setup/dist/src/clients.js": {
47
- "sha256": "1098fe951626980c0c5717d8a211d282db5d6c4acfd09a055b8ebd2d1b9362ab",
48
- "size": 13670
47
+ "sha256": "82d84903dd069c0ecad709a25d221b9a20b0b6e6f3f43e244dea01803a60f2d6",
48
+ "size": 14339
49
49
  },
50
50
  "packages/setup/dist/src/commands.d.ts": {
51
- "sha256": "63f0a5e9834ca75bced2079cb4c4f0e087c1c7cd14ad958aeda5234bcd80337e",
52
- "size": 1316
51
+ "sha256": "c930b1058ff2d45be38f74df2251a722fe0f1599b5d7afbc6bf74d17a780633c",
52
+ "size": 1417
53
53
  },
54
54
  "packages/setup/dist/src/commands.js": {
55
- "sha256": "eef7c76c21383b2dba733ce4967afa964c547a263333a380606b05eb197fb04f",
56
- "size": 5731
55
+ "sha256": "68f47c53dab225057d09c192cd941f509d39d3cbdc7868b74d5e8494df0e806c",
56
+ "size": 6416
57
57
  },
58
58
  "packages/setup/dist/src/config.d.ts": {
59
- "sha256": "b244629bb9a19d4a48b813c817733d998efea543e8daec99e282010d4e784499",
60
- "size": 1346
59
+ "sha256": "4ddeda3137d82b8fa82fa3c723b14fb37fd05ad1ca7cc2683fa09c32df56cdb2",
60
+ "size": 1489
61
61
  },
62
62
  "packages/setup/dist/src/config.js": {
63
- "sha256": "9ad91d6d9408f72166ed363eacac4496b1e831ccdda10cd28375f6e21521ef4e",
64
- "size": 3212
63
+ "sha256": "12d1594dca385cda8da9e628743ca64794bc7d6e314787090b7af4e8517dc517",
64
+ "size": 9034
65
65
  },
66
66
  "packages/setup/dist/src/doctor.d.ts": {
67
- "sha256": "115b7cf132e4101fe4964173787902d9585f586ee83aa9ae1694161bd646804f",
68
- "size": 827
67
+ "sha256": "212bdd1979f01c3d19c32e686a42472df645598afaf8ac979e6f59d3076a6329",
68
+ "size": 1159
69
69
  },
70
70
  "packages/setup/dist/src/doctor.js": {
71
- "sha256": "9e240e1f0796ce5e3a6e64dbcc41c56a9febd285c2276f88bb15dde6d68c201e",
72
- "size": 11225
71
+ "sha256": "1132cacce959550b1cd746275406b1cbb52525e5065aa7805c5e87eb54c69cbe",
72
+ "size": 12658
73
73
  },
74
74
  "packages/setup/dist/src/file-identity.d.ts": {
75
75
  "sha256": "1f5845364d263c80167ed533e46a02751a008d3993a6894aae50a13f646e6767",
@@ -87,21 +87,37 @@
87
87
  "sha256": "8d863cf184dd6837b7d6544a202f6b2a19787b37e82bac379decc8a07268a7a0",
88
88
  "size": 236
89
89
  },
90
+ "packages/setup/dist/src/invitation-server.d.ts": {
91
+ "sha256": "6456bba1de8ddf8c9a520a4631f972cd79ebf66428f4673af6692e7136b6bc97",
92
+ "size": 159
93
+ },
94
+ "packages/setup/dist/src/invitation-server.js": {
95
+ "sha256": "e6e1de957d76191e7695bcad51ce7049cc3db7cf92d82b682d43584ec00c4401",
96
+ "size": 2555
97
+ },
98
+ "packages/setup/dist/src/message-status.d.ts": {
99
+ "sha256": "047356037a4e6f93468e044473da6c32e210653276c69f89a311f189f2bf7b28",
100
+ "size": 272
101
+ },
102
+ "packages/setup/dist/src/message-status.js": {
103
+ "sha256": "0fd0339db07a43133018c54da572017b8ab4423a37698c80a8bf2aa6a6de3b2d",
104
+ "size": 576
105
+ },
90
106
  "packages/setup/dist/src/onboarding.d.ts": {
91
- "sha256": "b76892619695c2bd9298248d4e7557dce832a688aca0106c02939c4ae0352277",
92
- "size": 1141
107
+ "sha256": "7510056f60fdebb183143a53fed8d4495d361a0e2b05f8c8601d959e51ba7f67",
108
+ "size": 1440
93
109
  },
94
110
  "packages/setup/dist/src/onboarding.js": {
95
- "sha256": "caaec0a7f9e8f685185b096bccf1741ae93e7f64983602833ef4e1ccbff70544",
96
- "size": 14985
111
+ "sha256": "a27a426a21de33b6c5017a26d248a75875f8caffbf274ba1139e2ab1f876e116",
112
+ "size": 16248
97
113
  },
98
114
  "packages/setup/dist/src/outbox-attention.d.ts": {
99
115
  "sha256": "a96effdd0e47701836fb93ab0c24a30d78f29fc0f3e7193406067535532ff962",
100
116
  "size": 1606
101
117
  },
102
118
  "packages/setup/dist/src/outbox-attention.js": {
103
- "sha256": "db70b6eed2338efe0c2875dbca9c0306cce3c940f0f7f09f3dff7c528ca377af",
104
- "size": 5113
119
+ "sha256": "45c0cacd468907860415439ab519e39b07d154e1f64e90bf0dc62e135305aa92",
120
+ "size": 4326
105
121
  },
106
122
  "packages/setup/dist/src/paths.d.ts": {
107
123
  "sha256": "5c9ce9ac87f5fa90124fa071cc6a5d2176d045fc41de58deb53a0e3ef5d85504",
@@ -116,24 +132,24 @@
116
132
  "size": 591
117
133
  },
118
134
  "packages/setup/dist/src/platform/darwin.js": {
119
- "sha256": "b361a9481c12aa5952dd9c18f30cf612f2126bef87993e6808acf38e56ae7422",
120
- "size": 12996
135
+ "sha256": "b4a71ef4bf4cb215464e5678772c1f6c55f1da4960126d39741cb30c8d57ee92",
136
+ "size": 13212
121
137
  },
122
138
  "packages/setup/dist/src/platform/linux.d.ts": {
123
139
  "sha256": "989d39cc9d5c73c9dae7dc926344fa2c6dde5e80f0a8d7657d5ce1f774da9b44",
124
140
  "size": 375
125
141
  },
126
142
  "packages/setup/dist/src/platform/linux.js": {
127
- "sha256": "ab86ab63919d8df3c5c8ccd3bec1d34b4926d847911c56ecf5f8acbcc6404e26",
128
- "size": 9042
143
+ "sha256": "e4086029fa68b02d6f090b8b257b1387c3e7bfdba502d4fc7ca5cfbc07404bab",
144
+ "size": 9087
129
145
  },
130
146
  "packages/setup/dist/src/platform/windows.d.ts": {
131
147
  "sha256": "9f2cb7a20c26f936c9878ca5d525edd7486142392452db47c49e5676e98e2808",
132
148
  "size": 1123
133
149
  },
134
150
  "packages/setup/dist/src/platform/windows.js": {
135
- "sha256": "1a6db62bf38dd56fe78a115e30dc003aef892453265add5e338f8b32beedb87c",
136
- "size": 10787
151
+ "sha256": "d43f31edb07bf0ee37a4a7e28176a9e3087c47467ceefddc2a6c85c9299d8391",
152
+ "size": 14546
137
153
  },
138
154
  "packages/setup/dist/src/private-file.d.ts": {
139
155
  "sha256": "dd574a6f2135aa13064a45b452275aada896402243a4d147f7c417afe8199c4a",
@@ -168,16 +184,16 @@
168
184
  "size": 984
169
185
  },
170
186
  "packages/setup/dist/src/status.d.ts": {
171
- "sha256": "426841217d3f9f6248a63d65fb708af3aa38cd481bad1390a68d1ec1a3910124",
172
- "size": 4244
187
+ "sha256": "1906f6e98e70e33c0ff3d232410e84a9e44d992910447b789b78eed30b0f0469",
188
+ "size": 4720
173
189
  },
174
190
  "packages/setup/dist/src/status.js": {
175
- "sha256": "ddc80da3c1843cf84137b2543805c6c4cdf3316efe44870e6151476c1ca6d27c",
176
- "size": 13155
191
+ "sha256": "2149709708a996047e94f7f4fe809bdfb7bfc79f346288509f0143e2ef822002",
192
+ "size": 18057
177
193
  },
178
194
  "packages/setup/dist/src/types.d.ts": {
179
- "sha256": "2d9d05df2818b22a2be5050288cfe9837f2669814218cbeca1be64b19a079463",
180
- "size": 1506
195
+ "sha256": "d19a3e3aec782eea861e83b42121608a4251b100f940d2f9918e06496bf1a027",
196
+ "size": 2195
181
197
  },
182
198
  "packages/setup/dist/src/types.js": {
183
199
  "sha256": "8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881",
@@ -196,12 +212,20 @@
196
212
  "size": 505
197
213
  },
198
214
  "packages/setup/dist/src/verdict.js": {
199
- "sha256": "3b3265b31dc366745a42a48ac56655d838586197bba9774a0b47c90c02a9099b",
200
- "size": 7929
215
+ "sha256": "aa9deab4aa1872307673a24ac6c9c5cd2725810d51ed8b4eeaa780664a84239b",
216
+ "size": 8136
217
+ },
218
+ "packages/setup/dist/src/wake-attention.d.ts": {
219
+ "sha256": "dfcff1d3f6be50e4a55ba6f9310a1600341b041cc1fe68c1752d79684993beee",
220
+ "size": 431
221
+ },
222
+ "packages/setup/dist/src/wake-attention.js": {
223
+ "sha256": "62623206ebaba33150c381ccb24ee5a523e4c81a4dafc9d6ce2620941f375686",
224
+ "size": 2384
201
225
  },
202
226
  "packages/setup/bin/murmur.mjs": {
203
- "sha256": "6761c1030f648455e3b99499cd1fa7a356b091700dbbcb2392623315243c5bb5",
204
- "size": 1408
227
+ "sha256": "bb3ce6c03540f9c9ced3a4408651a0c916062a124592426f4f9b8f2447f5f043",
228
+ "size": 1675
205
229
  },
206
230
  "packages/mcp-server/package.json": {
207
231
  "sha256": "89c47db7851f89caec72da4f215ebc21cf1e294aeef3b45d2583562d846ab035",
@@ -212,8 +236,8 @@
212
236
  "size": 31
213
237
  },
214
238
  "scripts/murmur-daemon.mjs": {
215
- "sha256": "e3f7a2dfcb842ea4a908fd0e10ab6c5f066ea3034af51991c3326a1bcf808be6",
216
- "size": 22863
239
+ "sha256": "5012e4d309bbf0a03c730e47689b187309e15676d2bcc8a474aa331a12a1b503",
240
+ "size": 24198
217
241
  },
218
242
  "scripts/murmur-shell-send.mjs": {
219
243
  "sha256": "5e0ae14f59b634f89751c0487edbf7b9f03f95b0a38e55d5619d392bd2343eee",
@@ -228,16 +252,16 @@
228
252
  "size": 10755
229
253
  },
230
254
  "scripts/codex-app-server-wake.mjs": {
231
- "sha256": "8b3d975498f5904d42a18bc345a943a4707d9b147f5ae81fd050645796e97c26",
232
- "size": 26600
255
+ "sha256": "08d263afca8bdd2baf3232f36bdcfb14e80ea60dca82d52a0df215d8ccfd96a3",
256
+ "size": 34121
233
257
  },
234
258
  "scripts/murmur-jetstream-advisory.mjs": {
235
259
  "sha256": "4232c92418d46bd4c6bc4785641dd226f58a79e35211e51a469a8d469065e0a7",
236
260
  "size": 326
237
261
  },
238
262
  "scripts/wake-monitor.mjs": {
239
- "sha256": "416dd71e7e93b6827d9e603438804856cd38e7b575d9842ee33442a856a07cef",
240
- "size": 31907
263
+ "sha256": "f51f1c6f7653d60d5eb9877b4a17f1d69fd6c75a0b65cf56c9c26767cd2378bf",
264
+ "size": 33488
241
265
  },
242
266
  "scripts/lease.mjs": {
243
267
  "sha256": "c380ec90c0b5cef4d010df4d59793f86f0dc319c82039997c3d8884a9e92f56e",
@@ -248,8 +272,12 @@
248
272
  "size": 3280
249
273
  },
250
274
  "scripts/daemon-observation.mjs": {
251
- "sha256": "cef36ccf407d3c45c11ad796c709f05176faedc2af7adfdd0f618d306a03f459",
252
- "size": 2349
275
+ "sha256": "2c36283c8e77ae0a77758bf65e5f80599d4ef409bb393adae527549c3994da73",
276
+ "size": 5665
277
+ },
278
+ "scripts/daemon-link-watch.mjs": {
279
+ "sha256": "081b8d30f883b4daef7f3e18f01ad46f999ee3a77c3cbce5be920a8dc50d963e",
280
+ "size": 2313
253
281
  },
254
282
  "scripts/ack-security.mjs": {
255
283
  "sha256": "bb769e874b6d4144b074596ba4c99dac4b6987b1e0e2967ffcf5fa73962e41a1",
@@ -259,9 +287,17 @@
259
287
  "sha256": "e373b1ff7801bde10c016cb5d24fefdec39382127008a5c359c804338bd5dc13",
260
288
  "size": 5282
261
289
  },
290
+ "scripts/daemon-contacts.mjs": {
291
+ "sha256": "f12cb7b790d677bab7f3e36434ef3b54a6274d16ac3c6f15bb6f86ca5c86e37f",
292
+ "size": 3190
293
+ },
294
+ "scripts/daemon-flush-tick.mjs": {
295
+ "sha256": "1d47a46549861d5ad60323e8db4fdf85c33d84c9fb786d4aa29cfc306dc8128c",
296
+ "size": 1239
297
+ },
262
298
  "scripts/wake-drain-claude.mjs": {
263
- "sha256": "9f5d95c4242b56cd01b09e2198bb3dc4cbd819d8acf1bf664016f364279ca046",
264
- "size": 22815
299
+ "sha256": "e32308b0f2840c760eacbf53fdccf0c9de8e22e150f29d1f7f22194e58777de6",
300
+ "size": 25611
265
301
  },
266
302
  "plugins/claude-code/.claude-plugin/plugin.json": {
267
303
  "sha256": "39743b9ea55f475c767dba430e1014fcfa19648e95ddcf0da9b0128f1744ec88",
@@ -292,8 +328,8 @@
292
328
  "size": 705
293
329
  },
294
330
  "bin/murmur-svc.exe": {
295
- "sha256": "877f76eb7791c5a83b1a33dce0eaa7aa497eabdee2f877d750d695355cac76ab",
296
- "size": 3128320
331
+ "sha256": "7bb31d2080d23c5e8bcf690f03560259e9ffd421b6e6c7b2ccffb61e9b03a760",
332
+ "size": 3145216
297
333
  }
298
334
  }
299
335
  }
@@ -1 +1 @@
1
- {"name":"murmur","private":true,"version":"2.11.0","engines":{"node":">=22.13.0"}}
1
+ {"name":"murmur","private":true,"version":"2.12.0","engines":{"node":">=22.13.0"}}
@@ -12,15 +12,17 @@ try { await checkRuntime(); }
12
12
  catch (error) { process.stderr.write(error.message + '\n'); process.exit(1); }
13
13
  // Dynamic imports let the capability check run before the engine imports SQLite.
14
14
  const { main, isRawCliOutput } = await import('../dist/src/cli.js');
15
- const { safeError } = await import('../dist/src/config.js');
15
+ const { safeError, humanError } = await import('../dist/src/config.js');
16
16
  const lineMode = process.argv[2] === 'status' && process.argv.includes('--line');
17
17
  try {
18
18
  const result = await main(process.argv.slice(2));
19
- if (isRawCliOutput(result)) {
19
+ if (!process.argv.includes('--json') && (result?.schema === 'murmur.invite/1' || result?.schema === 'murmur.join/1')) {
20
+ process.stdout.write((result.invitation ?? result.reply) + '\n');
21
+ } else if (isRawCliOutput(result)) {
20
22
  if (result.text) process.stdout.write(result.text + '\n');
21
23
  } else process.stdout.write(JSON.stringify(result) + '\n');
22
24
  } catch (error) {
23
25
  if (lineMode) process.stdout.write('Murmur: unknown (status.command-failed)\n');
24
- process.stderr.write(safeError(error) + '\n');
26
+ process.stderr.write((process.argv.includes('--json') ? safeError(error) : humanError(error)) + '\n');
25
27
  process.exitCode = 1;
26
28
  }
@@ -6,4 +6,4 @@ export interface RawCliOutput {
6
6
  }
7
7
  export declare const rawCliOutput: (text: string) => RawCliOutput;
8
8
  export declare const isRawCliOutput: (value: unknown) => value is RawCliOutput;
9
- export declare function main(args: string[], adapter?: PlatformAdapter): Promise<unknown>;
9
+ export declare function main(args: string[], adapter?: PlatformAdapter, input?: AsyncIterable<Uint8Array | string>): Promise<unknown>;
@@ -1,6 +1,7 @@
1
1
  import { configureClient, previewClientConfiguration } from './clients.js';
2
2
  import { prepareReplyTest, checkReplyTest } from './reply-test.js';
3
3
  import { listOutboxAttention, setOutboxDismissed } from './outbox-attention.js';
4
+ import { dismissWake } from './wake-attention.js';
4
5
  import { initialize, invite, join, importPeer } from './onboarding.js';
5
6
  import { runDoctor } from './doctor.js';
6
7
  import { parseArgs } from 'node:util';
@@ -34,7 +35,7 @@ export function platformAdapter() {
34
35
  export const rawCliOutput = (text) => ({ kind: 'raw', text });
35
36
  export const isRawCliOutput = (value) => !!value && typeof value === 'object'
36
37
  && value.kind === 'raw' && typeof value.text === 'string';
37
- export async function main(args, adapter = platformAdapter()) {
38
+ export async function main(args, adapter = platformAdapter(), input = process.stdin) {
38
39
  // `murmur --version` is the first thing people type after npm install; answer it like `murmur version`.
39
40
  if (args.some(a => a === '--version' || a === '-v') && args.every(a => ['--version', '-v', '--json'].includes(a)))
40
41
  return readVersion();
@@ -42,8 +43,9 @@ export async function main(args, adapter = platformAdapter()) {
42
43
  try {
43
44
  parsed = parseArgs({ args, allowPositionals: true, options: {
44
45
  'msg-id': { type: 'string' }, 'expected-state': { type: 'string' }, 'expected-agent': { type: 'string' },
45
- 'agent-id': { type: 'string' }, 'broker-url': { type: 'string' }, 'token-file': { type: 'string' }, 'invite-file': { type: 'string' }, 'reply-file': { type: 'string' }, 'reply-out': { type: 'string' }, out: { type: 'string' },
46
- client: { type: 'string' }, replace: { type: 'boolean' }, 'plan-id': { type: 'string' }, 'test-token': { type: 'string' }, json: { type: 'boolean' }, line: { type: 'boolean' }, limit: { type: 'string' }, peer: { type: 'string' }, timeout: { type: 'string' }, 'data-dir': { type: 'string' }, 'service-name': { type: 'string' }, apply: { type: 'boolean' }, help: { type: 'boolean' },
46
+ 'agent-id': { type: 'string' }, 'broker-url': { type: 'string' }, broker: { type: 'string' }, 'token-file': { type: 'string' }, 'invite-file': { type: 'string' }, 'reply-file': { type: 'string' }, 'reply-out': { type: 'string' }, out: { type: 'string' },
47
+ 'invite-stdin': { type: 'boolean' }, 'reply-stdin': { type: 'boolean' },
48
+ client: { type: 'string' }, replace: { type: 'boolean' }, 'replace-previous': { type: 'boolean' }, 'plan-id': { type: 'string' }, 'test-token': { type: 'string' }, json: { type: 'boolean' }, line: { type: 'boolean' }, limit: { type: 'string' }, peer: { type: 'string' }, timeout: { type: 'string' }, 'data-dir': { type: 'string' }, 'service-name': { type: 'string' }, apply: { type: 'boolean' }, help: { type: 'boolean' },
47
49
  } });
48
50
  }
49
51
  catch (error) {
@@ -52,7 +54,7 @@ export async function main(args, adapter = platformAdapter()) {
52
54
  }
53
55
  const { values, positionals } = parsed;
54
56
  if (values.help || !positionals.length)
55
- return { commands: ['version --json', 'updates check|enable|disable --json', 'init --agent-id ID --broker-url URL [--token-file FILE]', 'invite --out FILE', 'join --agent-id ID --invite-file FILE --reply-out FILE', 'add-peer --reply-file FILE', 'status --json|--line', 'doctor --json [--peer AGENT] [--timeout MILLISECONDS]', 'logs path --json', 'service install|start|stop|uninstall', 'clients detect', 'clients preview --client ID', 'clients configure --client ID [--replace] [--plan-id SHA256]', 'reply-test prepare --peer AGENT', 'reply-test check --test-token TOKEN', 'wake pause|resume [--apply]', 'inbox read [--limit 1..100]', 'inbox mark-read', 'outbox list --json', 'outbox dismiss|restore --msg-id ID --expected-state TOKEN --expected-agent ID', 'mcp serve --data-dir ABSOLUTE'],
57
+ return { commands: ['version --json', 'updates check|enable|disable --json', 'init --agent-id ID --broker-url URL [--token-file FILE]', 'invite [--out FILE] [--broker PUBLIC_URL] [--json]', 'join --agent-id ID (--invite-stdin|--invite-file FILE) [--reply-out FILE] [--json]', 'add-peer (--reply-stdin|--reply-file FILE)', 'status --json|--line', 'doctor --json [--peer AGENT] [--timeout MILLISECONDS]', 'logs path --json', 'service install [--replace-previous]|start|stop|uninstall', 'clients detect', 'clients preview --client ID', 'clients configure --client ID [--replace] [--plan-id SHA256]', 'reply-test prepare --peer AGENT', 'reply-test check --test-token TOKEN', 'wake pause|resume [--apply]', 'wake dismiss --msg-id ID --expected-agent ID', 'inbox read [--limit 1..100]', 'inbox mark-read', 'outbox list --json', 'outbox dismiss|restore --msg-id ID --expected-state TOKEN --expected-agent ID', 'mcp serve --data-dir ABSOLUTE'],
56
58
  options: ['--data-dir ABSOLUTE', '--service-name NAME'], note: 'Windows service mutations require an elevated terminal and the matching native helper.' };
57
59
  const [command, action, extra] = positionals;
58
60
  if (extra)
@@ -72,12 +74,34 @@ export async function main(args, adapter = platformAdapter()) {
72
74
  throw new Error('cli.required-option:' + name); return value; };
73
75
  if (command === 'init' && !action)
74
76
  return initialize(context, { agentId: required('agent-id'), brokerUrl: required('broker-url'), tokenFile: values['token-file'] });
77
+ const onboardingInput = async (kind) => {
78
+ if (values[`${kind}-file`] !== undefined && values[`${kind}-stdin`])
79
+ throw new Error('onboarding.input-conflict');
80
+ if (!values[`${kind}-stdin`]) {
81
+ if (!values[`${kind}-file`])
82
+ throw new Error('onboarding.input-required');
83
+ return undefined;
84
+ }
85
+ if (input === process.stdin && process.stdin.isTTY)
86
+ throw new Error('onboarding.stdin-required');
87
+ const chunks = [];
88
+ let size = 0;
89
+ for await (const chunk of input) {
90
+ const bytes = Buffer.from(chunk);
91
+ size += bytes.length;
92
+ if (size > 16384)
93
+ throw new Error('onboarding.input-too-large');
94
+ chunks.push(bytes);
95
+ }
96
+ return Buffer.concat(chunks).toString('utf8');
97
+ };
75
98
  if (command === 'invite' && !action)
76
- return invite(context, required('out'));
99
+ return invite(context, values.out, { brokerUrl: values.broker });
77
100
  if (command === 'join' && !action)
78
- return join(context, { agentId: required('agent-id'), inviteFile: required('invite-file'), replyOut: required('reply-out') });
101
+ return join(context, { agentId: required('agent-id'), inviteFile: values['invite-file'],
102
+ invitation: await onboardingInput('invite'), replyOut: values['reply-out'] });
79
103
  if (command === 'add-peer' && !action)
80
- return importPeer(context, required('reply-file'));
104
+ return importPeer(context, values['reply-file'], await onboardingInput('reply'));
81
105
  if (command === 'status' && !action) {
82
106
  const status = await readStatus({ context, adapter });
83
107
  return values.line ? rawCliOutput(renderStatusLine(status)) : status;
@@ -97,8 +121,11 @@ export async function main(args, adapter = platformAdapter()) {
97
121
  return rawCliOutput('');
98
122
  }
99
123
  if (command === 'logs' && action === 'path') {
100
- if (process.platform === 'win32')
101
- throw new Error('logs.windows-native-location-unavailable');
124
+ if (process.platform === 'win32') {
125
+ if (!adapter.logDirectory)
126
+ throw new Error('logs.windows-native-location-unavailable');
127
+ return readLogPath(context, adapter);
128
+ }
102
129
  return readLogPath(context);
103
130
  }
104
131
  if (command === 'doctor' && !action)
@@ -115,11 +142,24 @@ export async function main(args, adapter = platformAdapter()) {
115
142
  return checkReplyTest(context, required('test-token'));
116
143
  if (command === 'wake' && ['pause', 'resume'].includes(action))
117
144
  return setWakeEnabled(context, adapter, action === 'resume', values.apply);
145
+ if (command === 'wake' && action === 'dismiss')
146
+ return dismissWake(context, required('msg-id'), required('expected-agent'));
118
147
  if (command === 'inbox' && action === 'read')
119
148
  return readInbox(context, values.limit === undefined ? 20 : Number(values.limit));
120
149
  if (command === 'inbox' && action === 'mark-read')
121
150
  return markInboxRead(context);
122
151
  if (command === 'service' && ['install', 'start', 'stop', 'uninstall'].includes(action)) {
152
+ if (values['replace-previous']) {
153
+ // One elevated command: remove the previous installation's Service, then install this one.
154
+ if (action !== 'install')
155
+ throw new Error('cli.replace-previous-only-for-install');
156
+ if (!adapter.removePrevious)
157
+ throw new Error('service.replace-previous-unavailable');
158
+ await adapter.removePrevious(context);
159
+ }
160
+ // Evaluated after a removal, so a process that outlived the removed Service still blocks install.
161
+ if ((await readStatus({ context, adapter })).service.state === 'running-unmanaged')
162
+ throw new Error('service.running-unmanaged');
123
163
  const operation = adapter[action];
124
164
  if (!operation)
125
165
  throw new Error('service.uninstall-unavailable');
@@ -69,7 +69,9 @@ const hookPath = (value) => `"${value.replaceAll('\\', '/')}"`;
69
69
  const WAKE_WINDOW_SECONDS = 28800;
70
70
  /** The node wake drain (docs/wake-native.md): polls the store after each turn and wakes the session. */
71
71
  function desiredWakeHook(c) {
72
- return { type: 'command', asyncRewake: true,
72
+ // Claude Code ends a hook without its own `timeout` after 600 s (hooks reference, asyncRewake);
73
+ // the entry carries the same window the drain script is asked for, or the script never gets it.
74
+ return { type: 'command', asyncRewake: true, timeout: WAKE_WINDOW_SECONDS,
73
75
  command: `${hookPath(c.nodePath)} --no-warnings ${hookPath(path.join(c.repoRoot, 'scripts', 'wake-drain-claude.mjs'))} --db ${hookPath(c.storePath)} --max-seconds ${WAKE_WINDOW_SECONDS}` };
74
76
  }
75
77
  const isMurmurWakeHook = (hook) => object(hook) && typeof hook.command === 'string' && hook.command.includes('wake-drain-claude');
@@ -150,8 +152,12 @@ function desiredEntry(c) {
150
152
  async function planFor(c, client, current, settings) {
151
153
  const config = await loadConfig(c), { original, key } = clientDocument(client, current.text);
152
154
  const entry = desiredEntry(c), previous = original[key]?.murmur;
153
- const action = isDeepStrictEqual(previous, entry) ? 'unchanged' : previous === undefined ? 'add' : 'replace';
155
+ const entryAction = isDeepStrictEqual(previous, entry) ? 'unchanged' : previous === undefined ? 'add' : 'replace';
154
156
  const wakeHook = settings && { settingsPath: claudeSettingsPath(client.configPath), action: planWakeHook(c, settings.text).action };
157
+ // The plan's action speaks for both files: an app that sees 'replace' asks the person and
158
+ // passes --replace, so a Stop hook written by an earlier version (no timeout, #273) is
159
+ // upgraded instead of failing with client.wake-hook-conflict while the MCP entry is unchanged.
160
+ const action = wakeHook?.action === 'replace' ? 'replace' : entryAction === 'unchanged' && wakeHook?.action === 'add' ? 'add' : entryAction;
155
161
  // Bind confirmation to the target, exact bytes and selected identity/runtime.
156
162
  // No existing commands, environment values, auth or config contents leave the engine.
157
163
  const planId = createHash('sha256').update(JSON.stringify([client.id, client.configPath, current,
@@ -1,6 +1,6 @@
1
1
  import type { PlatformAdapter, ServiceContext } from './types.js';
2
2
  /** Observe the configured directory only; this does not prove a live daemon's log destination. */
3
- export declare function readLogPath(context: ServiceContext): Promise<{
3
+ export declare function readLogPath(context: ServiceContext, adapter?: PlatformAdapter): Promise<{
4
4
  schema: string;
5
5
  agentId: string;
6
6
  dataDir: string;
@@ -30,6 +30,8 @@ export declare function readInbox(context: ServiceContext, limit?: number): Prom
30
30
  readCursor: number | null;
31
31
  unread: number | null;
32
32
  messages: {
33
+ assistantRead: boolean | null;
34
+ wake_error: string | null;
33
35
  unread: boolean | null;
34
36
  }[];
35
37
  }>;