@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.
- package/README.md +37 -12
- package/package.json +2 -1
- package/runtime/bin/murmur-svc.exe +0 -0
- package/runtime/npm-runtime-manifest.json +97 -61
- package/runtime/package.json +1 -1
- package/runtime/packages/setup/bin/murmur.mjs +5 -3
- package/runtime/packages/setup/dist/src/cli.d.ts +1 -1
- package/runtime/packages/setup/dist/src/cli.js +49 -9
- package/runtime/packages/setup/dist/src/clients.js +8 -2
- package/runtime/packages/setup/dist/src/commands.d.ts +3 -1
- package/runtime/packages/setup/dist/src/commands.js +17 -6
- package/runtime/packages/setup/dist/src/config.d.ts +2 -0
- package/runtime/packages/setup/dist/src/config.js +61 -0
- package/runtime/packages/setup/dist/src/doctor.d.ts +12 -0
- package/runtime/packages/setup/dist/src/doctor.js +19 -2
- package/runtime/packages/setup/dist/src/invitation-server.d.ts +2 -0
- package/runtime/packages/setup/dist/src/invitation-server.js +45 -0
- package/runtime/packages/setup/dist/src/message-status.d.ts +4 -0
- package/runtime/packages/setup/dist/src/message-status.js +10 -0
- package/runtime/packages/setup/dist/src/onboarding.d.ts +19 -6
- package/runtime/packages/setup/dist/src/onboarding.js +46 -22
- package/runtime/packages/setup/dist/src/outbox-attention.js +3 -21
- package/runtime/packages/setup/dist/src/platform/darwin.js +7 -1
- package/runtime/packages/setup/dist/src/platform/linux.js +21 -16
- package/runtime/packages/setup/dist/src/platform/windows.js +67 -3
- package/runtime/packages/setup/dist/src/status.d.ts +17 -2
- package/runtime/packages/setup/dist/src/status.js +78 -18
- package/runtime/packages/setup/dist/src/types.d.ts +11 -1
- package/runtime/packages/setup/dist/src/verdict.js +4 -2
- package/runtime/packages/setup/dist/src/wake-attention.d.ts +11 -0
- package/runtime/packages/setup/dist/src/wake-attention.js +44 -0
- package/runtime/packages/setup/package.json +1 -1
- package/runtime/scripts/codex-app-server-wake.mjs +169 -32
- package/runtime/scripts/daemon-contacts.mjs +56 -0
- package/runtime/scripts/daemon-flush-tick.mjs +25 -0
- package/runtime/scripts/daemon-link-watch.mjs +60 -0
- package/runtime/scripts/daemon-observation.mjs +74 -18
- package/runtime/scripts/murmur-daemon.mjs +45 -31
- package/runtime/scripts/wake-drain-claude.mjs +69 -32
- package/runtime/scripts/wake-monitor.mjs +46 -18
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Murmur CLI
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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.
|
|
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": "
|
|
3
|
+
"sourceCommit": "e7f389c97146dd305a19099eeb1ea00eda56c423",
|
|
4
4
|
"sourceDirty": false,
|
|
5
|
-
"declaredVersion": "2.
|
|
6
|
-
"sourceLockSha256": "
|
|
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.
|
|
12
|
-
"sourceCommit": "
|
|
13
|
-
"sha256": "
|
|
14
|
-
"size":
|
|
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": "
|
|
19
|
+
"sha256": "0c78cdd67aa02fefa10be5eecc0df994c5f83702d059659c84b5145ef540cbc7",
|
|
20
20
|
"size": 83
|
|
21
21
|
},
|
|
22
22
|
"packages/setup/package.json": {
|
|
23
|
-
"sha256": "
|
|
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": "
|
|
36
|
-
"size":
|
|
35
|
+
"sha256": "45ddc7e1eac91a7eb922339b3f01a39a28cf027789309b477eb4ffcfdd020682",
|
|
36
|
+
"size": 462
|
|
37
37
|
},
|
|
38
38
|
"packages/setup/dist/src/cli.js": {
|
|
39
|
-
"sha256": "
|
|
40
|
-
"size":
|
|
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": "
|
|
48
|
-
"size":
|
|
47
|
+
"sha256": "82d84903dd069c0ecad709a25d221b9a20b0b6e6f3f43e244dea01803a60f2d6",
|
|
48
|
+
"size": 14339
|
|
49
49
|
},
|
|
50
50
|
"packages/setup/dist/src/commands.d.ts": {
|
|
51
|
-
"sha256": "
|
|
52
|
-
"size":
|
|
51
|
+
"sha256": "c930b1058ff2d45be38f74df2251a722fe0f1599b5d7afbc6bf74d17a780633c",
|
|
52
|
+
"size": 1417
|
|
53
53
|
},
|
|
54
54
|
"packages/setup/dist/src/commands.js": {
|
|
55
|
-
"sha256": "
|
|
56
|
-
"size":
|
|
55
|
+
"sha256": "68f47c53dab225057d09c192cd941f509d39d3cbdc7868b74d5e8494df0e806c",
|
|
56
|
+
"size": 6416
|
|
57
57
|
},
|
|
58
58
|
"packages/setup/dist/src/config.d.ts": {
|
|
59
|
-
"sha256": "
|
|
60
|
-
"size":
|
|
59
|
+
"sha256": "4ddeda3137d82b8fa82fa3c723b14fb37fd05ad1ca7cc2683fa09c32df56cdb2",
|
|
60
|
+
"size": 1489
|
|
61
61
|
},
|
|
62
62
|
"packages/setup/dist/src/config.js": {
|
|
63
|
-
"sha256": "
|
|
64
|
-
"size":
|
|
63
|
+
"sha256": "12d1594dca385cda8da9e628743ca64794bc7d6e314787090b7af4e8517dc517",
|
|
64
|
+
"size": 9034
|
|
65
65
|
},
|
|
66
66
|
"packages/setup/dist/src/doctor.d.ts": {
|
|
67
|
-
"sha256": "
|
|
68
|
-
"size":
|
|
67
|
+
"sha256": "212bdd1979f01c3d19c32e686a42472df645598afaf8ac979e6f59d3076a6329",
|
|
68
|
+
"size": 1159
|
|
69
69
|
},
|
|
70
70
|
"packages/setup/dist/src/doctor.js": {
|
|
71
|
-
"sha256": "
|
|
72
|
-
"size":
|
|
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": "
|
|
92
|
-
"size":
|
|
107
|
+
"sha256": "7510056f60fdebb183143a53fed8d4495d361a0e2b05f8c8601d959e51ba7f67",
|
|
108
|
+
"size": 1440
|
|
93
109
|
},
|
|
94
110
|
"packages/setup/dist/src/onboarding.js": {
|
|
95
|
-
"sha256": "
|
|
96
|
-
"size":
|
|
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": "
|
|
104
|
-
"size":
|
|
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": "
|
|
120
|
-
"size":
|
|
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": "
|
|
128
|
-
"size":
|
|
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": "
|
|
136
|
-
"size":
|
|
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": "
|
|
172
|
-
"size":
|
|
187
|
+
"sha256": "1906f6e98e70e33c0ff3d232410e84a9e44d992910447b789b78eed30b0f0469",
|
|
188
|
+
"size": 4720
|
|
173
189
|
},
|
|
174
190
|
"packages/setup/dist/src/status.js": {
|
|
175
|
-
"sha256": "
|
|
176
|
-
"size":
|
|
191
|
+
"sha256": "2149709708a996047e94f7f4fe809bdfb7bfc79f346288509f0143e2ef822002",
|
|
192
|
+
"size": 18057
|
|
177
193
|
},
|
|
178
194
|
"packages/setup/dist/src/types.d.ts": {
|
|
179
|
-
"sha256": "
|
|
180
|
-
"size":
|
|
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": "
|
|
200
|
-
"size":
|
|
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": "
|
|
204
|
-
"size":
|
|
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": "
|
|
216
|
-
"size":
|
|
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": "
|
|
232
|
-
"size":
|
|
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": "
|
|
240
|
-
"size":
|
|
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": "
|
|
252
|
-
"size":
|
|
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": "
|
|
264
|
-
"size":
|
|
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": "
|
|
296
|
-
"size":
|
|
331
|
+
"sha256": "7bb31d2080d23c5e8bcf690f03560259e9ffd421b6e6c7b2ccffb61e9b03a760",
|
|
332
|
+
"size": 3145216
|
|
297
333
|
}
|
|
298
334
|
}
|
|
299
335
|
}
|
package/runtime/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"murmur","private":true,"version":"2.
|
|
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 (
|
|
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
|
-
|
|
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,
|
|
99
|
+
return invite(context, values.out, { brokerUrl: values.broker });
|
|
77
100
|
if (command === 'join' && !action)
|
|
78
|
-
return join(context, { agentId: required('agent-id'), inviteFile:
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
}>;
|