open source is social v-it.org
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

node compatibility + npm publish prep

Replace all Bun-specific APIs in runtime code with node equivalents:
- Bun.serve() → node:http createServer (login.js OAuth callback)
- Bun.spawn() → child_process.spawn (login.js browser open)
- Bun.which() → execFileSync which helper (setup.js, adopt.js)
- Bun.spawnSync() → child_process.spawnSync (setup.js skill install)
- Shebang changed from #!/usr/bin/env bun to #!/usr/bin/env node

Add engines field (node >=20), package-lock.json, CI workflow
(bun test + node smoke tests on 20/22), and npx install docs.

Also includes vit branding (mark/brand prefix on CLI output).

153 tests pass under bun, CLI verified working under node 22.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+1713 -85
+32
.github/workflows/test.yml
··· 1 + name: test 2 + 3 + on: 4 + push: 5 + branches: [main] 6 + pull_request: 7 + branches: [main] 8 + 9 + jobs: 10 + test-bun: 11 + runs-on: ubuntu-latest 12 + steps: 13 + - uses: actions/checkout@v4 14 + - uses: oven-sh/setup-bun@v2 15 + with: 16 + bun-version: latest 17 + - run: bun install 18 + - run: bun test 19 + 20 + test-node: 21 + runs-on: ubuntu-latest 22 + strategy: 23 + matrix: 24 + node-version: [20, 22] 25 + steps: 26 + - uses: actions/checkout@v4 27 + - uses: actions/setup-node@v4 28 + with: 29 + node-version: ${{ matrix.node-version }} 30 + - run: npm install 31 + - run: node bin/vit.js --help 32 + - run: node bin/vit.js --version
+3
Makefile
··· 11 11 12 12 clean: 13 13 rm -rf node_modules/ 14 + 15 + publish: 16 + npm publish
+8 -4
README.md
··· 8 8 9 9 ## install 10 10 11 - for development: 11 + ```bash 12 + npx vit doctor 13 + ``` 14 + 15 + or install globally: 12 16 13 17 ```bash 14 - make install 18 + npm install -g vit 15 19 ``` 16 20 17 - for global CLI use: 21 + for development: 18 22 19 23 ```bash 20 - make install-user 24 + make install 21 25 ``` 22 26 23 27 ## terminology
+1 -1
bin/vit.js
··· 1 - #!/usr/bin/env bun 1 + #!/usr/bin/env node 2 2 // SPDX-License-Identifier: AGPL-3.0-only 3 3 // Copyright (c) 2026 sol pbc 4 4
+1536
package-lock.json
··· 1 + { 2 + "name": "vit", 3 + "version": "0.1.0", 4 + "lockfileVersion": 3, 5 + "requires": true, 6 + "packages": { 7 + "": { 8 + "name": "vit", 9 + "version": "0.1.0", 10 + "license": "AGPL-3.0-only", 11 + "dependencies": { 12 + "@atproto/api": "^0.18.20", 13 + "@atproto/common-web": "^0.4.16", 14 + "@atproto/oauth-client-node": "^0.3.16", 15 + "@ipld/dag-cbor": "^9.2.0", 16 + "@noble/curves": "^1.8.0", 17 + "@noble/hashes": "^1.7.0", 18 + "@scure/bip39": "2.0.1", 19 + "bs58": "^6.0.0", 20 + "commander": "^13.0.0", 21 + "env-paths": "4.0.0", 22 + "isomorphic-git": "1.37.0", 23 + "memfs": "4.56.10" 24 + }, 25 + "bin": { 26 + "vit": "bin/vit.js" 27 + }, 28 + "engines": { 29 + "node": ">=20.0.0" 30 + } 31 + }, 32 + "node_modules/@atproto-labs/did-resolver": { 33 + "version": "0.2.6", 34 + "license": "MIT", 35 + "dependencies": { 36 + "@atproto-labs/fetch": "0.2.3", 37 + "@atproto-labs/pipe": "0.1.1", 38 + "@atproto-labs/simple-store": "0.3.0", 39 + "@atproto-labs/simple-store-memory": "0.1.4", 40 + "@atproto/did": "0.3.0", 41 + "zod": "^3.23.8" 42 + } 43 + }, 44 + "node_modules/@atproto-labs/fetch": { 45 + "version": "0.2.3", 46 + "license": "MIT", 47 + "dependencies": { 48 + "@atproto-labs/pipe": "0.1.1" 49 + } 50 + }, 51 + "node_modules/@atproto-labs/fetch-node": { 52 + "version": "0.2.0", 53 + "license": "MIT", 54 + "dependencies": { 55 + "@atproto-labs/fetch": "0.2.3", 56 + "@atproto-labs/pipe": "0.1.1", 57 + "ipaddr.js": "^2.1.0", 58 + "undici": "^6.14.1" 59 + }, 60 + "engines": { 61 + "node": ">=18.7.0" 62 + } 63 + }, 64 + "node_modules/@atproto-labs/handle-resolver": { 65 + "version": "0.3.6", 66 + "license": "MIT", 67 + "dependencies": { 68 + "@atproto-labs/simple-store": "0.3.0", 69 + "@atproto-labs/simple-store-memory": "0.1.4", 70 + "@atproto/did": "0.3.0", 71 + "zod": "^3.23.8" 72 + } 73 + }, 74 + "node_modules/@atproto-labs/handle-resolver-node": { 75 + "version": "0.1.25", 76 + "license": "MIT", 77 + "dependencies": { 78 + "@atproto-labs/fetch-node": "0.2.0", 79 + "@atproto-labs/handle-resolver": "0.3.6", 80 + "@atproto/did": "0.3.0" 81 + }, 82 + "engines": { 83 + "node": ">=18.7.0" 84 + } 85 + }, 86 + "node_modules/@atproto-labs/identity-resolver": { 87 + "version": "0.3.6", 88 + "license": "MIT", 89 + "dependencies": { 90 + "@atproto-labs/did-resolver": "0.2.6", 91 + "@atproto-labs/handle-resolver": "0.3.6" 92 + } 93 + }, 94 + "node_modules/@atproto-labs/pipe": { 95 + "version": "0.1.1", 96 + "license": "MIT" 97 + }, 98 + "node_modules/@atproto-labs/simple-store": { 99 + "version": "0.3.0", 100 + "license": "MIT" 101 + }, 102 + "node_modules/@atproto-labs/simple-store-memory": { 103 + "version": "0.1.4", 104 + "license": "MIT", 105 + "dependencies": { 106 + "@atproto-labs/simple-store": "0.3.0", 107 + "lru-cache": "^10.2.0" 108 + } 109 + }, 110 + "node_modules/@atproto/api": { 111 + "version": "0.18.20", 112 + "license": "MIT", 113 + "dependencies": { 114 + "@atproto/common-web": "^0.4.15", 115 + "@atproto/lexicon": "^0.6.1", 116 + "@atproto/syntax": "^0.4.3", 117 + "@atproto/xrpc": "^0.7.7", 118 + "await-lock": "^2.2.2", 119 + "multiformats": "^9.9.0", 120 + "tlds": "^1.234.0", 121 + "zod": "^3.23.8" 122 + } 123 + }, 124 + "node_modules/@atproto/common-web": { 125 + "version": "0.4.16", 126 + "license": "MIT", 127 + "dependencies": { 128 + "@atproto/lex-data": "^0.0.11", 129 + "@atproto/lex-json": "^0.0.11", 130 + "@atproto/syntax": "^0.4.3", 131 + "zod": "^3.23.8" 132 + } 133 + }, 134 + "node_modules/@atproto/did": { 135 + "version": "0.3.0", 136 + "license": "MIT", 137 + "dependencies": { 138 + "zod": "^3.23.8" 139 + } 140 + }, 141 + "node_modules/@atproto/jwk": { 142 + "version": "0.6.0", 143 + "license": "MIT", 144 + "dependencies": { 145 + "multiformats": "^9.9.0", 146 + "zod": "^3.23.8" 147 + } 148 + }, 149 + "node_modules/@atproto/jwk-jose": { 150 + "version": "0.1.11", 151 + "license": "MIT", 152 + "dependencies": { 153 + "@atproto/jwk": "0.6.0", 154 + "jose": "^5.2.0" 155 + } 156 + }, 157 + "node_modules/@atproto/jwk-webcrypto": { 158 + "version": "0.2.0", 159 + "license": "MIT", 160 + "dependencies": { 161 + "@atproto/jwk": "0.6.0", 162 + "@atproto/jwk-jose": "0.1.11", 163 + "zod": "^3.23.8" 164 + } 165 + }, 166 + "node_modules/@atproto/jwk/node_modules/multiformats": { 167 + "version": "9.9.0", 168 + "license": "(Apache-2.0 AND MIT)" 169 + }, 170 + "node_modules/@atproto/lex-data": { 171 + "version": "0.0.11", 172 + "license": "MIT", 173 + "dependencies": { 174 + "multiformats": "^9.9.0", 175 + "tslib": "^2.8.1", 176 + "uint8arrays": "3.0.0", 177 + "unicode-segmenter": "^0.14.0" 178 + } 179 + }, 180 + "node_modules/@atproto/lex-data/node_modules/multiformats": { 181 + "version": "9.9.0", 182 + "license": "(Apache-2.0 AND MIT)" 183 + }, 184 + "node_modules/@atproto/lex-json": { 185 + "version": "0.0.11", 186 + "license": "MIT", 187 + "dependencies": { 188 + "@atproto/lex-data": "^0.0.11", 189 + "tslib": "^2.8.1" 190 + } 191 + }, 192 + "node_modules/@atproto/lexicon": { 193 + "version": "0.6.1", 194 + "license": "MIT", 195 + "dependencies": { 196 + "@atproto/common-web": "^0.4.13", 197 + "@atproto/syntax": "^0.4.3", 198 + "iso-datestring-validator": "^2.2.2", 199 + "multiformats": "^9.9.0", 200 + "zod": "^3.23.8" 201 + } 202 + }, 203 + "node_modules/@atproto/lexicon/node_modules/multiformats": { 204 + "version": "9.9.0", 205 + "license": "(Apache-2.0 AND MIT)" 206 + }, 207 + "node_modules/@atproto/oauth-client": { 208 + "version": "0.5.14", 209 + "license": "MIT", 210 + "dependencies": { 211 + "@atproto-labs/did-resolver": "0.2.6", 212 + "@atproto-labs/fetch": "0.2.3", 213 + "@atproto-labs/handle-resolver": "0.3.6", 214 + "@atproto-labs/identity-resolver": "0.3.6", 215 + "@atproto-labs/simple-store": "0.3.0", 216 + "@atproto-labs/simple-store-memory": "0.1.4", 217 + "@atproto/did": "0.3.0", 218 + "@atproto/jwk": "0.6.0", 219 + "@atproto/oauth-types": "0.6.2", 220 + "@atproto/xrpc": "0.7.7", 221 + "core-js": "^3", 222 + "multiformats": "^9.9.0", 223 + "zod": "^3.23.8" 224 + } 225 + }, 226 + "node_modules/@atproto/oauth-client-node": { 227 + "version": "0.3.16", 228 + "license": "MIT", 229 + "dependencies": { 230 + "@atproto-labs/did-resolver": "0.2.6", 231 + "@atproto-labs/handle-resolver-node": "0.1.25", 232 + "@atproto-labs/simple-store": "0.3.0", 233 + "@atproto/did": "0.3.0", 234 + "@atproto/jwk": "0.6.0", 235 + "@atproto/jwk-jose": "0.1.11", 236 + "@atproto/jwk-webcrypto": "0.2.0", 237 + "@atproto/oauth-client": "0.5.14", 238 + "@atproto/oauth-types": "0.6.2" 239 + }, 240 + "engines": { 241 + "node": ">=18.7.0" 242 + } 243 + }, 244 + "node_modules/@atproto/oauth-client/node_modules/multiformats": { 245 + "version": "9.9.0", 246 + "license": "(Apache-2.0 AND MIT)" 247 + }, 248 + "node_modules/@atproto/oauth-types": { 249 + "version": "0.6.2", 250 + "license": "MIT", 251 + "dependencies": { 252 + "@atproto/did": "0.3.0", 253 + "@atproto/jwk": "0.6.0", 254 + "zod": "^3.23.8" 255 + } 256 + }, 257 + "node_modules/@atproto/syntax": { 258 + "version": "0.4.3", 259 + "license": "MIT", 260 + "dependencies": { 261 + "tslib": "^2.8.1" 262 + } 263 + }, 264 + "node_modules/@atproto/xrpc": { 265 + "version": "0.7.7", 266 + "license": "MIT", 267 + "dependencies": { 268 + "@atproto/lexicon": "^0.6.0", 269 + "zod": "^3.23.8" 270 + } 271 + }, 272 + "node_modules/@ipld/dag-cbor": { 273 + "version": "9.2.5", 274 + "license": "Apache-2.0 OR MIT", 275 + "dependencies": { 276 + "cborg": "^4.0.0", 277 + "multiformats": "^13.1.0" 278 + }, 279 + "engines": { 280 + "node": ">=16.0.0", 281 + "npm": ">=7.0.0" 282 + } 283 + }, 284 + "node_modules/@ipld/dag-cbor/node_modules/multiformats": { 285 + "version": "13.4.2", 286 + "license": "Apache-2.0 OR MIT" 287 + }, 288 + "node_modules/@jsonjoy.com/base64": { 289 + "version": "1.1.2", 290 + "license": "Apache-2.0", 291 + "engines": { 292 + "node": ">=10.0" 293 + }, 294 + "funding": { 295 + "type": "github", 296 + "url": "https://github.com/sponsors/streamich" 297 + }, 298 + "peerDependencies": { 299 + "tslib": "2" 300 + } 301 + }, 302 + "node_modules/@jsonjoy.com/buffers": { 303 + "version": "17.67.0", 304 + "license": "Apache-2.0", 305 + "engines": { 306 + "node": ">=10.0" 307 + }, 308 + "funding": { 309 + "type": "github", 310 + "url": "https://github.com/sponsors/streamich" 311 + }, 312 + "peerDependencies": { 313 + "tslib": "2" 314 + } 315 + }, 316 + "node_modules/@jsonjoy.com/codegen": { 317 + "version": "1.0.0", 318 + "license": "Apache-2.0", 319 + "engines": { 320 + "node": ">=10.0" 321 + }, 322 + "funding": { 323 + "type": "github", 324 + "url": "https://github.com/sponsors/streamich" 325 + }, 326 + "peerDependencies": { 327 + "tslib": "2" 328 + } 329 + }, 330 + "node_modules/@jsonjoy.com/fs-core": { 331 + "version": "4.56.10", 332 + "license": "Apache-2.0", 333 + "dependencies": { 334 + "@jsonjoy.com/fs-node-builtins": "4.56.10", 335 + "@jsonjoy.com/fs-node-utils": "4.56.10", 336 + "thingies": "^2.5.0" 337 + }, 338 + "engines": { 339 + "node": ">=10.0" 340 + }, 341 + "funding": { 342 + "type": "github", 343 + "url": "https://github.com/sponsors/streamich" 344 + }, 345 + "peerDependencies": { 346 + "tslib": "2" 347 + } 348 + }, 349 + "node_modules/@jsonjoy.com/fs-fsa": { 350 + "version": "4.56.10", 351 + "license": "Apache-2.0", 352 + "dependencies": { 353 + "@jsonjoy.com/fs-core": "4.56.10", 354 + "@jsonjoy.com/fs-node-builtins": "4.56.10", 355 + "@jsonjoy.com/fs-node-utils": "4.56.10", 356 + "thingies": "^2.5.0" 357 + }, 358 + "engines": { 359 + "node": ">=10.0" 360 + }, 361 + "funding": { 362 + "type": "github", 363 + "url": "https://github.com/sponsors/streamich" 364 + }, 365 + "peerDependencies": { 366 + "tslib": "2" 367 + } 368 + }, 369 + "node_modules/@jsonjoy.com/fs-node": { 370 + "version": "4.56.10", 371 + "license": "Apache-2.0", 372 + "dependencies": { 373 + "@jsonjoy.com/fs-core": "4.56.10", 374 + "@jsonjoy.com/fs-node-builtins": "4.56.10", 375 + "@jsonjoy.com/fs-node-utils": "4.56.10", 376 + "@jsonjoy.com/fs-print": "4.56.10", 377 + "@jsonjoy.com/fs-snapshot": "4.56.10", 378 + "glob-to-regex.js": "^1.0.0", 379 + "thingies": "^2.5.0" 380 + }, 381 + "engines": { 382 + "node": ">=10.0" 383 + }, 384 + "funding": { 385 + "type": "github", 386 + "url": "https://github.com/sponsors/streamich" 387 + }, 388 + "peerDependencies": { 389 + "tslib": "2" 390 + } 391 + }, 392 + "node_modules/@jsonjoy.com/fs-node-builtins": { 393 + "version": "4.56.10", 394 + "license": "Apache-2.0", 395 + "engines": { 396 + "node": ">=10.0" 397 + }, 398 + "funding": { 399 + "type": "github", 400 + "url": "https://github.com/sponsors/streamich" 401 + }, 402 + "peerDependencies": { 403 + "tslib": "2" 404 + } 405 + }, 406 + "node_modules/@jsonjoy.com/fs-node-to-fsa": { 407 + "version": "4.56.10", 408 + "license": "Apache-2.0", 409 + "dependencies": { 410 + "@jsonjoy.com/fs-fsa": "4.56.10", 411 + "@jsonjoy.com/fs-node-builtins": "4.56.10", 412 + "@jsonjoy.com/fs-node-utils": "4.56.10" 413 + }, 414 + "engines": { 415 + "node": ">=10.0" 416 + }, 417 + "funding": { 418 + "type": "github", 419 + "url": "https://github.com/sponsors/streamich" 420 + }, 421 + "peerDependencies": { 422 + "tslib": "2" 423 + } 424 + }, 425 + "node_modules/@jsonjoy.com/fs-node-utils": { 426 + "version": "4.56.10", 427 + "license": "Apache-2.0", 428 + "dependencies": { 429 + "@jsonjoy.com/fs-node-builtins": "4.56.10" 430 + }, 431 + "engines": { 432 + "node": ">=10.0" 433 + }, 434 + "funding": { 435 + "type": "github", 436 + "url": "https://github.com/sponsors/streamich" 437 + }, 438 + "peerDependencies": { 439 + "tslib": "2" 440 + } 441 + }, 442 + "node_modules/@jsonjoy.com/fs-print": { 443 + "version": "4.56.10", 444 + "license": "Apache-2.0", 445 + "dependencies": { 446 + "@jsonjoy.com/fs-node-utils": "4.56.10", 447 + "tree-dump": "^1.1.0" 448 + }, 449 + "engines": { 450 + "node": ">=10.0" 451 + }, 452 + "funding": { 453 + "type": "github", 454 + "url": "https://github.com/sponsors/streamich" 455 + }, 456 + "peerDependencies": { 457 + "tslib": "2" 458 + } 459 + }, 460 + "node_modules/@jsonjoy.com/fs-snapshot": { 461 + "version": "4.56.10", 462 + "license": "Apache-2.0", 463 + "dependencies": { 464 + "@jsonjoy.com/buffers": "^17.65.0", 465 + "@jsonjoy.com/fs-node-utils": "4.56.10", 466 + "@jsonjoy.com/json-pack": "^17.65.0", 467 + "@jsonjoy.com/util": "^17.65.0" 468 + }, 469 + "engines": { 470 + "node": ">=10.0" 471 + }, 472 + "funding": { 473 + "type": "github", 474 + "url": "https://github.com/sponsors/streamich" 475 + }, 476 + "peerDependencies": { 477 + "tslib": "2" 478 + } 479 + }, 480 + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { 481 + "version": "17.67.0", 482 + "license": "Apache-2.0", 483 + "dependencies": { 484 + "@jsonjoy.com/base64": "17.67.0", 485 + "@jsonjoy.com/buffers": "17.67.0", 486 + "@jsonjoy.com/codegen": "17.67.0", 487 + "@jsonjoy.com/json-pointer": "17.67.0", 488 + "@jsonjoy.com/util": "17.67.0", 489 + "hyperdyperid": "^1.2.0", 490 + "thingies": "^2.5.0", 491 + "tree-dump": "^1.1.0" 492 + }, 493 + "engines": { 494 + "node": ">=10.0" 495 + }, 496 + "funding": { 497 + "type": "github", 498 + "url": "https://github.com/sponsors/streamich" 499 + }, 500 + "peerDependencies": { 501 + "tslib": "2" 502 + } 503 + }, 504 + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/base64": { 505 + "version": "17.67.0", 506 + "license": "Apache-2.0", 507 + "engines": { 508 + "node": ">=10.0" 509 + }, 510 + "funding": { 511 + "type": "github", 512 + "url": "https://github.com/sponsors/streamich" 513 + }, 514 + "peerDependencies": { 515 + "tslib": "2" 516 + } 517 + }, 518 + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/codegen": { 519 + "version": "17.67.0", 520 + "license": "Apache-2.0", 521 + "engines": { 522 + "node": ">=10.0" 523 + }, 524 + "funding": { 525 + "type": "github", 526 + "url": "https://github.com/sponsors/streamich" 527 + }, 528 + "peerDependencies": { 529 + "tslib": "2" 530 + } 531 + }, 532 + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/json-pointer": { 533 + "version": "17.67.0", 534 + "license": "Apache-2.0", 535 + "dependencies": { 536 + "@jsonjoy.com/util": "17.67.0" 537 + }, 538 + "engines": { 539 + "node": ">=10.0" 540 + }, 541 + "funding": { 542 + "type": "github", 543 + "url": "https://github.com/sponsors/streamich" 544 + }, 545 + "peerDependencies": { 546 + "tslib": "2" 547 + } 548 + }, 549 + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { 550 + "version": "17.67.0", 551 + "license": "Apache-2.0", 552 + "dependencies": { 553 + "@jsonjoy.com/buffers": "17.67.0", 554 + "@jsonjoy.com/codegen": "17.67.0" 555 + }, 556 + "engines": { 557 + "node": ">=10.0" 558 + }, 559 + "funding": { 560 + "type": "github", 561 + "url": "https://github.com/sponsors/streamich" 562 + }, 563 + "peerDependencies": { 564 + "tslib": "2" 565 + } 566 + }, 567 + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/codegen": { 568 + "version": "17.67.0", 569 + "license": "Apache-2.0", 570 + "engines": { 571 + "node": ">=10.0" 572 + }, 573 + "funding": { 574 + "type": "github", 575 + "url": "https://github.com/sponsors/streamich" 576 + }, 577 + "peerDependencies": { 578 + "tslib": "2" 579 + } 580 + }, 581 + "node_modules/@jsonjoy.com/json-pack": { 582 + "version": "1.21.0", 583 + "license": "Apache-2.0", 584 + "dependencies": { 585 + "@jsonjoy.com/base64": "^1.1.2", 586 + "@jsonjoy.com/buffers": "^1.2.0", 587 + "@jsonjoy.com/codegen": "^1.0.0", 588 + "@jsonjoy.com/json-pointer": "^1.0.2", 589 + "@jsonjoy.com/util": "^1.9.0", 590 + "hyperdyperid": "^1.2.0", 591 + "thingies": "^2.5.0", 592 + "tree-dump": "^1.1.0" 593 + }, 594 + "engines": { 595 + "node": ">=10.0" 596 + }, 597 + "funding": { 598 + "type": "github", 599 + "url": "https://github.com/sponsors/streamich" 600 + }, 601 + "peerDependencies": { 602 + "tslib": "2" 603 + } 604 + }, 605 + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { 606 + "version": "1.2.1", 607 + "license": "Apache-2.0", 608 + "engines": { 609 + "node": ">=10.0" 610 + }, 611 + "funding": { 612 + "type": "github", 613 + "url": "https://github.com/sponsors/streamich" 614 + }, 615 + "peerDependencies": { 616 + "tslib": "2" 617 + } 618 + }, 619 + "node_modules/@jsonjoy.com/json-pointer": { 620 + "version": "1.0.2", 621 + "license": "Apache-2.0", 622 + "dependencies": { 623 + "@jsonjoy.com/codegen": "^1.0.0", 624 + "@jsonjoy.com/util": "^1.9.0" 625 + }, 626 + "engines": { 627 + "node": ">=10.0" 628 + }, 629 + "funding": { 630 + "type": "github", 631 + "url": "https://github.com/sponsors/streamich" 632 + }, 633 + "peerDependencies": { 634 + "tslib": "2" 635 + } 636 + }, 637 + "node_modules/@jsonjoy.com/util": { 638 + "version": "1.9.0", 639 + "license": "Apache-2.0", 640 + "dependencies": { 641 + "@jsonjoy.com/buffers": "^1.0.0", 642 + "@jsonjoy.com/codegen": "^1.0.0" 643 + }, 644 + "engines": { 645 + "node": ">=10.0" 646 + }, 647 + "funding": { 648 + "type": "github", 649 + "url": "https://github.com/sponsors/streamich" 650 + }, 651 + "peerDependencies": { 652 + "tslib": "2" 653 + } 654 + }, 655 + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { 656 + "version": "1.2.1", 657 + "license": "Apache-2.0", 658 + "engines": { 659 + "node": ">=10.0" 660 + }, 661 + "funding": { 662 + "type": "github", 663 + "url": "https://github.com/sponsors/streamich" 664 + }, 665 + "peerDependencies": { 666 + "tslib": "2" 667 + } 668 + }, 669 + "node_modules/@noble/curves": { 670 + "version": "1.9.7", 671 + "license": "MIT", 672 + "dependencies": { 673 + "@noble/hashes": "1.8.0" 674 + }, 675 + "engines": { 676 + "node": "^14.21.3 || >=16" 677 + }, 678 + "funding": { 679 + "url": "https://paulmillr.com/funding/" 680 + } 681 + }, 682 + "node_modules/@noble/hashes": { 683 + "version": "1.8.0", 684 + "license": "MIT", 685 + "engines": { 686 + "node": "^14.21.3 || >=16" 687 + }, 688 + "funding": { 689 + "url": "https://paulmillr.com/funding/" 690 + } 691 + }, 692 + "node_modules/@scure/base": { 693 + "version": "2.0.0", 694 + "license": "MIT", 695 + "funding": { 696 + "url": "https://paulmillr.com/funding/" 697 + } 698 + }, 699 + "node_modules/@scure/bip39": { 700 + "version": "2.0.1", 701 + "license": "MIT", 702 + "dependencies": { 703 + "@noble/hashes": "2.0.1", 704 + "@scure/base": "2.0.0" 705 + }, 706 + "funding": { 707 + "url": "https://paulmillr.com/funding/" 708 + } 709 + }, 710 + "node_modules/@scure/bip39/node_modules/@noble/hashes": { 711 + "version": "2.0.1", 712 + "license": "MIT", 713 + "engines": { 714 + "node": ">= 20.19.0" 715 + }, 716 + "funding": { 717 + "url": "https://paulmillr.com/funding/" 718 + } 719 + }, 720 + "node_modules/abort-controller": { 721 + "version": "3.0.0", 722 + "license": "MIT", 723 + "dependencies": { 724 + "event-target-shim": "^5.0.0" 725 + }, 726 + "engines": { 727 + "node": ">=6.5" 728 + } 729 + }, 730 + "node_modules/async-lock": { 731 + "version": "1.4.1", 732 + "license": "MIT" 733 + }, 734 + "node_modules/available-typed-arrays": { 735 + "version": "1.0.7", 736 + "license": "MIT", 737 + "dependencies": { 738 + "possible-typed-array-names": "^1.0.0" 739 + }, 740 + "engines": { 741 + "node": ">= 0.4" 742 + }, 743 + "funding": { 744 + "url": "https://github.com/sponsors/ljharb" 745 + } 746 + }, 747 + "node_modules/await-lock": { 748 + "version": "2.2.2", 749 + "license": "MIT" 750 + }, 751 + "node_modules/base-x": { 752 + "version": "5.0.1", 753 + "license": "MIT" 754 + }, 755 + "node_modules/base64-js": { 756 + "version": "1.5.1", 757 + "funding": [ 758 + { 759 + "type": "github", 760 + "url": "https://github.com/sponsors/feross" 761 + }, 762 + { 763 + "type": "patreon", 764 + "url": "https://www.patreon.com/feross" 765 + }, 766 + { 767 + "type": "consulting", 768 + "url": "https://feross.org/support" 769 + } 770 + ], 771 + "license": "MIT" 772 + }, 773 + "node_modules/bs58": { 774 + "version": "6.0.0", 775 + "license": "MIT", 776 + "dependencies": { 777 + "base-x": "^5.0.0" 778 + } 779 + }, 780 + "node_modules/buffer": { 781 + "version": "6.0.3", 782 + "funding": [ 783 + { 784 + "type": "github", 785 + "url": "https://github.com/sponsors/feross" 786 + }, 787 + { 788 + "type": "patreon", 789 + "url": "https://www.patreon.com/feross" 790 + }, 791 + { 792 + "type": "consulting", 793 + "url": "https://feross.org/support" 794 + } 795 + ], 796 + "license": "MIT", 797 + "dependencies": { 798 + "base64-js": "^1.3.1", 799 + "ieee754": "^1.2.1" 800 + } 801 + }, 802 + "node_modules/call-bind": { 803 + "version": "1.0.8", 804 + "license": "MIT", 805 + "dependencies": { 806 + "call-bind-apply-helpers": "^1.0.0", 807 + "es-define-property": "^1.0.0", 808 + "get-intrinsic": "^1.2.4", 809 + "set-function-length": "^1.2.2" 810 + }, 811 + "engines": { 812 + "node": ">= 0.4" 813 + }, 814 + "funding": { 815 + "url": "https://github.com/sponsors/ljharb" 816 + } 817 + }, 818 + "node_modules/call-bind-apply-helpers": { 819 + "version": "1.0.2", 820 + "license": "MIT", 821 + "dependencies": { 822 + "es-errors": "^1.3.0", 823 + "function-bind": "^1.1.2" 824 + }, 825 + "engines": { 826 + "node": ">= 0.4" 827 + } 828 + }, 829 + "node_modules/call-bound": { 830 + "version": "1.0.4", 831 + "license": "MIT", 832 + "dependencies": { 833 + "call-bind-apply-helpers": "^1.0.2", 834 + "get-intrinsic": "^1.3.0" 835 + }, 836 + "engines": { 837 + "node": ">= 0.4" 838 + }, 839 + "funding": { 840 + "url": "https://github.com/sponsors/ljharb" 841 + } 842 + }, 843 + "node_modules/cborg": { 844 + "version": "4.5.8", 845 + "license": "Apache-2.0", 846 + "bin": { 847 + "cborg": "lib/bin.js" 848 + } 849 + }, 850 + "node_modules/clean-git-ref": { 851 + "version": "2.0.1", 852 + "license": "Apache-2.0" 853 + }, 854 + "node_modules/commander": { 855 + "version": "13.1.0", 856 + "license": "MIT", 857 + "engines": { 858 + "node": ">=18" 859 + } 860 + }, 861 + "node_modules/core-js": { 862 + "version": "3.48.0", 863 + "hasInstallScript": true, 864 + "license": "MIT", 865 + "funding": { 866 + "type": "opencollective", 867 + "url": "https://opencollective.com/core-js" 868 + } 869 + }, 870 + "node_modules/crc-32": { 871 + "version": "1.2.2", 872 + "license": "Apache-2.0", 873 + "bin": { 874 + "crc32": "bin/crc32.njs" 875 + }, 876 + "engines": { 877 + "node": ">=0.8" 878 + } 879 + }, 880 + "node_modules/decompress-response": { 881 + "version": "6.0.0", 882 + "license": "MIT", 883 + "dependencies": { 884 + "mimic-response": "^3.1.0" 885 + }, 886 + "engines": { 887 + "node": ">=10" 888 + }, 889 + "funding": { 890 + "url": "https://github.com/sponsors/sindresorhus" 891 + } 892 + }, 893 + "node_modules/define-data-property": { 894 + "version": "1.1.4", 895 + "license": "MIT", 896 + "dependencies": { 897 + "es-define-property": "^1.0.0", 898 + "es-errors": "^1.3.0", 899 + "gopd": "^1.0.1" 900 + }, 901 + "engines": { 902 + "node": ">= 0.4" 903 + }, 904 + "funding": { 905 + "url": "https://github.com/sponsors/ljharb" 906 + } 907 + }, 908 + "node_modules/diff3": { 909 + "version": "0.0.3", 910 + "license": "MIT" 911 + }, 912 + "node_modules/dunder-proto": { 913 + "version": "1.0.1", 914 + "license": "MIT", 915 + "dependencies": { 916 + "call-bind-apply-helpers": "^1.0.1", 917 + "es-errors": "^1.3.0", 918 + "gopd": "^1.2.0" 919 + }, 920 + "engines": { 921 + "node": ">= 0.4" 922 + } 923 + }, 924 + "node_modules/env-paths": { 925 + "version": "4.0.0", 926 + "license": "MIT", 927 + "dependencies": { 928 + "is-safe-filename": "^0.1.0" 929 + }, 930 + "engines": { 931 + "node": ">=20" 932 + }, 933 + "funding": { 934 + "url": "https://github.com/sponsors/sindresorhus" 935 + } 936 + }, 937 + "node_modules/es-define-property": { 938 + "version": "1.0.1", 939 + "license": "MIT", 940 + "engines": { 941 + "node": ">= 0.4" 942 + } 943 + }, 944 + "node_modules/es-errors": { 945 + "version": "1.3.0", 946 + "license": "MIT", 947 + "engines": { 948 + "node": ">= 0.4" 949 + } 950 + }, 951 + "node_modules/es-object-atoms": { 952 + "version": "1.1.1", 953 + "license": "MIT", 954 + "dependencies": { 955 + "es-errors": "^1.3.0" 956 + }, 957 + "engines": { 958 + "node": ">= 0.4" 959 + } 960 + }, 961 + "node_modules/event-target-shim": { 962 + "version": "5.0.1", 963 + "license": "MIT", 964 + "engines": { 965 + "node": ">=6" 966 + } 967 + }, 968 + "node_modules/events": { 969 + "version": "3.3.0", 970 + "license": "MIT", 971 + "engines": { 972 + "node": ">=0.8.x" 973 + } 974 + }, 975 + "node_modules/for-each": { 976 + "version": "0.3.5", 977 + "license": "MIT", 978 + "dependencies": { 979 + "is-callable": "^1.2.7" 980 + }, 981 + "engines": { 982 + "node": ">= 0.4" 983 + }, 984 + "funding": { 985 + "url": "https://github.com/sponsors/ljharb" 986 + } 987 + }, 988 + "node_modules/function-bind": { 989 + "version": "1.1.2", 990 + "license": "MIT", 991 + "funding": { 992 + "url": "https://github.com/sponsors/ljharb" 993 + } 994 + }, 995 + "node_modules/get-intrinsic": { 996 + "version": "1.3.0", 997 + "license": "MIT", 998 + "dependencies": { 999 + "call-bind-apply-helpers": "^1.0.2", 1000 + "es-define-property": "^1.0.1", 1001 + "es-errors": "^1.3.0", 1002 + "es-object-atoms": "^1.1.1", 1003 + "function-bind": "^1.1.2", 1004 + "get-proto": "^1.0.1", 1005 + "gopd": "^1.2.0", 1006 + "has-symbols": "^1.1.0", 1007 + "hasown": "^2.0.2", 1008 + "math-intrinsics": "^1.1.0" 1009 + }, 1010 + "engines": { 1011 + "node": ">= 0.4" 1012 + }, 1013 + "funding": { 1014 + "url": "https://github.com/sponsors/ljharb" 1015 + } 1016 + }, 1017 + "node_modules/get-proto": { 1018 + "version": "1.0.1", 1019 + "license": "MIT", 1020 + "dependencies": { 1021 + "dunder-proto": "^1.0.1", 1022 + "es-object-atoms": "^1.0.0" 1023 + }, 1024 + "engines": { 1025 + "node": ">= 0.4" 1026 + } 1027 + }, 1028 + "node_modules/glob-to-regex.js": { 1029 + "version": "1.2.0", 1030 + "license": "Apache-2.0", 1031 + "engines": { 1032 + "node": ">=10.0" 1033 + }, 1034 + "funding": { 1035 + "type": "github", 1036 + "url": "https://github.com/sponsors/streamich" 1037 + }, 1038 + "peerDependencies": { 1039 + "tslib": "2" 1040 + } 1041 + }, 1042 + "node_modules/gopd": { 1043 + "version": "1.2.0", 1044 + "license": "MIT", 1045 + "engines": { 1046 + "node": ">= 0.4" 1047 + }, 1048 + "funding": { 1049 + "url": "https://github.com/sponsors/ljharb" 1050 + } 1051 + }, 1052 + "node_modules/has-property-descriptors": { 1053 + "version": "1.0.2", 1054 + "license": "MIT", 1055 + "dependencies": { 1056 + "es-define-property": "^1.0.0" 1057 + }, 1058 + "funding": { 1059 + "url": "https://github.com/sponsors/ljharb" 1060 + } 1061 + }, 1062 + "node_modules/has-symbols": { 1063 + "version": "1.1.0", 1064 + "license": "MIT", 1065 + "engines": { 1066 + "node": ">= 0.4" 1067 + }, 1068 + "funding": { 1069 + "url": "https://github.com/sponsors/ljharb" 1070 + } 1071 + }, 1072 + "node_modules/has-tostringtag": { 1073 + "version": "1.0.2", 1074 + "license": "MIT", 1075 + "dependencies": { 1076 + "has-symbols": "^1.0.3" 1077 + }, 1078 + "engines": { 1079 + "node": ">= 0.4" 1080 + }, 1081 + "funding": { 1082 + "url": "https://github.com/sponsors/ljharb" 1083 + } 1084 + }, 1085 + "node_modules/hasown": { 1086 + "version": "2.0.2", 1087 + "license": "MIT", 1088 + "dependencies": { 1089 + "function-bind": "^1.1.2" 1090 + }, 1091 + "engines": { 1092 + "node": ">= 0.4" 1093 + } 1094 + }, 1095 + "node_modules/hyperdyperid": { 1096 + "version": "1.2.0", 1097 + "license": "MIT", 1098 + "engines": { 1099 + "node": ">=10.18" 1100 + } 1101 + }, 1102 + "node_modules/ieee754": { 1103 + "version": "1.2.1", 1104 + "funding": [ 1105 + { 1106 + "type": "github", 1107 + "url": "https://github.com/sponsors/feross" 1108 + }, 1109 + { 1110 + "type": "patreon", 1111 + "url": "https://www.patreon.com/feross" 1112 + }, 1113 + { 1114 + "type": "consulting", 1115 + "url": "https://feross.org/support" 1116 + } 1117 + ], 1118 + "license": "BSD-3-Clause" 1119 + }, 1120 + "node_modules/ignore": { 1121 + "version": "5.3.2", 1122 + "license": "MIT", 1123 + "engines": { 1124 + "node": ">= 4" 1125 + } 1126 + }, 1127 + "node_modules/inherits": { 1128 + "version": "2.0.4", 1129 + "license": "ISC" 1130 + }, 1131 + "node_modules/ipaddr.js": { 1132 + "version": "2.3.0", 1133 + "license": "MIT", 1134 + "engines": { 1135 + "node": ">= 10" 1136 + } 1137 + }, 1138 + "node_modules/is-callable": { 1139 + "version": "1.2.7", 1140 + "license": "MIT", 1141 + "engines": { 1142 + "node": ">= 0.4" 1143 + }, 1144 + "funding": { 1145 + "url": "https://github.com/sponsors/ljharb" 1146 + } 1147 + }, 1148 + "node_modules/is-safe-filename": { 1149 + "version": "0.1.1", 1150 + "license": "MIT", 1151 + "engines": { 1152 + "node": ">=20" 1153 + }, 1154 + "funding": { 1155 + "url": "https://github.com/sponsors/sindresorhus" 1156 + } 1157 + }, 1158 + "node_modules/is-typed-array": { 1159 + "version": "1.1.15", 1160 + "license": "MIT", 1161 + "dependencies": { 1162 + "which-typed-array": "^1.1.16" 1163 + }, 1164 + "engines": { 1165 + "node": ">= 0.4" 1166 + }, 1167 + "funding": { 1168 + "url": "https://github.com/sponsors/ljharb" 1169 + } 1170 + }, 1171 + "node_modules/isarray": { 1172 + "version": "2.0.5", 1173 + "license": "MIT" 1174 + }, 1175 + "node_modules/iso-datestring-validator": { 1176 + "version": "2.2.2", 1177 + "license": "MIT" 1178 + }, 1179 + "node_modules/isomorphic-git": { 1180 + "version": "1.37.0", 1181 + "license": "MIT", 1182 + "dependencies": { 1183 + "async-lock": "^1.4.1", 1184 + "clean-git-ref": "^2.0.1", 1185 + "crc-32": "^1.2.0", 1186 + "diff3": "0.0.3", 1187 + "ignore": "^5.1.4", 1188 + "minimisted": "^2.0.0", 1189 + "pako": "^1.0.10", 1190 + "pify": "^4.0.1", 1191 + "readable-stream": "^4.0.0", 1192 + "sha.js": "^2.4.12", 1193 + "simple-get": "^4.0.1" 1194 + }, 1195 + "bin": { 1196 + "isogit": "cli.cjs" 1197 + }, 1198 + "engines": { 1199 + "node": ">=14.17" 1200 + } 1201 + }, 1202 + "node_modules/jose": { 1203 + "version": "5.10.0", 1204 + "license": "MIT", 1205 + "funding": { 1206 + "url": "https://github.com/sponsors/panva" 1207 + } 1208 + }, 1209 + "node_modules/lru-cache": { 1210 + "version": "10.4.3", 1211 + "license": "ISC" 1212 + }, 1213 + "node_modules/math-intrinsics": { 1214 + "version": "1.1.0", 1215 + "license": "MIT", 1216 + "engines": { 1217 + "node": ">= 0.4" 1218 + } 1219 + }, 1220 + "node_modules/memfs": { 1221 + "version": "4.56.10", 1222 + "license": "Apache-2.0", 1223 + "dependencies": { 1224 + "@jsonjoy.com/fs-core": "4.56.10", 1225 + "@jsonjoy.com/fs-fsa": "4.56.10", 1226 + "@jsonjoy.com/fs-node": "4.56.10", 1227 + "@jsonjoy.com/fs-node-builtins": "4.56.10", 1228 + "@jsonjoy.com/fs-node-to-fsa": "4.56.10", 1229 + "@jsonjoy.com/fs-node-utils": "4.56.10", 1230 + "@jsonjoy.com/fs-print": "4.56.10", 1231 + "@jsonjoy.com/fs-snapshot": "4.56.10", 1232 + "@jsonjoy.com/json-pack": "^1.11.0", 1233 + "@jsonjoy.com/util": "^1.9.0", 1234 + "glob-to-regex.js": "^1.0.1", 1235 + "thingies": "^2.5.0", 1236 + "tree-dump": "^1.0.3", 1237 + "tslib": "^2.0.0" 1238 + }, 1239 + "funding": { 1240 + "type": "github", 1241 + "url": "https://github.com/sponsors/streamich" 1242 + }, 1243 + "peerDependencies": { 1244 + "tslib": "2" 1245 + } 1246 + }, 1247 + "node_modules/mimic-response": { 1248 + "version": "3.1.0", 1249 + "license": "MIT", 1250 + "engines": { 1251 + "node": ">=10" 1252 + }, 1253 + "funding": { 1254 + "url": "https://github.com/sponsors/sindresorhus" 1255 + } 1256 + }, 1257 + "node_modules/minimist": { 1258 + "version": "1.2.8", 1259 + "license": "MIT", 1260 + "funding": { 1261 + "url": "https://github.com/sponsors/ljharb" 1262 + } 1263 + }, 1264 + "node_modules/minimisted": { 1265 + "version": "2.0.1", 1266 + "license": "MIT", 1267 + "dependencies": { 1268 + "minimist": "^1.2.5" 1269 + } 1270 + }, 1271 + "node_modules/multiformats": { 1272 + "version": "9.9.0", 1273 + "license": "(Apache-2.0 AND MIT)" 1274 + }, 1275 + "node_modules/once": { 1276 + "version": "1.4.0", 1277 + "license": "ISC", 1278 + "dependencies": { 1279 + "wrappy": "1" 1280 + } 1281 + }, 1282 + "node_modules/pako": { 1283 + "version": "1.0.11", 1284 + "license": "(MIT AND Zlib)" 1285 + }, 1286 + "node_modules/pify": { 1287 + "version": "4.0.1", 1288 + "license": "MIT", 1289 + "engines": { 1290 + "node": ">=6" 1291 + } 1292 + }, 1293 + "node_modules/possible-typed-array-names": { 1294 + "version": "1.1.0", 1295 + "license": "MIT", 1296 + "engines": { 1297 + "node": ">= 0.4" 1298 + } 1299 + }, 1300 + "node_modules/process": { 1301 + "version": "0.11.10", 1302 + "license": "MIT", 1303 + "engines": { 1304 + "node": ">= 0.6.0" 1305 + } 1306 + }, 1307 + "node_modules/readable-stream": { 1308 + "version": "4.7.0", 1309 + "license": "MIT", 1310 + "dependencies": { 1311 + "abort-controller": "^3.0.0", 1312 + "buffer": "^6.0.3", 1313 + "events": "^3.3.0", 1314 + "process": "^0.11.10", 1315 + "string_decoder": "^1.3.0" 1316 + }, 1317 + "engines": { 1318 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1319 + } 1320 + }, 1321 + "node_modules/safe-buffer": { 1322 + "version": "5.2.1", 1323 + "funding": [ 1324 + { 1325 + "type": "github", 1326 + "url": "https://github.com/sponsors/feross" 1327 + }, 1328 + { 1329 + "type": "patreon", 1330 + "url": "https://www.patreon.com/feross" 1331 + }, 1332 + { 1333 + "type": "consulting", 1334 + "url": "https://feross.org/support" 1335 + } 1336 + ], 1337 + "license": "MIT" 1338 + }, 1339 + "node_modules/set-function-length": { 1340 + "version": "1.2.2", 1341 + "license": "MIT", 1342 + "dependencies": { 1343 + "define-data-property": "^1.1.4", 1344 + "es-errors": "^1.3.0", 1345 + "function-bind": "^1.1.2", 1346 + "get-intrinsic": "^1.2.4", 1347 + "gopd": "^1.0.1", 1348 + "has-property-descriptors": "^1.0.2" 1349 + }, 1350 + "engines": { 1351 + "node": ">= 0.4" 1352 + } 1353 + }, 1354 + "node_modules/sha.js": { 1355 + "version": "2.4.12", 1356 + "license": "(MIT AND BSD-3-Clause)", 1357 + "dependencies": { 1358 + "inherits": "^2.0.4", 1359 + "safe-buffer": "^5.2.1", 1360 + "to-buffer": "^1.2.0" 1361 + }, 1362 + "bin": { 1363 + "sha.js": "bin.js" 1364 + }, 1365 + "engines": { 1366 + "node": ">= 0.10" 1367 + }, 1368 + "funding": { 1369 + "url": "https://github.com/sponsors/ljharb" 1370 + } 1371 + }, 1372 + "node_modules/simple-concat": { 1373 + "version": "1.0.1", 1374 + "funding": [ 1375 + { 1376 + "type": "github", 1377 + "url": "https://github.com/sponsors/feross" 1378 + }, 1379 + { 1380 + "type": "patreon", 1381 + "url": "https://www.patreon.com/feross" 1382 + }, 1383 + { 1384 + "type": "consulting", 1385 + "url": "https://feross.org/support" 1386 + } 1387 + ], 1388 + "license": "MIT" 1389 + }, 1390 + "node_modules/simple-get": { 1391 + "version": "4.0.1", 1392 + "funding": [ 1393 + { 1394 + "type": "github", 1395 + "url": "https://github.com/sponsors/feross" 1396 + }, 1397 + { 1398 + "type": "patreon", 1399 + "url": "https://www.patreon.com/feross" 1400 + }, 1401 + { 1402 + "type": "consulting", 1403 + "url": "https://feross.org/support" 1404 + } 1405 + ], 1406 + "license": "MIT", 1407 + "dependencies": { 1408 + "decompress-response": "^6.0.0", 1409 + "once": "^1.3.1", 1410 + "simple-concat": "^1.0.0" 1411 + } 1412 + }, 1413 + "node_modules/string_decoder": { 1414 + "version": "1.3.0", 1415 + "license": "MIT", 1416 + "dependencies": { 1417 + "safe-buffer": "~5.2.0" 1418 + } 1419 + }, 1420 + "node_modules/thingies": { 1421 + "version": "2.5.0", 1422 + "license": "MIT", 1423 + "engines": { 1424 + "node": ">=10.18" 1425 + }, 1426 + "funding": { 1427 + "type": "github", 1428 + "url": "https://github.com/sponsors/streamich" 1429 + }, 1430 + "peerDependencies": { 1431 + "tslib": "^2" 1432 + } 1433 + }, 1434 + "node_modules/tlds": { 1435 + "version": "1.261.0", 1436 + "license": "MIT", 1437 + "bin": { 1438 + "tlds": "bin.js" 1439 + } 1440 + }, 1441 + "node_modules/to-buffer": { 1442 + "version": "1.2.2", 1443 + "license": "MIT", 1444 + "dependencies": { 1445 + "isarray": "^2.0.5", 1446 + "safe-buffer": "^5.2.1", 1447 + "typed-array-buffer": "^1.0.3" 1448 + }, 1449 + "engines": { 1450 + "node": ">= 0.4" 1451 + } 1452 + }, 1453 + "node_modules/tree-dump": { 1454 + "version": "1.1.0", 1455 + "license": "Apache-2.0", 1456 + "engines": { 1457 + "node": ">=10.0" 1458 + }, 1459 + "funding": { 1460 + "type": "github", 1461 + "url": "https://github.com/sponsors/streamich" 1462 + }, 1463 + "peerDependencies": { 1464 + "tslib": "2" 1465 + } 1466 + }, 1467 + "node_modules/tslib": { 1468 + "version": "2.8.1", 1469 + "license": "0BSD" 1470 + }, 1471 + "node_modules/typed-array-buffer": { 1472 + "version": "1.0.3", 1473 + "license": "MIT", 1474 + "dependencies": { 1475 + "call-bound": "^1.0.3", 1476 + "es-errors": "^1.3.0", 1477 + "is-typed-array": "^1.1.14" 1478 + }, 1479 + "engines": { 1480 + "node": ">= 0.4" 1481 + } 1482 + }, 1483 + "node_modules/uint8arrays": { 1484 + "version": "3.0.0", 1485 + "license": "MIT", 1486 + "dependencies": { 1487 + "multiformats": "^9.4.2" 1488 + } 1489 + }, 1490 + "node_modules/uint8arrays/node_modules/multiformats": { 1491 + "version": "9.9.0", 1492 + "license": "(Apache-2.0 AND MIT)" 1493 + }, 1494 + "node_modules/undici": { 1495 + "version": "6.23.0", 1496 + "license": "MIT", 1497 + "engines": { 1498 + "node": ">=18.17" 1499 + } 1500 + }, 1501 + "node_modules/unicode-segmenter": { 1502 + "version": "0.14.5", 1503 + "license": "MIT" 1504 + }, 1505 + "node_modules/which-typed-array": { 1506 + "version": "1.1.20", 1507 + "license": "MIT", 1508 + "dependencies": { 1509 + "available-typed-arrays": "^1.0.7", 1510 + "call-bind": "^1.0.8", 1511 + "call-bound": "^1.0.4", 1512 + "for-each": "^0.3.5", 1513 + "get-proto": "^1.0.1", 1514 + "gopd": "^1.2.0", 1515 + "has-tostringtag": "^1.0.2" 1516 + }, 1517 + "engines": { 1518 + "node": ">= 0.4" 1519 + }, 1520 + "funding": { 1521 + "url": "https://github.com/sponsors/ljharb" 1522 + } 1523 + }, 1524 + "node_modules/wrappy": { 1525 + "version": "1.0.2", 1526 + "license": "ISC" 1527 + }, 1528 + "node_modules/zod": { 1529 + "version": "3.25.76", 1530 + "license": "MIT", 1531 + "funding": { 1532 + "url": "https://github.com/sponsors/colinhacks" 1533 + } 1534 + } 1535 + } 1536 + }
+3
package.json
··· 11 11 "src/" 12 12 ], 13 13 "type": "module", 14 + "engines": { 15 + "node": ">=20.0.0" 16 + }, 14 17 "dependencies": { 15 18 "@atproto/api": "^0.18.20", 16 19 "@atproto/common-web": "^0.4.16",
+2 -1
src/cli.js
··· 2 2 // Copyright (c) 2026 sol pbc 3 3 4 4 import { Command } from 'commander'; 5 + import { brand } from './lib/brand.js'; 5 6 import registerAdopt from './cmd/adopt.js'; 6 7 import registerBeacon from './cmd/beacon.js'; 7 8 import registerConfig from './cmd/config.js'; ··· 20 21 const program = new Command(); 21 22 program 22 23 .name('vit') 23 - .description('Social toolkit for personalized software') 24 + .description(`${brand} \u2014 social open source`) 24 25 .version('0.1.0'); 25 26 26 27 registerAdopt(program);
+2 -1
src/cmd/adopt.js
··· 6 6 import { execFileSync } from 'node:child_process'; 7 7 import { parseGitUrl, toBeacon, beaconToHttps } from '../lib/beacon.js'; 8 8 import { requireNotAgent } from '../lib/agent.js'; 9 + import { which } from '../lib/compat.js'; 9 10 10 11 export default function register(program) { 11 12 program ··· 46 47 } 47 48 48 49 // detect gh + github host 49 - const ghPath = Bun.which('gh'); 50 + const ghPath = which('gh'); 50 51 const isGitHub = parsed.host === 'github.com'; 51 52 if (verbose) console.log(`[verbose] gh available: ${ghPath ? 'yes' : 'no'}, github host: ${isGitHub ? 'yes' : 'no'}`); 52 53
+3 -2
src/cmd/beacon.js
··· 5 5 import http from 'isomorphic-git/http/node'; 6 6 import { memfs } from 'memfs'; 7 7 import { beaconToHttps } from '../lib/beacon.js'; 8 + import { mark } from '../lib/brand.js'; 8 9 9 10 async function readTreeFile(fs, dir, treeOid, pathParts) { 10 11 for (let i = 0; i < pathParts.length; i++) { ··· 49 50 } catch {} 50 51 51 52 if (beacon) { 52 - console.log('beacon: lit ' + beacon); 53 + console.log(`${mark} beacon: lit ${beacon}`); 53 54 } else { 54 - console.log('beacon: unlit'); 55 + console.log(`${mark} beacon: unlit`); 55 56 } 56 57 } catch (err) { 57 58 console.error(err instanceof Error ? err.message : String(err));
+7 -6
src/cmd/doctor.js
··· 5 5 import { readProjectConfig } from '../lib/vit-dir.js'; 6 6 import { existsSync } from 'node:fs'; 7 7 import { join } from 'node:path'; 8 + import { mark, brand } from '../lib/brand.js'; 8 9 9 10 export default function register(program) { 10 11 program ··· 15 16 const config = loadConfig(); 16 17 if (config.setup_at) { 17 18 const when = new Date(config.setup_at * 1000).toISOString(); 18 - console.log(`setup: ok (${when})`); 19 + console.log(`${mark} setup: ok (${when})`); 19 20 } else { 20 - console.log('setup: not done (run vit setup)'); 21 + console.log(`${mark} setup: not done (run ${brand} setup)`); 21 22 } 22 23 23 24 const projConfig = readProjectConfig(); 24 25 if (projConfig.beacon) { 25 - console.log(`beacon: ${projConfig.beacon}`); 26 + console.log(`${mark} beacon: ${projConfig.beacon}`); 26 27 } else { 27 - console.log('beacon: not set'); 28 + console.log(`${mark} beacon: not set`); 28 29 } 29 30 30 31 const skillPath = join(process.cwd(), '.claude', 'skills', 'using-vit', 'SKILL.md'); 31 32 if (existsSync(skillPath)) { 32 - console.log('skill: ok (using-vit)'); 33 + console.log(`${mark} skill: ok (using-vit)`); 33 34 } else { 34 - console.log('skill: not installed (run vit setup)'); 35 + console.log(`${mark} skill: not installed (run ${brand} setup)`); 35 36 } 36 37 } catch (err) { 37 38 console.error(err instanceof Error ? err.message : String(err));
+2 -1
src/cmd/firehose.js
··· 4 4 import { loadConfig } from '../lib/config.js'; 5 5 import { CAP_COLLECTION } from '../lib/constants.js'; 6 6 import { resolveRef } from '../lib/cap-ref.js'; 7 + import { brand } from '../lib/brand.js'; 7 8 8 9 const JETSTREAM_URL = 'wss://jetstream2.us-east.bsky.network/subscribe'; 9 10 ··· 132 133 } 133 134 134 135 const url = buildUrl(opts.collection, opts.did, null); 135 - console.log('Jetstream Firehose Listener'); 136 + console.log(`${brand} firehose`); 136 137 console.log(` Collection: ${opts.collection}`); 137 138 if (opts.did) console.log(` DID filter: ${opts.did}`); 138 139 console.log(` Endpoint: ${url}`);
+18 -11
src/cmd/init.js
··· 1 1 // SPDX-License-Identifier: AGPL-3.0-only 2 2 // Copyright (c) 2026 sol pbc 3 3 4 - import { existsSync } from 'node:fs'; 4 + import { existsSync, writeFileSync } from 'node:fs'; 5 5 import { execSync } from 'node:child_process'; 6 + import { join } from 'node:path'; 6 7 import { toBeacon } from '../lib/beacon.js'; 7 8 import { vitDir, readProjectConfig, writeProjectConfig } from '../lib/vit-dir.js'; 8 9 import { requireAgent } from '../lib/agent.js'; 10 + import { mark, brand, DOT_VIT_README } from '../lib/brand.js'; 9 11 10 12 export default function register(program) { 11 13 program ··· 17 19 try { 18 20 const gate = requireAgent(); 19 21 if (!gate.ok) { 20 - console.error('vit init should be run by a coding agent (e.g. claude code, gemini cli).'); 21 - console.error("open your agent and ask it to run 'vit init' for you."); 22 + console.error(`${brand} init should be run by a coding agent (e.g. claude code, gemini cli).`); 23 + console.error(`open your agent and ask it to run '${brand} init' for you.`); 22 24 process.exitCode = 1; 23 25 return; 24 26 } ··· 30 32 if (!opts.beacon) { 31 33 const config = readProjectConfig(); 32 34 if (config.beacon) { 33 - console.log(`beacon: ${config.beacon}`); 34 - console.log('hint: to change the beacon, run: vit init --beacon <git-url>'); 35 + console.log(`${mark} beacon: ${config.beacon}`); 36 + console.log(`hint: to change the beacon, run: ${brand} init --beacon <git-url>`); 35 37 return; 36 38 } 37 39 ··· 50 52 console.log(hasVitDir ? 'status: no beacon' : 'status: not initialized'); 51 53 console.log('git: false'); 52 54 if (hasVitDir) { 53 - console.log('hint: run: vit init --beacon <canonical-git-url>'); 55 + console.log(`hint: run: ${brand} init --beacon <canonical-git-url>`); 54 56 } else { 55 - console.log('hint: run vit init from inside a git repository.'); 57 + console.log(`hint: run ${brand} init from inside a git repository.`); 56 58 } 57 59 return; 58 60 } ··· 97 99 const origin = remotes.find(remote => remote.name === 'origin'); 98 100 if (upstream) { 99 101 console.log('hint: detected upstream remote. upstream points to the canonical repo.'); 100 - console.log(`hint: run: vit init --beacon ${upstream.url}`); 102 + console.log(`hint: run: ${brand} init --beacon ${upstream.url}`); 101 103 } else if (origin) { 102 - console.log(`hint: run: vit init --beacon ${origin.url}`); 104 + console.log(`hint: run: ${brand} init --beacon ${origin.url}`); 103 105 } else { 104 - console.log('hint: no git remotes found. run: vit init --beacon <canonical-git-url>'); 106 + console.log(`hint: no git remotes found. run: ${brand} init --beacon <canonical-git-url>`); 105 107 } 106 108 return; 107 109 } ··· 144 146 if (verbose) console.log(`[verbose] Computed beacon: ${beacon}`); 145 147 writeProjectConfig({ beacon }); 146 148 if (verbose) console.log(`[verbose] Wrote config.json`); 147 - console.log(`beacon: ${beacon}`); 149 + const readmePath = join(vitDir(), 'README.md'); 150 + if (!existsSync(readmePath)) { 151 + writeFileSync(readmePath, DOT_VIT_README); 152 + if (verbose) console.log(`[verbose] Wrote .vit/README.md`); 153 + } 154 + console.log(`${mark} beacon: ${beacon}`); 148 155 } catch (err) { 149 156 console.error(err instanceof Error ? err.message : String(err)); 150 157 process.exitCode = 1;
+24 -26
src/cmd/login.js
··· 1 1 // SPDX-License-Identifier: AGPL-3.0-only 2 2 // Copyright (c) 2026 sol pbc 3 3 4 + import { createServer } from 'node:http'; 5 + import { spawn } from 'node:child_process'; 4 6 import { loadConfig, saveConfig } from '../lib/config.js'; 5 7 import { createOAuthClient, createSessionStore, createStore } from '../lib/oauth.js'; 6 8 ··· 36 38 resolveCallback = resolve; 37 39 }); 38 40 39 - server = Bun.serve({ 40 - hostname: '127.0.0.1', 41 - port: 0, 42 - fetch(req) { 43 - const url = new URL(req.url); 41 + server = createServer((req, res) => { 42 + const url = new URL(req.url, `http://127.0.0.1`); 44 43 45 - if (req.method === 'GET' && url.pathname === '/callback') { 46 - const params = new URLSearchParams(url.searchParams); 44 + if (req.method === 'GET' && url.pathname === '/callback') { 45 + const params = new URLSearchParams(url.searchParams); 47 46 48 - if (!callbackResolved) { 49 - callbackResolved = true; 50 - resolveCallback(params); 51 - } 52 - 53 - return new Response( 54 - '<!doctype html><html><body><h2>Authorization complete, you can close this tab.</h2></body></html>', 55 - { 56 - headers: { 'content-type': 'text/html; charset=utf-8' }, 57 - }, 58 - ); 47 + if (!callbackResolved) { 48 + callbackResolved = true; 49 + resolveCallback(params); 59 50 } 60 51 61 - return new Response('Not found', { status: 404 }); 62 - }, 52 + res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }); 53 + res.end('<!doctype html><html><body><h2>Authorization complete, you can close this tab.</h2></body></html>'); 54 + return; 55 + } 56 + 57 + res.writeHead(404); 58 + res.end('Not found'); 63 59 }); 64 60 61 + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); 62 + const port = server.address().port; 63 + 65 64 if (verbose) { 66 - console.log(`[verbose] Server started on port ${server.port}`); 65 + console.log(`[verbose] Server started on port ${port}`); 67 66 } 68 67 69 - const redirectUri = `http://127.0.0.1:${server.port}/callback`; 68 + const redirectUri = `http://127.0.0.1:${port}/callback`; 70 69 71 70 if (verbose) { 72 71 console.log(`[verbose] Redirect URI: ${redirectUri}`); ··· 89 88 const args = platform === 'win32' ? ['/c', 'start', authUrl.toString()] : [authUrl.toString()]; 90 89 91 90 try { 92 - Bun.spawn([cmd, ...args], { 93 - stdio: ['ignore', 'ignore', 'ignore'], 94 - }); 91 + const child = spawn(cmd, args, { stdio: 'ignore', detached: true }); 92 + child.unref(); 95 93 } catch { 96 94 // Ignore browser-open failures and rely on printed URL. 97 95 } ··· 144 142 } 145 143 146 144 if (server) { 147 - server.stop(true); 145 + server.close(); 148 146 } 149 147 } 150 148 });
+23 -23
src/cmd/setup.js
··· 1 1 // SPDX-License-Identifier: AGPL-3.0-only 2 2 // Copyright (c) 2026 sol pbc 3 3 4 + import { spawnSync } from 'node:child_process'; 4 5 import { loadConfig, saveConfig } from '../lib/config.js'; 5 6 import { requireNotAgent } from '../lib/agent.js'; 7 + import { which } from '../lib/compat.js'; 8 + import { mark, brand } from '../lib/brand.js'; 6 9 7 10 export default function register(program) { 8 11 program ··· 12 15 try { 13 16 const gate = requireNotAgent(); 14 17 if (!gate.ok) { 15 - console.error('vit setup must be run by a human. run it in your own terminal.'); 18 + console.error(`${brand} setup must be run by a human. run it in your own terminal.`); 16 19 process.exitCode = 1; 17 20 return; 18 21 } 19 22 20 - const gitPath = Bun.which('git'); 21 - const bunPath = Bun.which('bun'); 22 - console.log(`git: ${gitPath ? 'found' : 'not found'}`); 23 - console.log(`bun: ${bunPath ? 'found' : 'not found'}`); 24 - if (!gitPath || !bunPath) { 25 - const missing = [!gitPath ? 'git' : null, !bunPath ? 'bun' : null].filter(Boolean).join(', '); 26 - console.error(`missing required tools: ${missing}`); 23 + const gitPath = which('git'); 24 + console.log(`${mark} git: ${gitPath ? 'found' : 'not found'}`); 25 + if (!gitPath) { 26 + console.error('missing required tool: git'); 27 27 process.exitCode = 1; 28 28 return; 29 29 } 30 30 31 31 // skill installation 32 - const npxPath = Bun.which('npx'); 32 + const npxPath = which('npx'); 33 33 if (npxPath) { 34 34 try { 35 - const result = Bun.spawnSync( 36 - ['npx', 'skills', 'add', 'https://github.com/solpbc/vit/tree/main/skills/vit', '-a', 'claude-code', '-y'], 35 + const result = spawnSync( 36 + 'npx', ['skills', 'add', 'https://github.com/solpbc/vit/tree/main/skills/vit', '-a', 'claude-code', '-y'], 37 37 { 38 - stdout: 'pipe', 39 - stderr: 'pipe', 38 + encoding: 'utf-8', 39 + stdio: ['pipe', 'pipe', 'pipe'], 40 40 } 41 41 ); 42 - if (result.exitCode === 0) { 43 - console.log('skill: installed (using-vit)'); 42 + if (result.status === 0) { 43 + console.log(`${mark} skill: installed (using-vit)`); 44 44 } else { 45 - const errText = result.stderr.toString().trim(); 46 - console.log(`skill: failed (${errText || 'unknown error'})`); 45 + const errText = (result.stderr || '').trim(); 46 + console.log(`${mark} skill: failed (${errText || 'unknown error'})`); 47 47 } 48 48 } catch { 49 - console.log('skill: failed (could not run npx skills)'); 49 + console.log(`${mark} skill: failed (could not run npx skills)`); 50 50 } 51 51 } else { 52 - console.log('skill: skipped (npx not found)'); 52 + console.log(`${mark} skill: skipped (npx not found)`); 53 53 } 54 54 55 55 const config = loadConfig(); 56 56 if (config.did) { 57 - console.log(`login: ${config.did}`); 57 + console.log(`${mark} login: ${config.did}`); 58 58 } else { 59 - console.log('login: not logged in'); 60 - console.log("next: run 'vit login <handle>' to authenticate with Bluesky"); 59 + console.log(`${mark} login: not logged in`); 60 + console.log(`next: run '${brand} login <handle>' to authenticate with Bluesky`); 61 61 } 62 62 63 63 if (!config.setup_at) { ··· 66 66 } 67 67 68 68 if (config.did) { 69 - console.log('vit setup complete'); 69 + console.log(`${brand} setup complete`); 70 70 } 71 71 } catch (err) { 72 72 console.error(err instanceof Error ? err.message : String(err));
+3 -2
src/cmd/ship.js
··· 9 9 import { restoreAgent } from '../lib/oauth.js'; 10 10 import { appendLog, readProjectConfig, readLog, readFollowing } from '../lib/vit-dir.js'; 11 11 import { REF_PATTERN, resolveRef } from '../lib/cap-ref.js'; 12 + import { brand } from '../lib/brand.js'; 12 13 13 14 export default function register(program) { 14 15 program ··· 24 25 try { 25 26 const gate = requireAgent(); 26 27 if (!gate.ok) { 27 - console.error('vit ship should be run by a coding agent (e.g. claude code, gemini cli).'); 28 - console.error("open your agent and ask it to run 'vit ship' for you."); 28 + console.error(`${brand} ship should be run by a coding agent (e.g. claude code, gemini cli).`); 29 + console.error(`open your agent and ask it to run '${brand} ship' for you.`); 29 30 process.exitCode = 1; 30 31 return; 31 32 }
+5 -4
src/cmd/skim.js
··· 7 7 import { readProjectConfig, readFollowing } from '../lib/vit-dir.js'; 8 8 import { requireAgent } from '../lib/agent.js'; 9 9 import { resolveRef } from '../lib/cap-ref.js'; 10 + import { brand } from '../lib/brand.js'; 10 11 11 12 export default function register(program) { 12 13 program ··· 21 22 try { 22 23 const gate = requireAgent(); 23 24 if (!gate.ok) { 24 - console.error('vit skim should be run by a coding agent (e.g. claude code, gemini cli).'); 25 - console.error("open your agent and ask it to run 'vit skim' for you."); 25 + console.error(`${brand} skim should be run by a coding agent (e.g. claude code, gemini cli).`); 26 + console.error(`open your agent and ask it to run '${brand} skim' for you.`); 26 27 process.exitCode = 1; 27 28 return; 28 29 } ··· 35 36 const projectConfig = readProjectConfig(); 36 37 const beacon = projectConfig.beacon; 37 38 if (!beacon) { 38 - console.error("no beacon set. run 'vit init' in a project directory first."); 39 + console.error(`no beacon set. run '${brand} init' in a project directory first.`); 39 40 process.exitCode = 1; 40 41 return; 41 42 } ··· 102 103 console.log(); 103 104 } 104 105 console.log('---'); 105 - console.log("hint: tell your user to run 'vit vet <ref>' in another terminal for any cap they want to review."); 106 + console.log(`hint: tell your user to run '${brand} vet <ref>' in another terminal for any cap they want to review.`); 106 107 } 107 108 } catch (err) { 108 109 console.error(err instanceof Error ? err.message : String(err));
+19
src/lib/brand.js
··· 1 + // SPDX-License-Identifier: AGPL-3.0-only 2 + // Copyright (c) 2026 sol pbc 3 + 4 + const VIT_MARK = 'v\u0307'; // v̇ 5 + const VIT_BRAND = `${VIT_MARK}it`; // v̇it 6 + 7 + const canCombine = process.stdout.isTTY && !process.env.TERM?.startsWith('dumb'); 8 + const brand = canCombine ? VIT_BRAND : 'vit'; 9 + const mark = canCombine ? VIT_MARK : 'v'; 10 + const prefix = canCombine ? `[${VIT_MARK}]` : '[v]'; 11 + 12 + const DOT_VIT_README = `# .${VIT_BRAND} 13 + 14 + this project participates in the social open source network. capabilities flow through people and agents you trust — not through gatekeepers or centralized platforms. the future of open source is social. 15 + 16 + learn more at [v-it.org](https://v-it.org) 17 + `; 18 + 19 + export { VIT_MARK, VIT_BRAND, brand, mark, prefix, DOT_VIT_README };
+20
src/lib/compat.js
··· 1 + // SPDX-License-Identifier: AGPL-3.0-only 2 + // Copyright (c) 2026 sol pbc 3 + 4 + import { execFileSync } from 'node:child_process'; 5 + 6 + /** 7 + * Find the full path of an executable (cross-runtime replacement for Bun.which). 8 + * Returns the path string or null if not found. 9 + */ 10 + export function which(cmd) { 11 + try { 12 + const bin = process.platform === 'win32' ? 'where' : 'which'; 13 + return execFileSync(bin, [cmd], { 14 + encoding: 'utf-8', 15 + stdio: ['pipe', 'pipe', 'pipe'], 16 + }).trim().split('\n')[0]; 17 + } catch { 18 + return null; 19 + } 20 + }
+1 -1
test/beacon-cmd.test.js
··· 8 8 test('probes a public repo without .vit/config.json beacon (unlit)', () => { 9 9 const result = run('beacon https://github.com/octocat/Hello-World.git'); 10 10 expect(result.exitCode).toBe(0); 11 - expect(result.stdout).toBe('beacon: unlit'); 11 + expect(result.stdout).toContain('beacon: unlit'); 12 12 }, 30000); 13 13 14 14 test('errors on invalid URL', () => {
+1 -2
test/setup.test.js
··· 11 11 expect(result.stderr).toContain('must be run by a human'); 12 12 }); 13 13 14 - test('checks for git and bun', () => { 14 + test('checks for git', () => { 15 15 const result = run('setup', undefined, { CLAUDECODE: '', GEMINI_CLI: '', CODEX_CI: '' }); 16 16 expect(result.stdout).toContain('git: found'); 17 - expect(result.stdout).toContain('bun: found'); 18 17 }); 19 18 20 19 test('reports login status', () => {