isomorphic-jj 1.7.0 → 1.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,205 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 — 2026-09-02
4
+
5
+ The first `@johnhenry/isomorphic-jj` release since 0.1.0, and the first
6
+ scoped release to carry the audit fixes from PR #19 below — **the published
7
+ 0.1.0 tarball on npm predates #19** and does not include them.
8
+
9
+ ### Fixed (PR #19 — audit findings)
10
+
11
+ Fixes all 8 findings from a bug-hunt audit of the storage/operation-log,
12
+ undo/redo, revset, and Git-push layers:
13
+
14
+ - **Same-process storage locking.** `Storage.appendLine()`/`write()` did
15
+ read-then-write with no lock, so concurrent same-process calls (e.g. a
16
+ user command racing `BackgroundOps`'s autosnapshot) could silently drop an
17
+ entry. Added a path-keyed in-process async mutex (`src/utils/mutex.js`)
18
+ that serializes the full critical section for both methods. Scoped to
19
+ same-process concurrency per the audit's guidance; cross-process locking
20
+ is a follow-up.
21
+ - **`undo()` now reverts in-place content mutations.** Previously it never
22
+ restored `ChangeGraph`/tag mutations made in place. `describe()` now
23
+ snapshots the affected `ChangeGraph` node before mutating it (mirroring
24
+ the existing `fileSnapshot` pattern), and `undo()` restores it.
25
+ `operations.revert()` now also diffs/restores `tags`, not just
26
+ `bookmarks`.
27
+ - **Ambiguous change-id prefixes now throw `AMBIGUOUS_ID`.** `show()`
28
+ previously resolved an ambiguous prefix silently to the first match; it
29
+ now throws `AMBIGUOUS_ID` listing all matches.
30
+ - **`push()` surfaces categorized error codes.** Previously all per-ref
31
+ errors were swallowed into a bare ref name. Rejected refs now carry a
32
+ categorized `code` (`AUTH_FAILED`/`NETWORK_ERROR`/`NON_FAST_FORWARD`/
33
+ `OTHER`) and `reason` so callers can tell an auth failure apart from a
34
+ non-fast-forward rejection instead of guessing.
35
+ - **Conflict-marker newline fix.** Markers could fuse content onto boundary
36
+ markers when content lacked a trailing newline; now forces a newline
37
+ separator for non-empty content.
38
+ - **Atomic protobuf writes.** `jj-operation-store.js`, `jj-view-store.js`,
39
+ and `jj-tree-state.js` risked a truncated/undecodable file on a mid-write
40
+ crash. Now route through a shared `atomicWriteFile()` temp+rename helper
41
+ (`src/utils/atomic-write.js`).
42
+ - **Weak temp-file naming fixed alongside storage locking** by adding a
43
+ random suffix, so two concurrent writes can't collide on the same temp
44
+ filename.
45
+ - **Open-ended revset ranges** (`..b`, `a..`, `::`) failed with a
46
+ misleading "invalid IDs" error; they now delegate to the existing
47
+ `ancestors()`/`descendants()`/`all()` implementations.
48
+
49
+ Closes #11–#18. See [PR #19](https://github.com/johnhenry/isomorphic-jj/pull/19).
50
+
51
+ ### CI (PR #20)
52
+
53
+ - Dropped macOS from the test matrix — hosted macOS runners are scarce/slow
54
+ to schedule and this is a pure-JS library with no native code path; Linux
55
+ + Windows already cover realistic cross-platform risk. See
56
+ [PR #20](https://github.com/johnhenry/isomorphic-jj/pull/20).
57
+
58
+ ### Documentation overhaul: examples suite
59
+
60
+ - **New `examples/` directory: 12 numbered, runnable examples** covering the
61
+ core loop (init/describe/new/log), stable-ID stacked changes, history
62
+ editing (split/squash/abandon/duplicate), branching and merging (including
63
+ `new({ parents })` for true merge changes), first-class conflicts, revsets,
64
+ bookmarks + tags (with the v0.44 `tag.track()` surface), Git interop,
65
+ configuration layers, undo/oplog/time travel, the `file.*` namespace, and
66
+ browser usage. Each example runs in a temp directory, cleans up after
67
+ itself, and *asserts* what it demonstrates, so the set doubles as a smoke
68
+ test. `npm run examples` runs the loop; `npm run example:NN` runs one.
69
+ - **Example 08 exercises real `git.clone()`/`git.push()`/`git.fetch()` with
70
+ zero network**: it builds a bare fixture repo with the git CLI and serves
71
+ it on 127.0.0.1 through `git http-backend` (buffering request bodies so
72
+ CGI gets a `CONTENT_LENGTH` — isomorphic-git sends chunked bodies). Skips
73
+ cleanly where the git CLI is unavailable.
74
+ - **CI**: the test workflow now runs the examples loop as a smoke step on
75
+ one matrix leg (ubuntu-latest / Node 22), deliberately a different leg
76
+ than the coverage gate.
77
+ - Companion docs for the site (opensource.johnhenry.me) were written from
78
+ this repo's README/API/MIGRATION/CONFIGURATION material in the same pass;
79
+ behavioral quirks the examples surfaced (e.g. `file()` matching snapshots
80
+ rather than modifications, duration revsets needing committer timestamps,
81
+ `init()` after `git.clone()` re-rooting `refs/heads/main`) are documented
82
+ there rather than papered over.
83
+
84
+ ### Publishing
85
+
86
+ - `@johnhenry/isomorphic-jj@0.2.0` is published from `main`. A final
87
+ unscoped bridge release, `isomorphic-jj@1.8.0` (same code as this
88
+ release), will follow so existing unscoped installs get one more version
89
+ pointing at the new package before the unscoped name is deprecated.
90
+
91
+ ## 0.1.0 — Track jj through v0.44
92
+
93
+ Jujutsu shipped v0.44.0 (2026-08-05) since isomorphic-jj's last parity pass
94
+ (v1.5.0/README, which tracked jj through v0.43). This release closes the gap
95
+ for the parts of v0.43–v0.44 that are in scope for a headless, browser-safe
96
+ reimplementation of jj's model — a library, not the `jj` CLI's terminal UX or
97
+ its Rust process/Git-plumbing internals.
98
+
99
+ ### Added
100
+
101
+ - **`tag.track({ name, remote })` / `tag.untrack({ name })`** — jj v0.44 made
102
+ tags remote-trackable the same way bookmarks already were, and added `jj
103
+ tag track`/`untrack` to manage that per-tag. `TagStore` now persists
104
+ tracking state (`{ remote, remoteName }` per local tag name) the same way
105
+ `BookmarkStore` already did for bookmarks, and `tag.list()` includes a
106
+ `tracking: { remote, ref }` field once a tag is tracked. The on-disk
107
+ `tags.json` format gained a `{ tags, tracked }` envelope; the old flat
108
+ `{ name: changeId }` format is still read for backward compatibility.
109
+ - **`builtin_log()` revset function** — jj v0.44 added `builtin_log()` as an
110
+ alias for the revset the built-in `jj log` uses by default, so a custom
111
+ `revsets.log` config can extend it instead of duplicating it. isomorphic-jj's
112
+ `log()` has always defaulted to `all()` when no revset is given, so
113
+ `builtin_log()` is wired to the same set and can be composed like any other
114
+ revset function (`builtin_log() & mine()`).
115
+ - **`file.search({ ..., nameOnly: true })`** — jj v0.44 changed `jj file
116
+ search`'s default CLI output to print every matched *line* (prefixed with
117
+ its file path), moving the old "just the file paths" behavior behind a new
118
+ `--name-only` flag. isomorphic-jj's `file.search()` already returned
119
+ structured per-line matches (`{ path, lineNumber, line }`) — that was
120
+ already the new default — so the only gap was the old, path-only shape;
121
+ `{ nameOnly: true }` now returns a deduplicated `string[]` of matching
122
+ paths, matching `--name-only`.
123
+
124
+ ### Changed
125
+
126
+ - **`git_refs()` / `git_head()` revsets are now documented as deprecated.**
127
+ Upstream jj deprecated both in favor of `bookmarks()`/`tags()`/`@`, then
128
+ removed them outright in jj v0.43 (calling them in real jj now errors).
129
+ isomorphic-jj keeps them working — removing a function outright is a
130
+ breaking API change this pass didn't want to force on existing callers
131
+ unilaterally — but they're no longer listed in the revset engine's
132
+ "did you mean" suggestion text, and their JSDoc now calls out the upstream
133
+ removal and recommends `bookmarks()`/`tags()`/`@` instead. See "Not
134
+ changed" below for the case for a harder break in a future major version.
135
+
136
+ ### Testing
137
+
138
+ 1714 tests passing (was 1701); lint (0 errors), format:check, typecheck, and
139
+ build all still green.
140
+
141
+ ### Not changed (needs a human design call)
142
+
143
+ jj v0.43–v0.44 included several changes this pass deliberately left alone:
144
+
145
+ - **`jj run`** (v0.43 new command, gained `--passthrough`/`--ignore-changes`/
146
+ `--ignore-errors`/oldest-first-ordering in v0.44) — runs an arbitrary
147
+ subprocess against each revision's own private working copy. isomorphic-jj
148
+ doesn't shell out to anything and has to keep working in browsers with no
149
+ process/filesystem access; "run a command" doesn't have an isomorphic
150
+ equivalent. Adding it would mean either a Node-only stub (inconsistent with
151
+ the rest of the API surface) or scope-creeping into a job-runner. Flagging
152
+ for a maintainer decision rather than guessing.
153
+ - **Auto-importing remote tags/bookmarks during `git.fetch()`.** jj v0.44's
154
+ headline change is that `jj git fetch` now fetches tags the same way it
155
+ fetches bookmarks — as `<name>@<remote>`, auto-tracked by default. Wiring
156
+ that up properly for tags would need `git.fetch()` to actually populate
157
+ `TagStore`'s (and, by the same logic, `BookmarkStore`'s) remote-tracking
158
+ state from the fetched refs. Investigating this surfaced a **pre-existing**
159
+ gap: `git.fetch()` already doesn't call `bookmarks.setRemote()` for fetched
160
+ bookmarks today, even though `BookmarkStore.setRemote()`/`getRemote()` have
161
+ existed since v0.4 — remote ref sync was never wired all the way through at
162
+ the fetch call site. Building tag-fetch-tracking on top of that gap would
163
+ mean either (a) fixing the older bookmark gap too as a drive-by, our
164
+ papering over an inconsistency where tags "worked" and bookmarks didn't, or
165
+ (b) building a second, tag-only special case. Both are judgment calls
166
+ about a real architectural gap, not a mechanical port of one version's
167
+ changelog — left for a maintainer to decide. `tag.track()`/`untrack()`
168
+ (added this pass) at least let callers record and query tracking intent by
169
+ hand in the meantime.
170
+ - **`jj git clone --tag=PATTERN` / `--fetch-tags` removal.** Real jj replaced
171
+ `--fetch-tags=all|none|included` with `--tag=PATTERN` in v0.44. isojj's
172
+ `git.clone()`/`git.fetch()` never exposed CLI-shaped `--fetch-tags` flags in
173
+ the first place (just a boolean `noTags`), so there's no removed flag to
174
+ mirror; a `PATTERN`-based tag filter for clone/fetch would be new surface
175
+ area tied to the fetch-tracking gap above.
176
+ - **`jj git push --allow-conflicts`.** Real jj normally refuses to push
177
+ commits containing conflicts unless this flag is passed. isojj's
178
+ `git.push()` doesn't currently check for conflicts before pushing at all —
179
+ there's no existing guard to add a bypass flag for. Adding the guard itself
180
+ (and then the bypass) is more surface area than a one-version parity pass.
181
+ - **CLI argument parsing "last occurrence wins" (v0.44).** Checked
182
+ `bin/isojj.js`'s `parseArgs()`: it already stores each `--flag` into a
183
+ plain object keyed by flag name, so repeating a flag already naturally
184
+ overwrites the earlier value with no error — this was already jj v0.44's
185
+ new behavior by construction. No change needed.
186
+ - **`try(expr, fallback...)` template function, `jj workspace list` root
187
+ display, `diff.stat.max-bar-width`, `colors.crossed-out`, Gerrit/config-gc/
188
+ `/etc/jj` config-discovery changes.** These are jj's template engine and
189
+ terminal/config-file layers, which isomorphic-jj's CLI (a thin, generic
190
+ API-argument passthrough — see `bin/isojj.js`) doesn't attempt to replicate
191
+ 1:1 for any command. Out of scope for this pass; noted here for
192
+ completeness of the v0.43/v0.44 diff.
193
+
194
+ ## 0.0.0
195
+
196
+ - **Renamed: `isomorphic-jj` is now `@johnhenry/isomorphic-jj`, restarted at 0.0.0.** Same library, same API — a new address and era, not a maturity signal (1.7.0 lineage).
197
+
198
+ ```sh
199
+ npm install @johnhenry/isomorphic-jj
200
+ ```
201
+
202
+
3
203
  All notable changes to isomorphic-jj are documented here. The project tracks the
