borgmcp 3.11.1 → 3.13.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 +15 -0
- package/THIRD_PARTY_NOTICES.md +5 -0
- package/dist/assimilate-deps.d.ts.map +1 -1
- package/dist/assimilate-deps.js +11 -0
- package/dist/assimilate-deps.js.map +1 -1
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +19 -7
- package/dist/cli-help.js.map +1 -1
- package/dist/clone-cmd.d.ts +4 -1
- package/dist/clone-cmd.d.ts.map +1 -1
- package/dist/clone-cmd.js +28 -6
- package/dist/clone-cmd.js.map +1 -1
- package/dist/codex-app-wake.d.ts +3 -2
- package/dist/codex-app-wake.d.ts.map +1 -1
- package/dist/codex-app-wake.js +42 -9
- package/dist/codex-app-wake.js.map +1 -1
- package/dist/cube-activity-wake-copy.d.ts +1 -1
- package/dist/cube-activity-wake-copy.d.ts.map +1 -1
- package/dist/cube-activity-wake-copy.js +1 -1
- package/dist/cube-activity-wake-copy.js.map +1 -1
- package/dist/log-stream.d.ts +3 -3
- package/dist/log-stream.d.ts.map +1 -1
- package/dist/log-stream.js +8 -13
- package/dist/log-stream.js.map +1 -1
- package/dist/opencode-drone.d.ts +1 -1
- package/dist/opencode-drone.d.ts.map +1 -1
- package/dist/opencode-drone.js +16 -2
- package/dist/opencode-drone.js.map +1 -1
- package/dist/parse-clone-args.d.ts +3 -2
- package/dist/parse-clone-args.d.ts.map +1 -1
- package/dist/parse-clone-args.js +32 -9
- package/dist/parse-clone-args.js.map +1 -1
- package/dist/quickstart-cmd.d.ts +5 -1
- package/dist/quickstart-cmd.d.ts.map +1 -1
- package/dist/quickstart-cmd.js +17 -6
- package/dist/quickstart-cmd.js.map +1 -1
- package/dist/remote-client.d.ts +2 -21
- package/dist/remote-client.d.ts.map +1 -1
- package/dist/remote-client.js +8 -6
- package/dist/remote-client.js.map +1 -1
- package/dist/server-handshake.d.ts +6 -1
- package/dist/server-handshake.d.ts.map +1 -1
- package/dist/server-handshake.js +1 -0
- package/dist/server-handshake.js.map +1 -1
- package/docs/LOCAL_SERVER.md +4 -8
- package/docs/RELEASING.md +32 -308
- package/package.json +3 -2
- package/src/assimilate-deps.ts +11 -0
- package/src/cli-help.ts +19 -7
- package/src/clone-cmd.ts +36 -7
- package/src/codex-app-wake.ts +42 -8
- package/src/cube-activity-wake-copy.ts +1 -1
- package/src/log-stream.ts +24 -15
- package/src/opencode-drone.ts +14 -1
- package/src/parse-clone-args.ts +31 -10
- package/src/quickstart-cmd.ts +34 -6
- package/src/remote-client.ts +11 -25
- package/src/server-handshake.ts +4 -1
package/docs/RELEASING.md
CHANGED
|
@@ -8,8 +8,9 @@ npm Trusted Publishing; no long-lived npm token is stored or exposed.
|
|
|
8
8
|
## Release Integrity
|
|
9
9
|
|
|
10
10
|
Release provenance is established by protected annotated tags, GitHub build
|
|
11
|
-
provenance, and npm Trusted Publishing.
|
|
12
|
-
|
|
11
|
+
provenance, and npm Trusted Publishing. Never move, replace, or reuse a tag.
|
|
12
|
+
A failed workflow may be rerun until npm accepts a stage; stage acceptance
|
|
13
|
+
consumes the version.
|
|
13
14
|
|
|
14
15
|
## Release Prerequisites
|
|
15
16
|
|
|
@@ -20,19 +21,15 @@ Before creating the release tag, independently verify all of these conditions:
|
|
|
20
21
|
- the extraction review confirms no private backend secrets, deployment
|
|
21
22
|
configuration, customer data, local state, or duplicated shared contracts
|
|
22
23
|
entered the public package;
|
|
23
|
-
- the exact audited registry dependency `borgmcp-shared@0.
|
|
24
|
+
- the exact audited registry dependency `borgmcp-shared@0.12.2` remains locked to
|
|
24
25
|
its canonical tarball and integrity
|
|
25
|
-
`sha512-
|
|
26
|
-
- the coupled shared/server/client candidates
|
|
27
|
-
|
|
28
|
-
before any stage is approved;
|
|
26
|
+
`sha512-l459XEeqk0cSz1+Z8yk8cCVWik4/CX4OBTRZqj6n1SZYvDpzWJksUz82FA9k4taf//rs43Tfl1tpWXnRHAqxOQ==`;
|
|
27
|
+
- the coupled shared/server/client candidates use the same exact
|
|
28
|
+
`borgmcp-shared` version;
|
|
29
29
|
- the selected stable client version is unused and the exact release commit is
|
|
30
30
|
on protected `main`;
|
|
31
31
|
- the repository and protected npm environment settings pass an operator audit;
|
|
32
|
-
- the exact release source passes
|
|
33
|
-
extraction, and package gates; and
|
|
34
|
-
- the immutable annotated tag and publication receive explicit release
|
|
35
|
-
authorization.
|
|
32
|
+
- the exact release source passes exact-SHA CI and one Code Review.
|
|
36
33
|
|
|
37
34
|
`scripts/verify-release-readiness.mjs` makes the source-side blockers
|
|
38
35
|
machine-checkable. A release tag created before they are resolved fails before
|
|
@@ -41,18 +38,19 @@ dependency installation or publication.
|
|
|
41
38
|
### Release branches
|
|
42
39
|
|
|
43
40
|
Release branches use the `release/` prefix and enter protected `main` through a
|
|
44
|
-
pull request.
|
|
45
|
-
|
|
41
|
+
pull request. After exact-SHA CI and one Code Review, merge the preparation and
|
|
42
|
+
create its annotated version tag. The tag automatically verifies and stages the
|
|
43
|
+
package.
|
|
46
44
|
|
|
47
45
|
## Repository Controls
|
|
48
46
|
|
|
49
47
|
Repository settings are operator-owned and are not changed by this workflow.
|
|
50
48
|
Before preparing a candidate, independently verify:
|
|
51
49
|
|
|
52
|
-
1. The `npm-publish` environment disables administrator bypass,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
1. The `npm-publish` environment disables administrator bypass, has no required
|
|
51
|
+
reviewer, and allows only `v*.*.*` tags. Its `NPM_EXPECTED_OWNER` variable
|
|
52
|
+
must match the sole reviewed maintainer of the existing `borgmcp` package.
|
|
53
|
+
It must contain no npm token.
|
|
56
54
|
2. npm Trusted Publishing is configured for organization `Byte-Ventures`,
|
|
57
55
|
repository `borg-mcp-client`, workflow `publish.yml`, and environment
|
|
58
56
|
`npm-publish`. Its allowed actions enable `npm stage publish` and disable
|
|
@@ -69,212 +67,8 @@ Before preparing a candidate, independently verify:
|
|
|
69
67
|
|
|
70
68
|
## Release Workflow
|
|
71
69
|
|
|
72
|
-
### Clean-environment rig lifecycle
|
|
73
|
-
|
|
74
|
-
Every clean-environment verification rig has an explicit identity and an
|
|
75
|
-
explicit end-of-life. Run it from a Borg-launched session and keep filesystem
|
|
76
|
-
workspaces under the exact disposable scratch root Borg exports. Give each
|
|
77
|
-
workspace a name beginning with `borg-rig-` followed by its owner, purpose, and
|
|
78
|
-
a unique suffix. Before the first command that can create files, anchor the rig
|
|
79
|
-
as its own npm project:
|
|
80
|
-
|
|
81
|
-
```sh
|
|
82
|
-
BORG_SCRATCH_ROOT="${BORG_LAUNCH_SCRATCH:?run from a Borg-launched session}"
|
|
83
|
-
RIG_OWNER="$(basename "$BORG_SCRATCH_ROOT")"
|
|
84
|
-
RIG_NONCE="${RIG_NONCE:-$(date +%Y%m%d%H%M%S)-$$}"
|
|
85
|
-
RIG_ID="borg-rig-${RIG_OWNER}-release-${RIG_NONCE}"
|
|
86
|
-
RIG_ROOT="$BORG_SCRATCH_ROOT/$RIG_ID"
|
|
87
|
-
mkdir -p "$RIG_ROOT"
|
|
88
|
-
printf '%s\n' '{"private":true}' > "$RIG_ROOT/package.json"
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
The manifest anchor is required before any `npm install`, `npm update`, or
|
|
92
|
-
other npm command. Without it, npm can walk up from an empty scratch directory
|
|
93
|
-
and write the operator's `package.json` instead of creating project-local
|
|
94
|
-
state. In a source checkout, the committed `release:exercise` follows this rule
|
|
95
|
-
for its temporary consumer; other QA scripts and manual rigs must do the same.
|
|
96
|
-
|
|
97
|
-
The system temporary root is shared with the whole machine, so an unbounded
|
|
98
|
-
listing there is not an inspectable cleanup check. Bound that leg by the
|
|
99
|
-
invoking user and the run-window markers, which select directories whose
|
|
100
|
-
timestamps fall within this run window without requiring a prefix inventory.
|
|
101
|
-
New `mkdtemp` prefixes therefore require no documentation change. Keep both
|
|
102
|
-
time predicates and the ownership predicate: removing the run-window bound
|
|
103
|
-
turns a populated shared temp root back into an uninspectable listing.
|
|
104
|
-
|
|
105
|
-
On a machine where several runs share one user account, this listing can
|
|
106
|
-
include another run's live workspace. Removal is scoped to paths created by
|
|
107
|
-
this run; anything else in the output is reported, not deleted. Unrelated
|
|
108
|
-
same-user temporary directories created during the window can therefore
|
|
109
|
-
appear in the result, so never remove a path merely because this listing found
|
|
110
|
-
it.
|
|
111
|
-
|
|
112
|
-
```sh
|
|
113
|
-
TEMP_ROOT="${TMPDIR:-/tmp}"
|
|
114
|
-
TEMP_OWNER="$(id -un)"
|
|
115
|
-
TEMP_SCAN_START="$TEMP_ROOT/.${RIG_ID}-temp-scan-start"
|
|
116
|
-
TEMP_SCAN_END="$TEMP_ROOT/.${RIG_ID}-temp-scan-end"
|
|
117
|
-
|
|
118
|
-
list_recent_owned_temp_rigs() {
|
|
119
|
-
find "$TEMP_ROOT" -mindepth 1 -prune \
|
|
120
|
-
-type d \
|
|
121
|
-
-user "$TEMP_OWNER" \
|
|
122
|
-
-newer "$TEMP_SCAN_START" \
|
|
123
|
-
! -newer "$TEMP_SCAN_END" \
|
|
124
|
-
-print
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
touch "$TEMP_SCAN_START"
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Container-backed rigs use the same `RIG_ID` as the container name and carry
|
|
131
|
-
both labels below. Register exact-target cleanup before launching the rig:
|
|
132
|
-
|
|
133
|
-
```sh
|
|
134
|
-
list_owned_rig_containers() {
|
|
135
|
-
docker container ls --all \
|
|
136
|
-
--filter label=borg-rig=1 \
|
|
137
|
-
--filter "label=borg-rig-owner=${RIG_OWNER:?}" \
|
|
138
|
-
--format '{{.ID}}\t{{.Names}}\t{{.Status}}'
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
cleanup_done=0
|
|
142
|
-
cleanup() {
|
|
143
|
-
[ "$cleanup_done" -eq 0 ] || return
|
|
144
|
-
cleanup_done=1
|
|
145
|
-
trap - EXIT HUP INT TERM
|
|
146
|
-
docker container rm --force "$RIG_ID" >/dev/null 2>&1 || true
|
|
147
|
-
rm -rf -- "$RIG_ROOT"
|
|
148
|
-
list_owned_rig_containers
|
|
149
|
-
find "$BORG_SCRATCH_ROOT" -mindepth 1 -print
|
|
150
|
-
find "$BORG_SCRATCH_ROOT" -name 'borg-rig-*' -print
|
|
151
|
-
if [ -e "$TEMP_SCAN_START" ]; then
|
|
152
|
-
touch "$TEMP_SCAN_END"
|
|
153
|
-
list_recent_owned_temp_rigs
|
|
154
|
-
fi
|
|
155
|
-
rm -f -- "$TEMP_SCAN_START" "$TEMP_SCAN_END"
|
|
156
|
-
}
|
|
157
|
-
trap cleanup EXIT
|
|
158
|
-
trap 'exit 129' HUP
|
|
159
|
-
trap 'exit 130' INT
|
|
160
|
-
trap 'exit 143' TERM
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
List containers and scratch paths before starting. The filters distinguish this
|
|
164
|
-
session's rigs from unrelated containers on a shared host:
|
|
165
|
-
|
|
166
|
-
```sh
|
|
167
|
-
list_owned_rig_containers
|
|
168
|
-
find "$BORG_SCRATCH_ROOT" -mindepth 1 -print
|
|
169
|
-
find "$BORG_SCRATCH_ROOT" -name 'borg-rig-*' -print
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
Only after the cleanup traps and pre-launch listings are in place, launch a
|
|
173
|
-
container-backed rig. `--rm` is preferred; a runtime without automatic removal
|
|
174
|
-
must remove the exact `RIG_ID` in its cleanup path and retain the labels for a
|
|
175
|
-
bounded sweep:
|
|
176
|
-
|
|
177
|
-
```sh
|
|
178
|
-
RIG_IMAGE="${RIG_IMAGE:?set the rig image}"
|
|
179
|
-
docker run --rm \
|
|
180
|
-
--name "$RIG_ID" \
|
|
181
|
-
--label borg-rig=1 \
|
|
182
|
-
--label "borg-rig-owner=$RIG_OWNER" \
|
|
183
|
-
"$RIG_IMAGE"
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
The unfiltered filesystem listings expose legacy names as well as conforming
|
|
187
|
-
rigs. The bounded temporary-directory function reports same-user directories
|
|
188
|
-
created during the run window, including unrelated work; it does not establish
|
|
189
|
-
which process owns them. The cleanup path runs the container and scratch
|
|
190
|
-
listings after removing this rig, then runs the bounded temporary-directory
|
|
191
|
-
listing between the start and end markers. Inspect and report its results. If a
|
|
192
|
-
rig creates an exact system-temporary path, record that path when it is created
|
|
193
|
-
and remove that exact path during cleanup; never remove a path solely because
|
|
194
|
-
the bounded listing found it.
|
|
195
|
-
|
|
196
|
-
Register cleanup before launching any process, run it on success and failure,
|
|
197
|
-
and do not deliver a verdict until the container listing and both scratch
|
|
198
|
-
listings show no rig owned by this run, every exact system-temporary path
|
|
199
|
-
recorded by the rig has been removed, and the bounded temporary-directory
|
|
200
|
-
listing has been inspected and reported. For a non-`--rm` container runtime,
|
|
201
|
-
remove only the named rig or the same owner label; never prune unrelated
|
|
202
|
-
containers. A completed verification
|
|
203
|
-
therefore implies zero running or stopped rig containers and no rig workspace
|
|
204
|
-
created by this run left in either the session scratch root or any exact
|
|
205
|
-
system-temporary path the rig recorded.
|
|
206
|
-
|
|
207
|
-
### Pre-tag composed exercise
|
|
208
|
-
|
|
209
|
-
Before creating a release tag, exercise the packed client against the selected
|
|
210
|
-
server artifact:
|
|
211
|
-
|
|
212
|
-
```sh
|
|
213
|
-
npm run release:exercise -- \
|
|
214
|
-
--server /absolute/path/to/borgmcp-server.tgz \
|
|
215
|
-
--server-integrity 'sha512-...'
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
The server integrity must come from the reviewed producer of that artifact. Run
|
|
219
|
-
the command once with the published counterpart. When the client and server are
|
|
220
|
-
being released together, run it again with the co-releasing server candidate.
|
|
221
|
-
The default path builds and packs the current client; `--client-tarball` exists
|
|
222
|
-
only for reproducing a reviewed packed client or running a negative control.
|
|
223
|
-
|
|
224
|
-
This harness exercises reviewed release candidates and their published
|
|
225
|
-
counterparts. It is not a containment sandbox for hostile or otherwise untrusted
|
|
226
|
-
packages and must not be used as one. The temporary install and data directories
|
|
227
|
-
isolate the reviewed exercise from normal product state; they are not an
|
|
228
|
-
operating-system security boundary.
|
|
229
|
-
|
|
230
|
-
The harness requires Node.js 22, npm 11.18.0, Python 3, and macOS or Linux. It
|
|
231
|
-
installs both tarballs into a private temporary project, bootstraps isolated
|
|
232
|
-
server data, and starts the installed server directly. It never uses
|
|
233
|
-
`borg server setup`, because registry-backed activation would select the
|
|
234
|
-
previously published server instead of a candidate.
|
|
235
|
-
|
|
236
|
-
Both composed terminal journeys run under a real PTY:
|
|
237
|
-
|
|
238
|
-
- `borg server dashboard` must render the attached-viewer footer, exit cleanly
|
|
239
|
-
on Ctrl-C, restore the cursor and alternate screen, and leave the server's
|
|
240
|
-
pinned-TLS process healthy at `GET /healthz` (204, empty body).
|
|
241
|
-
- `borg server start` must render the foreground-server footer, exit cleanly on
|
|
242
|
-
Ctrl-C, restore the terminal, stop the server, and release its health endpoint.
|
|
243
|
-
|
|
244
|
-
The client facade resolves `borg-mcp-server` by bare name. The harness therefore
|
|
245
|
-
uses a controlled shim only to arrange resolution, then verifies the outcome:
|
|
246
|
-
before trusting a frame, it reads the live process command and requires the
|
|
247
|
-
absolute installed server entry. Every client or server executable must resolve
|
|
248
|
-
inside the installed package root covered by the SRI cited for that role. Its
|
|
249
|
-
JSON report records the absolute path, version, and independently supplied
|
|
250
|
-
integrity for the client, dashboard listener, dashboard viewer, and foreground
|
|
251
|
-
listener/viewer roles. PATH ordering alone is never accepted as identity evidence.
|
|
252
|
-
|
|
253
|
-
The harness is a fail-closed release gate. A missing frame, non-PTY execution,
|
|
254
|
-
wrong journey footer, substituted artifact, nonzero exit, absent terminal
|
|
255
|
-
restore sequence, failed post-exit health assertion, timeout, or oversized
|
|
256
|
-
transcript fails the command. Its controls must remain demonstrably bidirectional:
|
|
257
|
-
the current client/server pairing passes; and a deliberately wrong server
|
|
258
|
-
integrity fails before either journey starts.
|
|
259
|
-
|
|
260
|
-
The terminal-restore negative control is specifically the packed pre-#146 client
|
|
261
|
-
from commit `81da7b970ffb4e76a35c7bc551c419fec702a3b6` composed with published
|
|
262
|
-
`borgmcp-server@0.2.0`, registry integrity
|
|
263
|
-
`sha512-squb0+vdy0q7l/4FeV7OTvSm7OiFWGsAjGhcVEXYrQc9K/8jJYduqPS90VBwaJRT6z221Gxf3xQ5SeZe/Qoncw==`.
|
|
264
|
-
That composition must fail on the missing cursor-restore sequence. A newer server
|
|
265
|
-
candidate can mask the old client's defect and is not a valid counterpart for
|
|
266
|
-
this negative control.
|
|
267
|
-
|
|
268
|
-
```sh
|
|
269
|
-
npm run release:exercise -- \
|
|
270
|
-
--server borgmcp-server@0.2.0 \
|
|
271
|
-
--server-integrity 'sha512-squb0+vdy0q7l/4FeV7OTvSm7OiFWGsAjGhcVEXYrQc9K/8jJYduqPS90VBwaJRT6z221Gxf3xQ5SeZe/Qoncw==' \
|
|
272
|
-
--client-tarball /absolute/path/to/pre-146-borgmcp-2.1.1.tgz
|
|
273
|
-
```
|
|
274
|
-
|
|
275
70
|
The only trigger is a protected annotated `v<package version>` tag. Manual
|
|
276
|
-
dispatch is intentionally absent
|
|
277
|
-
existing tag. The workflow rejects reruns, root `.npmrc`
|
|
71
|
+
dispatch is intentionally absent. The workflow rejects root `.npmrc`
|
|
278
72
|
configuration, non-tag events, lightweight or malformed tags, version mismatch,
|
|
279
73
|
source/tag mismatch, and tags whose commits are not on protected `main`.
|
|
280
74
|
|
|
@@ -283,7 +77,8 @@ The unprivileged `verify` job performs one sequence:
|
|
|
283
77
|
1. Verify the public-source boundary, extraction readiness, exact shared-package
|
|
284
78
|
pin, and canonical registry lock metadata.
|
|
285
79
|
2. Install the lockfile once with lifecycle scripts disabled and audit it.
|
|
286
|
-
3. Run
|
|
80
|
+
3. Run one readable build and reject generated `dist` drift. Tests already ran
|
|
81
|
+
in CI on the exact source.
|
|
287
82
|
4. Produce one npm tarball.
|
|
288
83
|
5. Verify that tarball once for package identity, license/notice, source and map
|
|
289
84
|
completeness, executable bins, archive safety, dependency integrity, and
|
|
@@ -294,14 +89,6 @@ The unprivileged `verify` job performs one sequence:
|
|
|
294
89
|
7. Upload only the tarball and its verifier-generated report as the same-run
|
|
295
90
|
release artifact.
|
|
296
91
|
|
|
297
|
-
After `verify` succeeds, the designated Queen operator alone approves the
|
|
298
|
-
`npm-publish` environment. There is no separate pre-stage exact-artifact
|
|
299
|
-
Security gate: the verify job is the mechanical authority for the exact bytes
|
|
300
|
-
that the stage job consumes. Environment approval authorizes submitting those
|
|
301
|
-
bytes to npm's private staged-publishing service; it does not make the version
|
|
302
|
-
public, permit a rerun or rebuilt artifact, or authorize approval by another
|
|
303
|
-
actor.
|
|
304
|
-
|
|
305
92
|
The protected `publish` job alone receives `id-token: write`. It downloads the
|
|
306
93
|
same-run artifact and rejects a report whose package name or version differs
|
|
307
94
|
from the release, a version that already exists, an unclaimed package, or an
|
|
@@ -313,48 +100,15 @@ package.
|
|
|
313
100
|
|
|
314
101
|
Successful completion of the workflow means npm accepted the immutable staged
|
|
315
102
|
tarball. It does not mean the version is public. Stage acceptance consumes the
|
|
316
|
-
|
|
103
|
+
version, but must not trigger
|
|
317
104
|
release announcements, issue closure, consumer pins, site synchronization, or
|
|
318
105
|
claims that the version was published. There is no workflow registry readback:
|
|
319
106
|
stage inspection and approval require an interactive npm identity and cannot use
|
|
320
107
|
the workflow's OIDC credential.
|
|
321
108
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
`borgmcp-shared`, `borgmcp-server`, and `borgmcp`. Use authenticated
|
|
326
|
-
`npm stage list` and `npm stage view <UUID>` to record and inspect all three stage
|
|
327
|
-
UUIDs and verify each package, version, and eventual `latest` tag. For every
|
|
328
|
-
package, `npm stage download <UUID>` is mandatory; compute its SHA-512 SRI and
|
|
329
|
-
require an exact match with that workflow run's same-run artifact report. Bind
|
|
330
|
-
the source annotated tag object, commit, and workflow run separately from GitHub
|
|
331
|
-
evidence, because npm stage inspection does not expose them. Exercise the exact
|
|
332
|
-
downloaded coupled set before approval. Confirm that public `latest`, public
|
|
333
|
-
`versions`, and client update resolution still expose the prior coherent release
|
|
334
|
-
set. If a pending stage appears on any public surface, approve nothing and halt
|
|
335
|
-
this mechanism before consumers can observe it.
|
|
336
|
-
|
|
337
|
-
Approve the verified UUIDs in one operator session, using interactive 2FA, in
|
|
338
|
-
this exact order:
|
|
339
|
-
|
|
340
|
-
1. `npm stage approve <shared-stage-uuid>`
|
|
341
|
-
2. `npm stage approve <server-stage-uuid>`
|
|
342
|
-
3. `npm stage approve <client-stage-uuid>`
|
|
343
|
-
|
|
344
|
-
The approvals are not atomic. Shared approval leaves existing client and server
|
|
345
|
-
pins coherent. Server approval opens a bounded mismatch window between public
|
|
346
|
-
server `latest` and client `latest`; client approval closes it. After an approval
|
|
347
|
-
returns successfully, continue only while the next stage remains valid. For an
|
|
348
|
-
ambiguous result, inspect authenticated stage state and canonical public package
|
|
349
|
-
version/integrity before acting; never repeat an approval blindly.
|
|
350
|
-
|
|
351
|
-
The terminal release boundary is successful interactive stage approval followed
|
|
352
|
-
by canonical registry visibility, integrity verification, and registry
|
|
353
|
-
provenance-attestation inspection. Stage inspection cannot establish provenance
|
|
354
|
-
before approval; Trusted Publishing carries it to the live package, where the
|
|
355
|
-
registry attestation is authoritative. Only then may the release be announced,
|
|
356
|
-
issues closed, consumer pins or site data synchronized, or the version described
|
|
357
|
-
as published.
|
|
109
|
+
Inspect the npm stage, then approve it interactively. This stage approval is the
|
|
110
|
+
sole human publication boundary. Confirm canonical live package visibility and
|
|
111
|
+
integrity before announcing the release or updating dependent packages.
|
|
358
112
|
|
|
359
113
|
After all three packages cross that boundary, create their GitHub Releases in
|
|
360
114
|
the same shared → server → client operator session. In each package repository,
|
|
@@ -364,46 +118,16 @@ run:
|
|
|
364
118
|
GITHUB_TOKEN="$(gh auth token)" node scripts/create-github-release.mjs <version>
|
|
365
119
|
```
|
|
366
120
|
|
|
367
|
-
The script binds the annotated tag,
|
|
368
|
-
|
|
369
|
-
the
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
it into an isolated prefix and exercise the real user update path end to end.
|
|
373
|
-
This is product verification, not candidate validation: failure routes a new
|
|
374
|
-
reviewed fix and never invalidates, rebuilds, retags, or reruns the immutable
|
|
375
|
-
release. Do not repeat byte comparisons, packed-version checks, source-tree
|
|
376
|
-
verification, dist-tag readback, or provenance reconstruction that the
|
|
377
|
-
exact-artifact `verify` and stage jobs already completed. The canonical
|
|
378
|
-
live-version integrity check is required because it establishes the approval
|
|
379
|
-
boundary; it is not a duplicate candidate verification.
|
|
380
|
-
|
|
381
|
-
No separate checksum file is needed: the tarball verifier records canonical
|
|
382
|
-
SHA-512 SRI in the artifact report. GitHub's same-run artifact transport and the
|
|
383
|
-
report bind the reviewed candidate without repeated SHA512 choreography.
|
|
384
|
-
|
|
385
|
-
Rely on npm Trusted Publishing. Perform the one authoritative registry
|
|
386
|
-
provenance-attestation inspection at the approved-live boundary; do not
|
|
387
|
-
reconstruct DSSE, in-toto, SLSA, workflow-ref, or builder statements locally or
|
|
388
|
-
add redundant provenance readback.
|
|
389
|
-
Do not add cross-run tuple variables, cross-run artifact selection, duplicate
|
|
390
|
-
builds, duplicate package verification, checksum bundles, or SBOM ceremony.
|
|
121
|
+
The script binds the annotated tag, live npm package and integrity, and Release
|
|
122
|
+
absence before creating the Release. It reads
|
|
123
|
+
the curated `docs/releases/<version>.md` notes from the exact tagged commit,
|
|
124
|
+
renders them under `News and fixes`, and refuses missing or blank notes and an
|
|
125
|
+
existing Release.
|
|
391
126
|
|
|
392
127
|
## Stop And Recovery Conditions
|
|
393
128
|
|
|
394
|
-
Stop when source, settings, ownership, tag, artifact, test, audit, review
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
Before any approval, missing or inconsistent stage evidence means approve none.
|
|
401
|
-
Reject all three stages only when abandoning the coupled candidate; Borg treats
|
|
402
|
-
every rejected or unusable tagged stage as burned, even though npm permits some
|
|
403
|
-
re-staging. Replacement versions require fresh review, tags, and stage runs.
|
|
404
|
-
After shared approval but before server approval, stopping is compatibility-safe
|
|
405
|
-
for the existing client/server pair, but shared is immutable and any repair uses
|
|
406
|
-
fresh versions. After server approval, prioritize the already-verified client
|
|
407
|
-
approval because the public pair is mismatched. If that client stage cannot be
|
|
408
|
-
approved, do not reject it or rerun the tag; prepare newly reviewed matching
|
|
409
|
-
server/client recovery versions and state the live mismatch window explicitly.
|
|
129
|
+
Stop when source, settings, ownership, tag, artifact, test, audit, or review
|
|
130
|
+
evidence is missing or inconsistent. Never move or reuse a tag,
|
|
131
|
+
overwrite an npm version, unpublish to hide a failure, or substitute a local
|
|
132
|
+
rebuild. A pre-stage workflow failure may be rerun against the same immutable
|
|
133
|
+
tag. After npm accepts a stage, recovery uses a fresh reviewed version.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "borgmcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.0",
|
|
4
4
|
"description": "Coordinate AI coding agents in shared cubes. Works with Claude Code, Codex, and OpenCode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"README.md",
|
|
49
49
|
"LICENSE",
|
|
50
50
|
"NOTICE",
|
|
51
|
+
"THIRD_PARTY_NOTICES.md",
|
|
51
52
|
"SECURITY.md",
|
|
52
53
|
"CONTRIBUTING.md"
|
|
53
54
|
],
|
|
@@ -71,7 +72,7 @@
|
|
|
71
72
|
},
|
|
72
73
|
"dependencies": {
|
|
73
74
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
74
|
-
"borgmcp-shared": "0.
|
|
75
|
+
"borgmcp-shared": "0.12.2",
|
|
75
76
|
"chalk": "^5.3.0",
|
|
76
77
|
"prompts": "^2.4.2",
|
|
77
78
|
"which": "^4.0.0"
|
package/src/assimilate-deps.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
resumeLocalBorgServerEnrollment,
|
|
41
41
|
sendBorgServerAttach,
|
|
42
42
|
} from './server-handshake.js';
|
|
43
|
+
import { advanceLocalServerCursor } from './local-server-cursor.js';
|
|
43
44
|
import {
|
|
44
45
|
findIncompleteSiblingAttempt,
|
|
45
46
|
observeSeat,
|
|
@@ -483,6 +484,16 @@ export function buildDefaultAssimilateDeps(
|
|
|
483
484
|
);
|
|
484
485
|
}
|
|
485
486
|
}
|
|
487
|
+
if (prepared.initialLogCursor) {
|
|
488
|
+
const binding = {
|
|
489
|
+
origin: apiUrl,
|
|
490
|
+
trustIdentity: serverTrustIdentity,
|
|
491
|
+
cubeId: prepared.cube.id,
|
|
492
|
+
droneId: prepared.drone.id,
|
|
493
|
+
};
|
|
494
|
+
await advanceLocalServerCursor(binding, prepared.initialLogCursor);
|
|
495
|
+
await advanceLocalServerCursor({ ...binding, purpose: 'stream' }, prepared.initialLogCursor);
|
|
496
|
+
}
|
|
486
497
|
return {
|
|
487
498
|
cube_id: prepared.cube.id,
|
|
488
499
|
drone_id: prepared.drone.id,
|
package/src/cli-help.ts
CHANGED
|
@@ -57,12 +57,15 @@ export function quickstartHelpText(version: string): string {
|
|
|
57
57
|
`Usage:\n` +
|
|
58
58
|
` borg quickstart [options]\n\n` +
|
|
59
59
|
`Options:\n` +
|
|
60
|
-
` --template
|
|
60
|
+
` --template <name> Choose without prompting:\n` +
|
|
61
|
+
` ${NEW_CUBE_TEMPLATE_OPTIONS}\n` +
|
|
61
62
|
` --role <slug>[:<count>] Fully specify the roster (repeatable)\n` +
|
|
62
63
|
` --yes, -y Accept the displayed plan\n` +
|
|
63
64
|
` --help, -h Show this help\n\n` +
|
|
64
|
-
`
|
|
65
|
-
`
|
|
65
|
+
`For the current repository, quickstart creates and launches a full roster.\n` +
|
|
66
|
+
`Use --role to replace that roster with an explicit selection. Quickstart\n` +
|
|
67
|
+
`requires a running Borg server and never starts one. Rerun the same command\n` +
|
|
68
|
+
`after a partial failure; existing drones are kept and skipped.\n`
|
|
66
69
|
);
|
|
67
70
|
}
|
|
68
71
|
|
|
@@ -70,10 +73,17 @@ export function cloneHelpText(version: string): string {
|
|
|
70
73
|
return (
|
|
71
74
|
`borg clone (borgmcp ${version}) — clone a repository and run quickstart\n\n` +
|
|
72
75
|
`Usage:\n` +
|
|
73
|
-
` borg clone <repository-url> [directory] [
|
|
76
|
+
` borg clone <repository-url> [directory] [options]\n\n` +
|
|
74
77
|
`Options:\n` +
|
|
75
|
-
` --
|
|
76
|
-
`
|
|
78
|
+
` --template <name> Choose without prompting:\n` +
|
|
79
|
+
` ${NEW_CUBE_TEMPLATE_OPTIONS}\n` +
|
|
80
|
+
` --role <slug>[:<count>] Fully specify the roster (repeatable)\n` +
|
|
81
|
+
` --yes, -y Accept the displayed plan\n` +
|
|
82
|
+
` --checkout-only Stop after the checkout is ready\n` +
|
|
83
|
+
` --no-launch Same as --checkout-only\n` +
|
|
84
|
+
` --help, -h Show this help\n\n` +
|
|
85
|
+
`Clone checks out a new repository, then delegates the complete setup directly to\n` +
|
|
86
|
+
`quickstart. Non-interactive full setup requires both --yes and --template.\n` +
|
|
77
87
|
`A repeated command reuses a checkout only when its origin matches. Default\n` +
|
|
78
88
|
`destination names avoid non-repository collisions. Credential-bearing URLs are\n` +
|
|
79
89
|
`refused; use a Git credential helper or SSH configuration instead.\n`
|
|
@@ -162,7 +172,7 @@ export function topLevelHelpText(version: string): string {
|
|
|
162
172
|
` borg doctor Check agent hook commands, versions, configs, and the OpenCode plugin\n` +
|
|
163
173
|
` borg clone <url> [dir] Clone a repository, then create and launch its cube\n` +
|
|
164
174
|
` borg quickstart Create a cube and a drone for every role, then launch them\n` +
|
|
165
|
-
` borg assimilate [role] Join or create a cube\n` +
|
|
175
|
+
` borg assimilate [role] Join or create a cube with one drone under one role\n` +
|
|
166
176
|
` borg assimilate --host <host> Join or create on an explicit server\n` +
|
|
167
177
|
` borg assimilate --worktree <name> Spawn a worktree drone (in ~/.borg/worktrees/<repo>/<name>)\n` +
|
|
168
178
|
` borg server cube init Initialize this repository's cube without creating a drone\n` +
|
|
@@ -280,6 +290,8 @@ export function assimilateHelpText(version: string): string {
|
|
|
280
290
|
` --cli claude|codex|opencode Agent CLI to launch\n` +
|
|
281
291
|
` --model claude:<model> Legacy Claude model override (configure models in the agent CLI)\n` +
|
|
282
292
|
` --yes, -y Accept new-cube defaults; never adopt by name\n\n` +
|
|
293
|
+
`Assimilate adds or resumes one drone under one role; use quickstart when you want\n` +
|
|
294
|
+
`the repository's full roster.\n` +
|
|
283
295
|
`Creation shows repository context, name, template, and one confirmation. An existing\n` +
|
|
284
296
|
`repository association skips all prompts. One accessible exact-name legacy cube requires\n` +
|
|
285
297
|
`explicit interactive adoption; ambiguous matches fail closed. An enrolled owner client may\n` +
|
package/src/clone-cmd.ts
CHANGED
|
@@ -4,7 +4,12 @@ import { basename, dirname, resolve } from 'node:path';
|
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { hasCloneCredentials, redactCloneSecrets } from './clone-security.js';
|
|
6
6
|
import type { CloneArgs } from './parse-clone-args.js';
|
|
7
|
-
import {
|
|
7
|
+
import type { QuickstartArgs } from './parse-quickstart-args.js';
|
|
8
|
+
import {
|
|
9
|
+
buildDefaultQuickstartDeps,
|
|
10
|
+
runQuickstart,
|
|
11
|
+
type QuickstartRunOptions,
|
|
12
|
+
} from './quickstart-cmd.js';
|
|
8
13
|
import { shellEscape } from './shell-escape.js';
|
|
9
14
|
|
|
10
15
|
export interface GitRunResult {
|
|
@@ -22,7 +27,8 @@ export interface CloneDeps {
|
|
|
22
27
|
readDirectory: (path: string) => string[];
|
|
23
28
|
createDirectory: (path: string) => boolean;
|
|
24
29
|
removeTree: (path: string) => void;
|
|
25
|
-
|
|
30
|
+
isTTY: () => boolean;
|
|
31
|
+
quickstart: (cwd: string, args: QuickstartArgs, options: QuickstartRunOptions) => Promise<number>;
|
|
26
32
|
stdout: (text: string) => void;
|
|
27
33
|
stderr: (text: string) => void;
|
|
28
34
|
}
|
|
@@ -61,9 +67,10 @@ export function buildDefaultCloneDeps(): CloneDeps {
|
|
|
61
67
|
}
|
|
62
68
|
},
|
|
63
69
|
removeTree: (path) => rmSync(path, { recursive: true, force: true }),
|
|
64
|
-
|
|
70
|
+
isTTY: () => process.stdin.isTTY === true,
|
|
71
|
+
quickstart: async (cwd, args, options) => {
|
|
65
72
|
process.chdir(cwd);
|
|
66
|
-
return runQuickstart(
|
|
73
|
+
return runQuickstart(args, buildDefaultQuickstartDeps(), options);
|
|
67
74
|
},
|
|
68
75
|
stdout: (text) => process.stdout.write(text),
|
|
69
76
|
stderr: (text) => process.stderr.write(text),
|
|
@@ -177,6 +184,13 @@ export async function runClone(args: CloneArgs, rawDeps: CloneDeps): Promise<num
|
|
|
177
184
|
deps.stderr(`borg clone: ${valid.error}.\n`);
|
|
178
185
|
return 1;
|
|
179
186
|
}
|
|
187
|
+
if (!args.checkoutOnly && !deps.isTTY() && (!args.yes || !args.template)) {
|
|
188
|
+
deps.stderr(
|
|
189
|
+
'borg clone: non-interactive full setup requires both --yes and --template; ' +
|
|
190
|
+
'use --checkout-only to clone without setup.\n',
|
|
191
|
+
);
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
180
194
|
const selected = chooseDestination(deps, args);
|
|
181
195
|
if ('error' in selected) {
|
|
182
196
|
deps.stderr(`borg clone: ${selected.error}.\n`);
|
|
@@ -224,7 +238,7 @@ export async function runClone(args: CloneArgs, rawDeps: CloneDeps): Promise<num
|
|
|
224
238
|
deps.stdout(`Cloned ${sourceName(args.repositoryUrl)} into ${destination}.\n`);
|
|
225
239
|
}
|
|
226
240
|
|
|
227
|
-
if (args.
|
|
241
|
+
if (args.checkoutOnly) {
|
|
228
242
|
deps.stdout(
|
|
229
243
|
`Checkout ready at ${destination}. No cube or drone was created.\n` +
|
|
230
244
|
`Next: cd ${shellEscape(destination)} && borg quickstart\n`,
|
|
@@ -232,8 +246,23 @@ export async function runClone(args: CloneArgs, rawDeps: CloneDeps): Promise<num
|
|
|
232
246
|
return 0;
|
|
233
247
|
}
|
|
234
248
|
deps.chdir(destination);
|
|
235
|
-
const
|
|
236
|
-
|
|
249
|
+
const quickstartArgs: QuickstartArgs = {
|
|
250
|
+
...(args.template === undefined ? {} : { template: args.template }),
|
|
251
|
+
roles: args.roles,
|
|
252
|
+
yes: args.yes,
|
|
253
|
+
};
|
|
254
|
+
let cancelled = false;
|
|
255
|
+
const code = await deps.quickstart(destination, quickstartArgs, {
|
|
256
|
+
onCancelled: (kind) => {
|
|
257
|
+
cancelled = true;
|
|
258
|
+
const message =
|
|
259
|
+
`${kind === 'interrupted' ? '\n' : ''}borg clone: cancelled. Checkout remains at ${destination}.\n` +
|
|
260
|
+
`Resume: cd ${shellEscape(destination)} && borg quickstart\n`;
|
|
261
|
+
if (kind === 'interrupted') deps.stderr(message);
|
|
262
|
+
else deps.stdout(message);
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
if (code !== 0 && !cancelled) {
|
|
237
266
|
deps.stderr(
|
|
238
267
|
`The checkout${cloned ? '' : ' you already had'} is ready at ${destination}, but quickstart did not finish. ` +
|
|
239
268
|
`It was left untouched; cd there and run \`borg quickstart\` again.\n`,
|