isomorphic-jj 1.7.0 → 1.9.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 CHANGED
@@ -1,11 +1,18 @@
1
- # isomorphic-jj
2
-
3
- [![npm version](https://img.shields.io/npm/v/isomorphic-jj.svg)](https://www.npmjs.com/package/isomorphic-jj)
4
- [![test coverage](https://img.shields.io/badge/tests-1701%20passing-brightgreen.svg)](https://github.com/johnhenry/isomorphic-jj)
5
- [![license](https://img.shields.io/npm/l/isomorphic-jj.svg)](LICENSE)
1
+ # @johnhenry/isomorphic-jj
6
2
 
7
3
  > **Jujutsu version control for JavaScript**—stable change IDs, fearless undo, and no staging area. Works in Node.js and browsers.
8
4
 
5
+ Full documentation: [opensource.johnhenry.me/isomorphic-jj](https://opensource.johnhenry.me/isomorphic-jj/)
6
+
7
+ > Previously published as `isomorphic-jj` (final release 1.8.0, deprecated in
8
+ > favor of this package). Renamed to `@johnhenry/isomorphic-jj` and restarted
9
+ > at 0.0.0 on import into the @johnhenry family — a new address and era, not
10
+ > a maturity signal.
11
+
12
+ [![npm version](https://img.shields.io/npm/v/%40johnhenry%2Fisomorphic-jj.svg)](https://www.npmjs.com/package/@johnhenry/isomorphic-jj)
13
+ [![CI](https://github.com/johnhenry/isomorphic-jj/actions/workflows/test.yml/badge.svg)](https://github.com/johnhenry/isomorphic-jj/actions/workflows/test.yml)
14
+ [![license](https://img.shields.io/npm/l/%40johnhenry%2Fisomorphic-jj.svg)](LICENSE)
15
+
9
16
  **What makes it different:**
10
17
  - 🎯 **Stable change IDs** that survive rebases/squashes
11
18
  - ↩️ **Complete undo** for any operation (not just commits)
@@ -14,7 +21,7 @@
14
21
  - 🌐 **True isomorphic**—same API in Node, browsers, and Web Workers
15
22
 
16
23
  ```javascript
17
- import { createJJ } from 'isomorphic-jj';
24
+ import { createJJ } from '@johnhenry/isomorphic-jj';
18
25
  import git from 'isomorphic-git';
19
26
  import fs from 'fs';
20
27
 
@@ -30,6 +37,83 @@ await jj.undo();
30
37
 
31
38
  ---
32
39
 
40
+ ## Contents
41
+
42
+ - [Try it in 60 seconds](#try-it-in-60-seconds)
43
+ - [Quick Start](#quick-start)
44
+ - [Examples](#examples)
45
+ - [What's New in v1.0](#whats-new-in-v10)
46
+ - [How is this Different?](#how-is-this-different)
47
+ - [Features](#features)
48
+ - [Use Cases](#use-cases)
49
+ - [API Reference](#api-reference)
50
+ - [Why isomorphic-jj?](#why-isomorphic-jj)
51
+ - [Architecture](#architecture)
52
+ - [Project Status](#project-status)
53
+ - [Installation & Environment](#installation--environment)
54
+ - [Security model](#security-model)
55
+ - [Contributing](#contributing)
56
+ - [FAQ](#faq)
57
+ - [Family](#family)
58
+ - [License](#license)
59
+ - [Acknowledgments](#acknowledgments)
60
+
61
+ ---
62
+
63
+ ## Try it in 60 seconds
64
+
65
+ ### CLI
66
+
67
+ Every method is reachable from the `isojj` CLI (`bin/isojj.js`). Run it with
68
+ `npx`, or install it globally (`npm i -g @johnhenry/isomorphic-jj`) and call
69
+ `isojj` directly:
70
+
71
+ ```bash
72
+ npx @johnhenry/isomorphic-jj init
73
+ echo "# hello" > README.md
74
+ npx @johnhenry/isomorphic-jj describe -m "Initial commit"
75
+ npx @johnhenry/isomorphic-jj new -m "Add a feature"
76
+ npx @johnhenry/isomorphic-jj log
77
+ ```
78
+
79
+ ```
80
+ Change History:
81
+
82
+ cb7b4e93fd23 Add a feature
83
+ You 9/2/2026, 7:20:30 AM
84
+
85
+ a2f6f5af8107 Initial commit
86
+ You 9/2/2026, 7:20:30 AM
87
+ ```
88
+
89
+ Run `npx @johnhenry/isomorphic-jj --help` for the full command list.
90
+
91
+ ### Node.js
92
+
93
+ ```javascript
94
+ import { createJJ } from '@johnhenry/isomorphic-jj';
95
+ import fs from 'fs';
96
+
97
+ const jj = await createJJ({ fs, dir: './my-repo' });
98
+ await jj.init({ userName: 'You', userEmail: 'you@example.com' });
99
+ await jj.write({ path: 'README.md', data: '# hello\n' });
100
+ await jj.describe({ message: 'Initial commit' });
101
+ console.log(await jj.log({ limit: 5 }));
102
+ ```
103
+
104
+ ### Browser
105
+
106
+ ```javascript
107
+ import { createJJ } from '@johnhenry/isomorphic-jj';
108
+ import { createBrowserFS } from '@johnhenry/isomorphic-jj/browser';
109
+
110
+ const fs = await createBrowserFS({ name: 'my-repo' });
111
+ const jj = await createJJ({ fs, dir: '/repo' });
112
+ // Same API as Node from here on — see examples/12-browser.mjs.
113
+ ```
114
+
115
+ ---
116
+
33
117
  ## Quick Start
34
118
 
35
119
  **Coming from isomorphic-git?** Read the [Migration Guide](./MIGRATION_FROM_ISOMORPHIC_GIT.md) to see how isomorphic-jj simplifies your JavaScript version control workflow.
@@ -42,6 +126,43 @@ This showcases all 17 feature categories (including v1.0 enhancements) in ~3 sec
42
126
 
43
127
  ---
44
128
 
129
+ ## Examples
130
+
131
+ The [`examples/`](./examples) directory has 12 numbered, runnable, self-asserting
132
+ scripts — each creates a repo in a temp dir, demonstrates one area, and cleans
133
+ up after itself. Run one with `npm run example:01` (etc.), or the whole set
134
+ (the same loop CI runs) with:
135
+
136
+ ```bash
137
+ npm run examples
138
+ ```
139
+
140
+ | # | What it shows |
141
+ |---|----------------|
142
+ | [01](./examples/01-init-commit-log.mjs) | The core loop: init → write → `describe()` → `new()` → `log()` |
143
+ | [02](./examples/02-stacked-changes.mjs) | Stable change IDs across a 3-layer stack; `edit()`+`amend()` a bottom layer |
144
+ | [03](./examples/03-history-editing.mjs) | `split()`, `squash({ into })`, `abandon()`/`unabandon()`, `duplicate()` |
145
+ | [04](./examples/04-branching-and-merging.mjs) | Diverging without branches; content merge vs. true merge changes |
146
+ | [05](./examples/05-conflicts.mjs) | First-class conflicts: dry-run preview, `conflicts.list()`/`resolve()` |
147
+ | [06](./examples/06-revsets.mjs) | The revset query language, end to end |
148
+ | [07](./examples/07-bookmarks-and-tags.mjs) | Bookmarks, tags, and remote tracking |
149
+ | [08](./examples/08-git-interop.mjs) | Real `git.clone()`/`push()`/`fetch()` against a local fixture, zero network |
150
+ | [09](./examples/09-config.mjs) | Config layers: persisted, programmatic, deep-merge, reset |
151
+ | [10](./examples/10-undo-and-oplog.mjs) | `undo()`/`redo()`, `operations.at()` time travel, `obslog()` |
152
+ | [11](./examples/11-file-operations.mjs) | The `file.*` namespace: historical `show()`, `annotate()`, `search()` |
153
+ | [12](./examples/12-browser.mjs) | Browser usage (IndexedDB fs, persistence, CORS proxy) as a reference |
154
+
155
+ See [`examples/README.md`](./examples/README.md) for details and conventions.
156
+
157
+ Three fuller example applications live under [`example/`](./example) — each
158
+ exercises the library from a different angle and documents the bugs it found:
159
+
160
+ - [`jj-review-tool`](./example/jj-review-tool) — a code-review CLI built on stacked changes and bookmarks.
161
+ - [`jj-storage-server`](./example/jj-storage-server) — a REST API using isomorphic-jj as a versioned document store.
162
+ - [`jj-wiki`](./example/jj-wiki) — a collaborative wiki exercising workspaces and conflict resolution.
163
+
164
+ ---
165
+
45
166
  ## What's New in v1.0
46
167
 
47
168
  isomorphic-jj v1.0 achieves **complete JJ CLI semantic compatibility** while maintaining 100% backward compatibility:
@@ -76,6 +197,7 @@ isomorphic-jj v1.0 now implements virtually all commonly-used JJ CLI commands:
76
197
  - **`git.remote.*`** - Complete remote management (list, add, remove, rename, setUrl)
77
198
  - **`bookmark.rename()`** - Rename bookmarks
78
199
  - **`bookmark.track/untrack/forget()`** - Remote bookmark management
200
+ - **`tag.track/untrack()`** - Remote tag management (jj v0.44)
79
201
  - **`config.*`** - Configuration management (get, set, list)
80
202
  - **`diff()`** - Show file differences between revisions
81
203
  - **`next()` / `prev()`** - Navigate between parent/child revisions
@@ -85,10 +207,10 @@ isomorphic-jj v1.0 now implements virtually all commonly-used JJ CLI commands:
85
207
  - **`operations.show/diff/restore()`** - Advanced operation log features
86
208
  - **`remote.*`** - Convenience aliases for git operations (push, fetch, add)
87
209
 
88
- See [JJ_CLI_PARITY.md](./JJ_CLI_PARITY.md) for complete feature comparison.
210
+ See [ROADMAP.md](./ROADMAP.md) for the release-by-release feature comparison and what's still planned.
89
211
 
90
212
  ### Testing & Quality
91
- - **1701 tests** passing — ~97% statement / 91% branch coverage (v1.0–v1.7)
213
+ - **1823 tests** passing — ~97% statement / 91% branch coverage
92
214
  - **100% backward compatible** - All existing code continues to work
93
215
  - **Zero breaking changes** - Deprecated features show warnings but still function
94
216
 
@@ -97,7 +219,7 @@ See [JJ_CLI_PARITY.md](./JJ_CLI_PARITY.md) for complete feature comparison.
97
219
  ### Installation
98
220
 
99
221
  ```bash
100
- npm install isomorphic-jj isomorphic-git
222
+ npm install @johnhenry/isomorphic-jj isomorphic-git
101
223
  ```
102
224
 
103
225
  For browsers, also install:
@@ -108,7 +230,7 @@ npm install @isomorphic-git/lightning-fs
108
230
  ### Basic Workflow
109
231
 
110
232
  ```javascript
111
- import { createJJ } from 'isomorphic-jj';
233
+ import { createJJ } from '@johnhenry/isomorphic-jj';
112
234
  import git from 'isomorphic-git';
113
235
  import fs from 'fs';
114
236
  import http from 'isomorphic-git/http/node';
@@ -147,13 +269,13 @@ console.log(log);
147
269
  ### Browser Usage
148
270
 
149
271
  ```javascript
150
- import { createJJ } from 'isomorphic-jj';
151
- import { createBrowserFS } from 'isomorphic-jj/browser';
272
+ import { createJJ } from '@johnhenry/isomorphic-jj';
273
+ import { createBrowserFS } from '@johnhenry/isomorphic-jj/browser';
152
274
  import git from 'isomorphic-git';
153
275
  import http from 'isomorphic-git/http/web';
154
276
 
155
277
  // Create browser filesystem (uses IndexedDB)
156
- const fs = createBrowserFS({ name: 'my-repo' });
278
+ const fs = await createBrowserFS({ name: 'my-repo' });
157
279
 
158
280
  const jj = await createJJ({ fs, dir: '/repo', git, http });
159
281
  await jj.git.init({ userName: 'User', userEmail: 'user@example.com' });
@@ -494,7 +616,7 @@ await jj.undo();
494
616
  Merge drivers enable smart merging of structured files like JSON, package.json, and YAML:
495
617
 
496
618
  ```javascript
497
- import { jsonDriver, packageJsonDriver, yamlDriver, markdownDriver } from 'isomorphic-jj';
619
+ import { jsonDriver, packageJsonDriver, yamlDriver, markdownDriver } from '@johnhenry/isomorphic-jj';
498
620
 
499
621
  // Register merge drivers for different file types
500
622
  jj.mergeDrivers.register({
@@ -625,23 +747,23 @@ const bookmarks = await jj.bookmark.list();
625
747
  ### Browser Support
626
748
 
627
749
  ```javascript
628
- import { createBrowserFS, requestPersistentStorage } from 'isomorphic-jj/browser';
750
+ import { createBrowserFS, requestPersistentStorage } from '@johnhenry/isomorphic-jj/browser';
629
751
 
630
752
  // Request persistent storage (prevents eviction)
631
753
  const persistent = await requestPersistentStorage();
632
754
 
633
755
  // Create filesystem with IndexedDB backend
634
- const fs = createBrowserFS({ backend: 'idb', name: 'my-repo' });
756
+ const fs = await createBrowserFS({ backend: 'idb', name: 'my-repo' });
635
757
 
636
758
  // Check browser capabilities
637
- import { detectCapabilities } from 'isomorphic-jj/browser';
759
+ import { detectCapabilities } from '@johnhenry/isomorphic-jj/browser';
638
760
  const caps = detectCapabilities();
639
761
  if (caps.indexedDB && caps.serviceWorker) {
640
762
  // Enable offline support
641
763
  }
642
764
 
643
765
  // Get storage quota
644
- import { getStorageQuota } from 'isomorphic-jj/browser';
766
+ import { getStorageQuota } from '@johnhenry/isomorphic-jj/browser';
645
767
  const quota = await getStorageQuota();
646
768
  console.log(`Using ${quota.percentage}% of available storage`);
647
769
  ```
@@ -794,7 +916,7 @@ Full API documentation available in [TypeScript definitions](./src/types.d.ts).
794
916
  ### Main Interface
795
917
 
796
918
  ```typescript
797
- import { createJJ, type JJ, type CreateJJOptions } from 'isomorphic-jj';
919
+ import { createJJ, type JJ, type CreateJJOptions } from '@johnhenry/isomorphic-jj';
798
920
 
799
921
  const jj: JJ = await createJJ(options: CreateJJOptions);
800
922
  ```
@@ -804,8 +926,8 @@ const jj: JJ = await createJJ(options: CreateJJOptions);
804
926
  - **Repository**: `init()`, `status()`, `stats()`
805
927
  - **Files**: `write()`, `read()`, `cat()`, `move()` (deprecated for history), `remove()`, `listFiles()` | **Namespace**: `file.write()`, `file.show()`, `file.list()`, `file.move()`, `file.remove()`
806
928
  - **Changes**: `describe()`, `new()`, `amend()`, `commit()`, `edit()`, `show()`
807
- - **History**: `log()`, `obslog()`, `squash()`, `split()`, `rebase()`, `abandon()`, `unabandon()`
808
- - **Operations**: `undo()`, `operations.list()`, `operations.at()`
929
+ - **History**: `log()`, `obslog()`, `squash()`, `split()`, `rebase()`, `abandon()`, `unabandon()`, `converge()`
930
+ - **Operations**: `undo()`, `redo()`, `operations.list()`, `operations.at()`, `operations.restore()`
809
931
  - **Bookmarks**: `bookmark.list()`, `bookmark.set()`, `bookmark.move()`, `bookmark.delete()`
810
932
  - **Git**: `git.init()`, `git.fetch()`, `git.push()`, `git.import()`, `git.export()`
811
933
  - **Remotes**: `remote.add()`, `remote.fetch()`, `remote.push()`
@@ -898,10 +1020,10 @@ repo/
898
1020
 
899
1021
  ## Project Status
900
1022
 
901
- **Current Version**: v1.7.0
902
- **Test Coverage**: 1701 tests, ~97% statements / 91% branches
903
- **JJ CLI parity**: tracks Jujutsu through v0.43
904
- **Status**: Ready for experimentation and prototyping
1023
+ **Current Version**: 0.3.0 (`@johnhenry/isomorphic-jj`; same library/API lineage as the old `isomorphic-jj`, which reached v1.7.0 before the rename — see the provenance note at the top of this file)
1024
+ **Test Coverage**: 1823 tests passing, ~97% statements / 91% branches
1025
+ **JJ CLI parity**: tracks Jujutsu through v0.45.1
1026
+ **Status**: Actively developed; broad JJ CLI semantic parity, used in the examples/apps in this repo and in [JJHub](#family). Not yet 1.0 — API surface can still shift; pin a version and read the CHANGELOG before upgrading.
905
1027
 
906
1028
  **Completed:**
907
1029
  - ✅ v0.1: Core JJ experience (stable IDs, undo, bookmarks, revsets)
@@ -911,6 +1033,9 @@ repo/
911
1033
  - ✅ v0.5: Custom merge drivers, enhanced revsets (time-based, graph analytics), conflict resolution enhancements
912
1034
  - ✅ v1.0: Full JJ CLI semantic parity, complete `file.*`/`operations.*`/`git.*` namespaces
913
1035
  - ✅ v1.5: Parity refresh tracking jj through **v0.43** — new revsets (`change_id`, `commit_id`, `subject`, `author_name`/`email`, `committer*`, `signed`, `divergent`, `merges`, `forks`, `first_parent`, `first_ancestors`, `fork_point`, `merge_point`, `exactly`, `present`, `coalesce`, `remote_tags`, `ancestors(x, depth)`), working `tags()`/`remote_tags()` revsets, and new commands: `revert()`, `redo()`, `sign()`/`unsign()`, `file.search()`, `bookmark.advance()`, `tag.set()`. See [CHANGELOG.md](./CHANGELOG.md).
1036
+ - ✅ 0.1.0 (post-rename): Parity refresh tracking jj through **v0.44** — `tag.track()`/`tag.untrack()`, the `builtin_log()` revset alias, and `file.search({ nameOnly: true })`; `git_refs()`/`git_head()` documented as deprecated (jj removed both in v0.43). See [CHANGELOG.md](./CHANGELOG.md) for what was deliberately left for a maintainer call (`jj run`, fetch-time remote tag/bookmark import).
1037
+ - ✅ 0.2.0: Storage-layer audit fixes — same-process storage locking, `undo()` reverting in-place graph/tag mutations, ambiguous change-id detection, categorized `push()` error codes, a conflict-marker newline fix, atomic protobuf writes, and open-ended revset ranges (`..b`, `a..`, `::`). See [CHANGELOG.md](./CHANGELOG.md).
1038
+ - ✅ 0.3.0: Parity refresh tracking jj through **v0.45.1** — a working `/browser` entry (async `createBrowserFS()`, bundle-safe protobuf schema loading, no stray Node-only imports), `undo()`/`operations.restore()` reverting graph rewrites with real progressive undo/redo, `squash()`/`abandon()`/`edit()`/`new()` fully syncing content instead of only metadata, `rebase()` performing a real three-way merge and recording conflicts, and the new `converge()` command (jj v0.45.0) to auto-resolve divergent commits. See [CHANGELOG.md](./CHANGELOG.md).
914
1039
 
915
1040
  See [ROADMAP.md](./ROADMAP.md) for detailed plans, and [CHANGELOG.md](./CHANGELOG.md) for the release history.
916
1041
 
@@ -920,7 +1045,7 @@ See [ROADMAP.md](./ROADMAP.md) for detailed plans, and [CHANGELOG.md](./CHANGELO
920
1045
 
921
1046
  ### Requirements
922
1047
 
923
- - **Node.js**: 20.0.0 or higher (uses the Web Crypto global, stabilized in Node 20; Node 18 is EOL)
1048
+ - **Node.js**: 26.0.0 or higher, matching `engines.node` and CI (uses the Web Crypto global, stabilized in Node 20 — the family floor is higher than the functional minimum)
924
1049
  - **Browsers**: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
925
1050
  - **Optional**: Git CLI (for JJ CLI interop testing)
926
1051
 
@@ -941,6 +1066,58 @@ See [ROADMAP.md](./ROADMAP.md) for detailed plans, and [CHANGELOG.md](./CHANGELO
941
1066
 
942
1067
  ---
943
1068
 
1069
+ ## Security model
1070
+
1071
+ isomorphic-jj is a headless reimplementation of JJ's model, not a wrapper
1072
+ around the `jj` or `git` binaries — that architectural choice is also its
1073
+ main security property. It does not run a sandbox and does not vet the
1074
+ repositories you point it at.
1075
+
1076
+ **What isomorphic-jj guarantees:**
1077
+
1078
+ - **No shell-out, ever.** The library never spawns a child process to run
1079
+ `git`, `jj`, or any other binary — repository paths, branch/bookmark
1080
+ names, and commit messages are handled as plain JS values through
1081
+ `isomorphic-git`'s and `protobufjs`'s pure-JS encoders, never interpolated
1082
+ into a shell command string. This removes the whole class of
1083
+ shell-injection risk that a CLI-wrapping library (like `simple-git`) has
1084
+ to defend against by construction, not by escaping.
1085
+ - **Storage writes are atomic.** `jj-operation-store.js`, `jj-view-store.js`,
1086
+ and `jj-tree-state.js` route every write through a shared
1087
+ `atomicWriteFile()` temp+rename helper, and same-process concurrent writes
1088
+ to the same path are serialized through a path-keyed async mutex — a
1089
+ crash or a racing autosnapshot mid-write cannot leave a truncated or
1090
+ undecodable store file. Fixed in [PR #19](https://github.com/johnhenry/isomorphic-jj/pull/19) (0.2.0); scoped to
1091
+ same-process concurrency — cross-process locking is not yet implemented
1092
+ (see "still yours" below).
1093
+
1094
+ **What is still yours:**
1095
+
1096
+ - **Remote authentication and transport trust.** `git.push()`/`git.fetch()`
1097
+ delegate to `isomorphic-git`'s HTTP client (and, in the browser, whatever
1098
+ CORS proxy you configure) — isomorphic-jj neither stores nor validates
1099
+ credentials, and does not verify a remote server's identity beyond what
1100
+ that HTTP layer does. A misconfigured or malicious CORS proxy sees
1101
+ everything a normal Git remote would.
1102
+ - **Custom merge drivers run arbitrary code with full process access.**
1103
+ `mergeDrivers.register()` lets you register a function per file
1104
+ pattern (`'*.json'`, `'package.json'`, …); a registered driver — yours or
1105
+ a dependency's — executes with the same privileges as the rest of your
1106
+ process during every merge that touches a matching path. isomorphic-jj
1107
+ does not sandbox driver execution; treat a third-party merge driver the
1108
+ same as any other third-party code you'd `require()`.
1109
+ - **Cross-process locking is not implemented.** The same-process mutex
1110
+ above does not protect a repository opened by two separate OS processes
1111
+ at once (e.g. two CLI invocations, or a CLI run concurrently with a
1112
+ long-running server process) — don't rely on isomorphic-jj to serialize
1113
+ those for you.
1114
+ - **No allowlisting of untrusted repository content.** Cloning or importing
1115
+ a Git history runs its objects through the same parsing code regardless
1116
+ of whether you trust the source, matching `isomorphic-git`'s own model —
1117
+ this library adds no additional vetting layer.
1118
+
1119
+ ---
1120
+
944
1121
  ## Contributing
945
1122
 
946
1123
  We welcome contributions! Here's how to help:
@@ -982,7 +1159,7 @@ A: Yes! Colocated repos expose normal Git commits. Git users never see JJ metada
982
1159
  A: Comparable to isomorphic-git for Git operations. JJ metadata (JSON) is fast in Node, acceptable in browsers. Large histories need pagination.
983
1160
 
984
1161
  **Q: Does this support all JJ features?**
985
- A: Not yet. We're at v0.4. See [ROADMAP.md](./ROADMAP.md) for planned features.
1162
+ A: Broad semantic parity (tracks Jujutsu through v0.45.1), not every CLI/UX detail — it's a library, not a terminal UI. See [ROADMAP.md](./ROADMAP.md) for what's planned and what's deliberately out of scope.
986
1163
 
987
1164
  **Q: Can I migrate my Git repo?**
988
1165
  A: Yes! `jj.git.init()` works on existing Git repositories.
@@ -992,12 +1169,35 @@ A: JJ's model genuinely improves common workflows—stable change IDs, fearless
992
1169
 
993
1170
  ---
994
1171
 
995
- ## Related Projects
996
-
997
- - [isomorphic-git](https://isomorphic-git.org/) - Pure JS Git implementation (our foundation)
998
- - [Jujutsu](https://jj-vcs.github.io/jj/) - The original JJ version control system
999
- - [simple-git](https://github.com/steveukx/git-js) - Git wrapper for Node.js
1000
- - [Git plumbing vs porcelain](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain) - Architecture pattern we follow
1172
+ ## Family
1173
+
1174
+ isomorphic-jj has no other package in the `@johnhenry` npm scope yet — it
1175
+ consumes and is consumed by projects outside that scope. Those relationships
1176
+ are still concrete enough to document precisely, so they're recorded here
1177
+ rather than under a vaguer "see also".
1178
+
1179
+ - **[JJHub](https://jjhub.erisera.com)** — a Jujutsu-native overlay on GitHub,
1180
+ and the closest thing this library has to a downstream consumer: it calls
1181
+ `createJJ()` directly (not a wrapped or forked copy) to get stable change
1182
+ IDs and stacked PRs on top of existing GitHub repos, platform-wide undo,
1183
+ and an MCP server exposing the same fearless-undo, no-staging-area
1184
+ workflow to coding agents. JJHub is a private Erisera product, not a
1185
+ `@johnhenry/*` package — install its CLI with `npm i -g jjhub`.
1186
+ - **[`isomorphic-git`](https://github.com/isomorphic-git/isomorphic-git)** —
1187
+ a real, non-optional dependency: this library's Git backend support
1188
+ (`jj.git.init/clone/push/fetch`) is built directly on isomorphic-git's
1189
+ pure-JS Git object model, not a fork or reimplementation of it. Peer
1190
+ dependency, not bundled — see [Installation & Environment](#installation--environment).
1191
+
1192
+ ### Prior art
1193
+
1194
+ - [Jujutsu](https://jj-vcs.github.io/jj/) — the original JJ version control
1195
+ system this library reimplements the semantics of (headlessly, in JS; not
1196
+ a wrapper around the `jj` binary).
1197
+ - [simple-git](https://github.com/steveukx/git-js) — a Git CLI wrapper for
1198
+ Node.js; unlike isomorphic-jj, it shells out to the `git` binary rather
1199
+ than reimplementing the object model in JS.
1200
+ - [Git plumbing vs porcelain](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain) — the architecture pattern this library's own layering follows.
1001
1201
 
1002
1202
  ---
1003
1203
 
@@ -1013,5 +1213,3 @@ Built on the shoulders of:
1013
1213
  - [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git) by William Hilton
1014
1214
  - [Jujutsu](https://github.com/martinvonz/jj) by Martin von Zweigbergk
1015
1215
  - The Git and JavaScript communities
1016
-
1017
- **Status**: v1.0.0 | **Tests**: 371 passing | **Ready for**: Production use
package/bin/isojj.js CHANGED
@@ -24,6 +24,7 @@ const BOOLEAN_FLAGS = new Set([
24
24
  'noTags',
25
25
  'allowNew',
26
26
  'preserveSnapshot',
27
+ 'nameOnly',
27
28
  ]);
28
29
 
29
30
  /** Coerce a raw flag-value string to a real boolean when it looks like one. */
@@ -179,7 +180,7 @@ History editing:
179
180
  Files:
180
181
  file.list [--revision <id>] List tracked files
181
182
  file.show <path> Show file contents
182
- file.search --pattern <re> Search file contents (jj file search)
183
+ file.search --pattern <re> [--nameOnly] Search file contents (jj file search)
183
184
  file.annotate --path <p> Blame-style annotation
184
185
 
185
186
  Bookmarks & tags:
@@ -188,6 +189,8 @@ Bookmarks & tags:
188
189
  bookmark.list
189
190
  tag.set --name <n> --changeId <id> Create or move a tag
190
191
  tag.list
192
+ tag.track --name <n> [--remote <r>] Track a remote tag (jj v0.44)
193
+ tag.untrack --name <n> Stop tracking a remote tag
191
194
 
192
195
  Signing:
193
196
  sign [--revision <id>] [--backend ssh --key <k>]