4
204
  [Jujutsu (jj)](https://github.com/jj-vcs/jj) CLI; each release notes the upstream
5
205
  jj version whose semantics it targets.
@@ -171,7 +371,9 @@ adds a batch of revset functions and commands, and cleans up the toolchain.
171
371
  - `forks()` — changes with more than one child.
172
372
  - `first_parent(x)` / `first_ancestors(x)` — first-parent navigation (jj v0.32).
173
373
  - `fork_point(x)` — youngest common ancestor of a set (jj v0.32).
174
- - `merge_point(x)` — youngest common descendant of a set.
374
+ - `merge_point(x)` — youngest common descendant of a set (implemented ahead of
375
+ upstream; jj stabilized its own `merge_point()` in v0.44 with matching
376
+ semantics — "the point where multiple branches merge").
175
377
  - `exactly(x, n)` — the set, but errors unless it has exactly `n` elements (jj v0.34).
176
378
  - `present(x)` — evaluate without erroring on unknown symbols.
177
379
  - `coalesce(a, b, …)` — the first argument that resolves to a non-empty set.
package/README.md CHANGED
@@ -1,11 +1,20 @@
1
- # isomorphic-jj
1
+ # @johnhenry/isomorphic-jj
2
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)
3
+ > **This package has moved to `@johnhenry/isomorphic-jj`.** This is the final release under the old name.
6
4
 
7
5
  > **Jujutsu version control for JavaScript**—stable change IDs, fearless undo, and no staging area. Works in Node.js and browsers.
8
6
 
7
+ Full documentation: [opensource.johnhenry.me/isomorphic-jj](https://opensource.johnhenry.me/isomorphic-jj/)
8
+
9
+ > Previously published as `isomorphic-jj` (final release 1.8.0, deprecated in
10
+ > favor of this package). Renamed to `@johnhenry/isomorphic-jj` and restarted
11
+ > at 0.0.0 on import into the @johnhenry family — a new address and era, not
12
+ > a maturity signal.
13
+
14
+ [![npm version](https://img.shields.io/npm/v/%40johnhenry%2Fisomorphic-jj.svg)](https://www.npmjs.com/package/@johnhenry/isomorphic-jj)
15
+ [![CI](https://github.com/johnhenry/isomorphic-jj/actions/workflows/test.yml/badge.svg)](https://github.com/johnhenry/isomorphic-jj/actions/workflows/test.yml)
16
+ [![license](https://img.shields.io/npm/l/%40johnhenry%2Fisomorphic-jj.svg)](LICENSE)
17
+
9
18
  **What makes it different:**
10
19
  - 🎯 **Stable change IDs** that survive rebases/squashes
11
20
  - ↩️ **Complete undo** for any operation (not just commits)
@@ -14,7 +23,7 @@
14
23
  - 🌐 **True isomorphic**—same API in Node, browsers, and Web Workers
15
24
 
16
25
  ```javascript
17
- import { createJJ } from 'isomorphic-jj';
26
+ import { createJJ } from '@johnhenry/isomorphic-jj';
18
27
  import git from 'isomorphic-git';
19
28
  import fs from 'fs';
20
29
 
@@ -30,6 +39,60 @@ await jj.undo();
30
39
 
31
40
  ---
32
41
 
42
+ ## Try it in 60 seconds
43
+
44
+ ### CLI
45
+
46
+ Every method is reachable from the `isojj` CLI (`bin/isojj.js`). Run it with
47
+ `npx`, or install it globally (`npm i -g @johnhenry/isomorphic-jj`) and call
48
+ `isojj` directly:
49
+
50
+ ```bash
51
+ npx @johnhenry/isomorphic-jj init
52
+ echo "# hello" > README.md
53
+ npx @johnhenry/isomorphic-jj describe -m "Initial commit"
54
+ npx @johnhenry/isomorphic-jj new -m "Add a feature"
55
+ npx @johnhenry/isomorphic-jj log
56
+ ```
57
+
58
+ ```
59
+ Change History:
60
+
61
+ cb7b4e93fd23 Add a feature
62
+ You 9/2/2026, 7:20:30 AM
63
+
64
+ a2f6f5af8107 Initial commit
65
+ You 9/2/2026, 7:20:30 AM
66
+ ```
67
+
68
+ Run `npx @johnhenry/isomorphic-jj --help` for the full command list.
69
+
70
+ ### Node.js
71
+
72
+ ```javascript
73
+ import { createJJ } from '@johnhenry/isomorphic-jj';
74
+ import fs from 'fs';
75
+
76
+ const jj = await createJJ({ fs, dir: './my-repo' });
77
+ await jj.init({ userName: 'You', userEmail: 'you@example.com' });
78
+ await jj.write({ path: 'README.md', data: '# hello\n' });
79
+ await jj.describe({ message: 'Initial commit' });
80
+ console.log(await jj.log({ limit: 5 }));
81
+ ```
82
+
83
+ ### Browser
84
+
85
+ ```javascript
86
+ import { createJJ } from '@johnhenry/isomorphic-jj';
87
+ import { createBrowserFS } from '@johnhenry/isomorphic-jj/browser';
88
+
89
+ const fs = createBrowserFS({ name: 'my-repo' });
90
+ const jj = await createJJ({ fs, dir: '/repo' });
91
+ // Same API as Node from here on — see examples/12-browser.mjs.
92
+ ```
93
+
94
+ ---
95
+
33
96
  ## Quick Start
34
97
 
35
98
  **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 +105,43 @@ This showcases all 17 feature categories (including v1.0 enhancements) in ~3 sec
42
105
 
43
106
  ---
44
107
 
108
+ ## Examples
109
+
110
+ The [`examples/`](./examples) directory has 12 numbered, runnable, self-asserting
111
+ scripts — each creates a repo in a temp dir, demonstrates one area, and cleans
112
+ up after itself. Run one with `npm run example:01` (etc.), or the whole set
113
+ (the same loop CI runs) with:
114
+
115
+ ```bash
116
+ npm run examples
117
+ ```
118
+
119
+ | # | What it shows |
120
+ |---|----------------|
121
+ | [01](./examples/01-init-commit-log.mjs) | The core loop: init → write → `describe()` → `new()` → `log()` |
122
+ | [02](./examples/02-stacked-changes.mjs) | Stable change IDs across a 3-layer stack; `edit()`+`amend()` a bottom layer |
123
+ | [03](./examples/03-history-editing.mjs) | `split()`, `squash({ into })`, `abandon()`/`unabandon()`, `duplicate()` |
124
+ | [04](./examples/04-branching-and-merging.mjs) | Diverging without branches; content merge vs. true merge changes |
125
+ | [05](./examples/05-conflicts.mjs) | First-class conflicts: dry-run preview, `conflicts.list()`/`resolve()` |
126
+ | [06](./examples/06-revsets.mjs) | The revset query language, end to end |
127
+ | [07](./examples/07-bookmarks-and-tags.mjs) | Bookmarks, tags, and remote tracking |
128
+ | [08](./examples/08-git-interop.mjs) | Real `git.clone()`/`push()`/`fetch()` against a local fixture, zero network |
129
+ | [09](./examples/09-config.mjs) | Config layers: persisted, programmatic, deep-merge, reset |
130
+ | [10](./examples/10-undo-and-oplog.mjs) | `undo()`/`redo()`, `operations.at()` time travel, `obslog()` |
131
+ | [11](./examples/11-file-operations.mjs) | The `file.*` namespace: historical `show()`, `annotate()`, `search()` |
132
+ | [12](./examples/12-browser.mjs) | Browser usage (IndexedDB fs, persistence, CORS proxy) as a reference |
133
+
134
+ See [`examples/README.md`](./examples/README.md) for details and conventions.
135
+
136
+ Three fuller example applications live under [`example/`](./example) — each
137
+ exercises the library from a different angle and documents the bugs it found:
138
+
139
+ - [`jj-review-tool`](./example/jj-review-tool) — a code-review CLI built on stacked changes and bookmarks.
140
+ - [`jj-storage-server`](./example/jj-storage-server) — a REST API using isomorphic-jj as a versioned document store.
141
+ - [`jj-wiki`](./example/jj-wiki) — a collaborative wiki exercising workspaces and conflict resolution.
142
+
143
+ ---
144
+
45
145
  ## What's New in v1.0
46
146
 
47
147
  isomorphic-jj v1.0 achieves **complete JJ CLI semantic compatibility** while maintaining 100% backward compatibility:
@@ -76,6 +176,7 @@ isomorphic-jj v1.0 now implements virtually all commonly-used JJ CLI commands:
76
176
  - **`git.remote.*`** - Complete remote management (list, add, remove, rename, setUrl)
77
177
  - **`bookmark.rename()`** - Rename bookmarks
78
178
  - **`bookmark.track/untrack/forget()`** - Remote bookmark management
179
+ - **`tag.track/untrack()`** - Remote tag management (jj v0.44)
79
180
  - **`config.*`** - Configuration management (get, set, list)
80
181
  - **`diff()`** - Show file differences between revisions
81
182
  - **`next()` / `prev()`** - Navigate between parent/child revisions
@@ -85,10 +186,10 @@ isomorphic-jj v1.0 now implements virtually all commonly-used JJ CLI commands:
85
186
  - **`operations.show/diff/restore()`** - Advanced operation log features
86
187
  - **`remote.*`** - Convenience aliases for git operations (push, fetch, add)
87
188
 
88
- See [JJ_CLI_PARITY.md](./JJ_CLI_PARITY.md) for complete feature comparison.
189
+ See [ROADMAP.md](./ROADMAP.md) for the release-by-release feature comparison and what's still planned.
89
190
 
90
191
  ### Testing & Quality
91
- - **1701 tests** passing — ~97% statement / 91% branch coverage (v1.0–v1.7)
192
+ - **1730 tests** passing — ~97% statement / 91% branch coverage
92
193
  - **100% backward compatible** - All existing code continues to work
93
194
  - **Zero breaking changes** - Deprecated features show warnings but still function
94
195
 
@@ -97,7 +198,7 @@ See [JJ_CLI_PARITY.md](./JJ_CLI_PARITY.md) for complete feature comparison.
97
198
  ### Installation
98
199
 
99
200
  ```bash
100
- npm install isomorphic-jj isomorphic-git
201
+ npm install @johnhenry/isomorphic-jj isomorphic-git
101
202
  ```
102
203
 
103
204
  For browsers, also install:
@@ -108,7 +209,7 @@ npm install @isomorphic-git/lightning-fs
108
209
  ### Basic Workflow
109
210
 
110
211
  ```javascript
111
- import { createJJ } from 'isomorphic-jj';
212
+ import { createJJ } from '@johnhenry/isomorphic-jj';
112
213
  import git from 'isomorphic-git';
113
214
  import fs from 'fs';
114
215
  import http from 'isomorphic-git/http/node';
@@ -147,8 +248,8 @@ console.log(log);
147
248
  ### Browser Usage
148
249
 
149
250
  ```javascript
150
- import { createJJ } from 'isomorphic-jj';
151
- import { createBrowserFS } from 'isomorphic-jj/browser';
251
+ import { createJJ } from '@johnhenry/isomorphic-jj';
252
+ import { createBrowserFS } from '@johnhenry/isomorphic-jj/browser';
152
253
  import git from 'isomorphic-git';
153
254
  import http from 'isomorphic-git/http/web';
154
255
 
@@ -494,7 +595,7 @@ await jj.undo();
494
595
  Merge drivers enable smart merging of structured files like JSON, package.json, and YAML:
495
596
 
496
597
  ```javascript
497
- import { jsonDriver, packageJsonDriver, yamlDriver, markdownDriver } from 'isomorphic-jj';
598
+ import { jsonDriver, packageJsonDriver, yamlDriver, markdownDriver } from '@johnhenry/isomorphic-jj';
498
599
 
499
600
  // Register merge drivers for different file types
500
601
  jj.mergeDrivers.register({
@@ -625,7 +726,7 @@ const bookmarks = await jj.bookmark.list();
625
726
  ### Browser Support
626
727
 
627
728
  ```javascript
628
- import { createBrowserFS, requestPersistentStorage } from 'isomorphic-jj/browser';
729
+ import { createBrowserFS, requestPersistentStorage } from '@johnhenry/isomorphic-jj/browser';
629
730
 
630
731
  // Request persistent storage (prevents eviction)
631
732
  const persistent = await requestPersistentStorage();
@@ -634,14 +735,14 @@ const persistent = await requestPersistentStorage();
634
735
  const fs = createBrowserFS({ backend: 'idb', name: 'my-repo' });
635
736
 
636
737
  // Check browser capabilities
637
- import { detectCapabilities } from 'isomorphic-jj/browser';
738
+ import { detectCapabilities } from '@johnhenry/isomorphic-jj/browser';
638
739
  const caps = detectCapabilities();
639
740
  if (caps.indexedDB && caps.serviceWorker) {
640
741
  // Enable offline support
641
742
  }
642
743
 
643
744
  // Get storage quota
644
- import { getStorageQuota } from 'isomorphic-jj/browser';
745
+ import { getStorageQuota } from '@johnhenry/isomorphic-jj/browser';
645
746
  const quota = await getStorageQuota();
646
747
  console.log(`Using ${quota.percentage}% of available storage`);
647
748
  ```
@@ -794,7 +895,7 @@ Full API documentation available in [TypeScript definitions](./src/types.d.ts).
794
895
  ### Main Interface
795
896
 
796
897
  ```typescript
797
- import { createJJ, type JJ, type CreateJJOptions } from 'isomorphic-jj';
898
+ import { createJJ, type JJ, type CreateJJOptions } from '@johnhenry/isomorphic-jj';
798
899
 
799
900
  const jj: JJ = await createJJ(options: CreateJJOptions);
800
901
  ```
@@ -898,10 +999,10 @@ repo/
898
999
 
899
1000
  ## Project Status
900
1001
 
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
1002
+ **Current Version**: 0.2.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)
1003
+ **Test Coverage**: 1730 tests passing, ~97% statements / 91% branches
1004
+ **JJ CLI parity**: tracks Jujutsu through v0.44
1005
+ **Status**: Actively developed; broad JJ CLI semantic parity, used in the examples/apps in this repo and in [JJHub](#related-projects). Not yet 1.0 — API surface can still shift; pin a version and read the CHANGELOG before upgrading.
905
1006
 
906
1007
  **Completed:**
907
1008
  - ✅ v0.1: Core JJ experience (stable IDs, undo, bookmarks, revsets)
@@ -911,6 +1012,8 @@ repo/
911
1012
  - ✅ v0.5: Custom merge drivers, enhanced revsets (time-based, graph analytics), conflict resolution enhancements
912
1013
  - ✅ v1.0: Full JJ CLI semantic parity, complete `file.*`/`operations.*`/`git.*` namespaces
913
1014
  - ✅ 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).
1015
+ - ✅ 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).
1016
+ - ✅ 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).
914
1017
 
915
1018
  See [ROADMAP.md](./ROADMAP.md) for detailed plans, and [CHANGELOG.md](./CHANGELOG.md) for the release history.
916
1019
 
@@ -982,7 +1085,7 @@ A: Yes! Colocated repos expose normal Git commits. Git users never see JJ metada
982
1085
  A: Comparable to isomorphic-git for Git operations. JJ metadata (JSON) is fast in Node, acceptable in browsers. Large histories need pagination.
983
1086
 
984
1087
  **Q: Does this support all JJ features?**
985
- A: Not yet. We're at v0.4. See [ROADMAP.md](./ROADMAP.md) for planned features.
1088
+ A: Broad semantic parity (tracks Jujutsu through v0.44), 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
1089
 
987
1090
  **Q: Can I migrate my Git repo?**
988
1091
  A: Yes! `jj.git.init()` works on existing Git repositories.
@@ -994,6 +1097,16 @@ A: JJ's model genuinely improves common workflows—stable change IDs, fearless
994
1097
 
995
1098
  ## Related Projects
996
1099
 
1100
+ ### JJHub
1101
+
1102
+ [JJHub](https://jjhub.erisera.com) is a Jujutsu-native overlay on GitHub, built
1103
+ on this library (it uses `createJJ` directly): stable change IDs and stacked
1104
+ PRs on top of your existing GitHub repos, platform-wide undo, and an MCP
1105
+ server so coding agents get the same fearless-undo, no-staging-area workflow.
1106
+ Install the CLI with `npm i -g jjhub`.
1107
+
1108
+ ### Others
1109
+
997
1110
  - [isomorphic-git](https://isomorphic-git.org/) - Pure JS Git implementation (our foundation)
998
1111
  - [Jujutsu](https://jj-vcs.github.io/jj/) - The original JJ version control system
999
1112
  - [simple-git](https://github.com/steveukx/git-js) - Git wrapper for Node.js
@@ -1013,5 +1126,3 @@ Built on the shoulders of:
1013
1126
  - [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git) by William Hilton
1014
1127
  - [Jujutsu](https://github.com/martinvonz/jj) by Martin von Zweigbergk
1015
1128
  - 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>]