jjhub 0.1.2 → 0.1.3
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 +13 -13
- package/dist/cli/{jjh.mjs → jjhub.mjs} +19 -19
- package/package.json +3 -4
- package/skills/jjhub-cli/SKILL.md +34 -34
- package/skills/jjhub-cli/agents-snippet.md +15 -15
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# jjhub
|
|
1
|
+
# jjhub
|
|
2
2
|
|
|
3
3
|
GitHub CLI with Jujutsu-native superpowers: stable change IDs, stacks,
|
|
4
4
|
platform-wide undo, and conflicts that wait — layered over plain GitHub
|
|
@@ -7,7 +7,7 @@ repos by a [JJHub](https://jjhub.johnhenry.me) server.
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
npm install -g jjhub # installs `jjhub`
|
|
10
|
+
npm install -g jjhub # installs the `jjhub` command
|
|
11
11
|
# or one-off:
|
|
12
12
|
npx jjhub --help
|
|
13
13
|
```
|
|
@@ -15,20 +15,20 @@ npx jjhub --help
|
|
|
15
15
|
## Quick start
|
|
16
16
|
|
|
17
17
|
```sh
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
jjhub auth login # device-flow sign-in to your JJHub server
|
|
19
|
+
jjhub repo list # what the server tracks
|
|
20
|
+
jjhub change create "Fix login" # a change with a STABLE id (survives rebases)
|
|
21
|
+
jjhub change list
|
|
22
|
+
jjhub undo # platform-wide undo, from the op log
|
|
23
|
+
jjhub agents-md >> AGENTS.md # teach your repo's coding agents to prefer jjhub
|
|
24
|
+
jjhub mcp serve # stdio MCP server over the same API
|
|
25
|
+
jjhub acp serve # ACP agent (Zed etc.)
|
|
26
|
+
jjhub help # everything else
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
The CLI talks to the JJHub server at `JJHUB_URL` (default
|
|
30
|
-
`http://localhost:3000`) — e.g. `JJHUB_URL=https://jjhub.johnhenry.me
|
|
31
|
-
or use `
|
|
30
|
+
`http://localhost:3000`) — e.g. `JJHUB_URL=https://jjhub.johnhenry.me jjhub repo list`,
|
|
31
|
+
or use `jjhub auth login --url https://jjhub.johnhenry.me` once and the saved
|
|
32
32
|
config takes over.
|
|
33
33
|
|
|
34
34
|
This package is the standalone CLI build (single bundled file, no runtime
|
|
@@ -83,7 +83,7 @@ var init_api_client = __esm({
|
|
|
83
83
|
/**
|
|
84
84
|
* `apiKey` falls back to JJHUB_API_KEY when omitted (the legacy shared
|
|
85
85
|
* secret / ops credential). `opts.bearerToken` is an OAuth access token
|
|
86
|
-
* from `
|
|
86
|
+
* from `jjhub auth login` (issue #43) — when present it wins, sent as
|
|
87
87
|
* `Authorization: Bearer`.
|
|
88
88
|
*/
|
|
89
89
|
constructor(baseUrl, apiKey, opts = {}) {
|
|
@@ -64727,7 +64727,7 @@ var init_agent = __esm({
|
|
|
64727
64727
|
});
|
|
64728
64728
|
return { sessionId };
|
|
64729
64729
|
}
|
|
64730
|
-
/** Credentials come from ~/.config/jjhub (
|
|
64730
|
+
/** Credentials come from ~/.config/jjhub (jjhub auth login) — nothing to do in-protocol. */
|
|
64731
64731
|
authenticate() {
|
|
64732
64732
|
}
|
|
64733
64733
|
async prompt(params) {
|
|
@@ -93318,7 +93318,7 @@ async function resolveRepoId(api, repoFlag, resolveContext) {
|
|
|
93318
93318
|
const match = repos.find((r) => r.fullName === fullName);
|
|
93319
93319
|
if (!match) {
|
|
93320
93320
|
throw new Error(
|
|
93321
|
-
`no JJHub repository for ${fullName} \u2014 run \`
|
|
93321
|
+
`no JJHub repository for ${fullName} \u2014 run \`jjhub repo init${repoFlag ? ` ${fullName}` : ""}\` to create it`
|
|
93322
93322
|
);
|
|
93323
93323
|
}
|
|
93324
93324
|
return match.id;
|
|
@@ -93631,7 +93631,7 @@ function isProcessAlive(pid) {
|
|
|
93631
93631
|
}
|
|
93632
93632
|
}
|
|
93633
93633
|
var defaultSpawnFn = (command, args, options) => spawn(command, args, options);
|
|
93634
|
-
var CLI_ENTRY = fileURLToPath(new URL("../../bin/
|
|
93634
|
+
var CLI_ENTRY = fileURLToPath(new URL("../../bin/jjhub.mjs", import.meta.url));
|
|
93635
93635
|
function spawnDaemon(opts) {
|
|
93636
93636
|
const args = [
|
|
93637
93637
|
CLI_ENTRY,
|
|
@@ -93715,9 +93715,9 @@ var defaultSpawnGh = (argv) => new Promise((resolve, reject) => {
|
|
|
93715
93715
|
});
|
|
93716
93716
|
|
|
93717
93717
|
// src/cli/index.ts
|
|
93718
|
-
var USAGE = `
|
|
93718
|
+
var USAGE = `jjhub \u2014 GitHub CLI with Jujutsu-native superpowers (JJHub)
|
|
93719
93719
|
|
|
93720
|
-
Usage:
|
|
93720
|
+
Usage: jjhub <command> [args] [--repo owner/name|repoId] [--json]
|
|
93721
93721
|
|
|
93722
93722
|
repo init [owner/name] [--github-token pat]
|
|
93723
93723
|
create the JJHub overlay for this repo
|
|
@@ -93730,7 +93730,7 @@ Usage: jjh <command> [args] [--repo owner/name|repoId] [--json]
|
|
|
93730
93730
|
repo delete hard-delete (ops credential only \u2014 archive is the normal path)
|
|
93731
93731
|
|
|
93732
93732
|
user list list known users (identity is GitHub-federated;
|
|
93733
|
-
sign in with "
|
|
93733
|
+
sign in with "jjhub auth login")
|
|
93734
93734
|
|
|
93735
93735
|
change new <title> [--parent CHG-x] [--stack id]
|
|
93736
93736
|
change list
|
|
@@ -93777,7 +93777,7 @@ Usage: jjh <command> [args] [--repo owner/name|repoId] [--json]
|
|
|
93777
93777
|
slash-commands for ACP clients (Zed's agent panel, ...)
|
|
93778
93778
|
|
|
93779
93779
|
agents-md print an AGENTS.md section teaching coding agents to
|
|
93780
|
-
prefer
|
|
93780
|
+
prefer jjhub over raw git/gh (jjhub agents-md >> AGENTS.md)
|
|
93781
93781
|
|
|
93782
93782
|
sync push overlay state to GitHub
|
|
93783
93783
|
|
|
@@ -93800,9 +93800,9 @@ Usage: jjh <command> [args] [--repo owner/name|repoId] [--json]
|
|
|
93800
93800
|
spawn the same sync as a detached background process
|
|
93801
93801
|
daemon stop [alias]
|
|
93802
93802
|
daemon status [alias]
|
|
93803
|
-
omit alias to list every repo configured via "
|
|
93803
|
+
omit alias to list every repo configured via "jjhub daemon start"
|
|
93804
93804
|
|
|
93805
|
-
Anything else (pr, issue, ...) is passed through to gh. (
|
|
93805
|
+
Anything else (pr, issue, ...) is passed through to gh. (jjhub's own "auth" command
|
|
93806
93806
|
signs into the JJHub server \u2014 it uses your GitHub identity via the server's
|
|
93807
93807
|
GitHub App, but is separate from "gh auth".)
|
|
93808
93808
|
|
|
@@ -93937,7 +93937,7 @@ async function dispatch(ctx, pos, values) {
|
|
|
93937
93937
|
const requiredBearer = process.env.JJHUB_API_KEY ?? config2.apiKey ?? config2.token;
|
|
93938
93938
|
if (!requiredBearer) {
|
|
93939
93939
|
ctx.err(
|
|
93940
|
-
"warning: no credential configured (JJHUB_API_KEY /
|
|
93940
|
+
"warning: no credential configured (JJHUB_API_KEY / jjhub auth login) \u2014 serving MCP over HTTP without authentication; do not expose this port publicly"
|
|
93941
93941
|
);
|
|
93942
93942
|
}
|
|
93943
93943
|
const server = await serveMcpHttp2(ctx.api, port, { requiredBearer, log: ctx.out });
|
|
@@ -93992,7 +93992,7 @@ async function repoCmd(ctx, pos, values) {
|
|
|
93992
93992
|
const inferred = await ctx.resolveContext();
|
|
93993
93993
|
if (!inferred) {
|
|
93994
93994
|
ctx.err(
|
|
93995
|
-
"error: could not infer a GitHub repository from the current directory \u2014 run `
|
|
93995
|
+
"error: could not infer a GitHub repository from the current directory \u2014 run `jjhub repo init <owner/name>`"
|
|
93996
93996
|
);
|
|
93997
93997
|
return 1;
|
|
93998
93998
|
}
|
|
@@ -94034,7 +94034,7 @@ async function repoCmd(ctx, pos, values) {
|
|
|
94034
94034
|
}
|
|
94035
94035
|
if (sub === "members") {
|
|
94036
94036
|
ctx.err(
|
|
94037
|
-
"error: `
|
|
94037
|
+
"error: `jjhub repo members` was removed \u2014 repo access now derives live from GitHub collaborator permissions (manage collaborators on GitHub itself; see issue #43)"
|
|
94038
94038
|
);
|
|
94039
94039
|
return 1;
|
|
94040
94040
|
}
|
|
@@ -94059,7 +94059,7 @@ async function userCmd(ctx, pos) {
|
|
|
94059
94059
|
}
|
|
94060
94060
|
if (sub === "create" || sub === "token" || sub === "tokens" || sub === "revoke-token") {
|
|
94061
94061
|
ctx.err(
|
|
94062
|
-
`error: \`
|
|
94062
|
+
`error: \`jjhub user ${sub}\` was removed \u2014 identity is GitHub-federated now. Sign in with \`jjhub auth login\` (device flow); tokens come from the OAuth flow (issue #43).`
|
|
94063
94063
|
);
|
|
94064
94064
|
return 1;
|
|
94065
94065
|
}
|
|
@@ -94525,7 +94525,7 @@ async function authCmd(ctx, pos, values) {
|
|
|
94525
94525
|
throw e;
|
|
94526
94526
|
}
|
|
94527
94527
|
}
|
|
94528
|
-
ctx.err("error: sign-in timed out \u2014 run `
|
|
94528
|
+
ctx.err("error: sign-in timed out \u2014 run `jjhub auth login` again");
|
|
94529
94529
|
return 1;
|
|
94530
94530
|
}
|
|
94531
94531
|
if (sub === "sessions") {
|
|
@@ -94582,7 +94582,7 @@ async function authCmd(ctx, pos, values) {
|
|
|
94582
94582
|
});
|
|
94583
94583
|
}
|
|
94584
94584
|
ctx.out(
|
|
94585
|
-
`connected to ${ctx.api.baseUrl} (${repos.length} repositor${repos.length === 1 ? "y" : "ies"}, no user identity \u2014 sign in with \`
|
|
94585
|
+
`connected to ${ctx.api.baseUrl} (${repos.length} repositor${repos.length === 1 ? "y" : "ies"}, no user identity \u2014 sign in with \`jjhub auth login\`)`
|
|
94586
94586
|
);
|
|
94587
94587
|
return 0;
|
|
94588
94588
|
} catch {
|
|
@@ -94669,7 +94669,7 @@ async function resolveDaemonTarget(ctx, aliasOrPath, registerIfMissing) {
|
|
|
94669
94669
|
const entry = config2.repos?.[aliasOrPath];
|
|
94670
94670
|
if (!entry) {
|
|
94671
94671
|
return {
|
|
94672
|
-
error: `no configured repo alias "${aliasOrPath}" \u2014 run \`
|
|
94672
|
+
error: `no configured repo alias "${aliasOrPath}" \u2014 run \`jjhub daemon start <path>\` from that repo directory first`
|
|
94673
94673
|
};
|
|
94674
94674
|
}
|
|
94675
94675
|
return { repositoryId: entry.repositoryId, localPath: entry.localPath, alias: aliasOrPath };
|
|
@@ -94759,7 +94759,7 @@ async function daemonStatusCmd(ctx, rest) {
|
|
|
94759
94759
|
ctx.err(`error: no configured repo alias "${aliasOrPath}"`);
|
|
94760
94760
|
return 1;
|
|
94761
94761
|
}
|
|
94762
|
-
ctx.out("no repos configured \u2014 run `
|
|
94762
|
+
ctx.out("no repos configured \u2014 run `jjhub daemon start` from a repo directory first");
|
|
94763
94763
|
return 0;
|
|
94764
94764
|
}
|
|
94765
94765
|
const rows = [];
|
|
@@ -94842,7 +94842,7 @@ function emitJson(ctx, value) {
|
|
|
94842
94842
|
return 0;
|
|
94843
94843
|
}
|
|
94844
94844
|
function usageError(ctx, usage) {
|
|
94845
|
-
ctx.err(`usage:
|
|
94845
|
+
ctx.err(`usage: jjhub ${usage}`);
|
|
94846
94846
|
return 1;
|
|
94847
94847
|
}
|
|
94848
94848
|
var invokedDirectly = (() => {
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jjhub",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "jjhub — GitHub CLI with Jujutsu-native superpowers: stable change IDs, stacks, platform-wide undo, and conflicts that wait, layered over plain GitHub repos by a JJHub server.",
|
|
5
5
|
"bin": {
|
|
6
|
-
"jjhub": "./dist/cli/
|
|
7
|
-
"jjh": "./dist/cli/jjh.mjs"
|
|
6
|
+
"jjhub": "./dist/cli/jjhub.mjs"
|
|
8
7
|
},
|
|
9
8
|
"type": "module",
|
|
10
9
|
"engines": {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jjhub-cli
|
|
3
|
-
description: Drive a running JJHub instance from the command line with the `
|
|
3
|
+
description: Drive a running JJHub instance from the command line with the `jjhub` CLI — create and land changes, manage stacks and bookmarks, resolve conflicts, and undo/redo via the operation log. Use when scripting or automating repository operations against a JJHub server instead of the web UI.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# jjhub — the JJHub CLI
|
|
7
7
|
|
|
8
|
-
`
|
|
8
|
+
`jjhub` is a GitHub CLI (`gh`)-like wrapper with Jujutsu-native superpowers. It is a thin
|
|
9
9
|
client over JJHub's HTTP API: every command reads or mutates state on a running JJHub
|
|
10
10
|
server, the same server backing the web UI. Repo context is inferred from the current
|
|
11
11
|
directory's git `origin` remote (override with `--repo`), and any top-level command that
|
|
12
|
-
isn't one of `
|
|
12
|
+
isn't one of `jjhub`'s own nouns is passed straight through to the real `gh` binary.
|
|
13
13
|
|
|
14
14
|
## Setup
|
|
15
15
|
|
|
@@ -22,12 +22,12 @@ tests, requirements). This section covers just the CLI.
|
|
|
22
22
|
2. **Point the CLI at it**: `export JJHUB_URL=http://localhost:3000` (this is the default,
|
|
23
23
|
so only needed if the server is elsewhere). If the server was started with
|
|
24
24
|
`JJHUB_API_KEY` set, also `export JJHUB_API_KEY=<the same key>` — every request will
|
|
25
|
-
otherwise get a `401 unauthorized`. (`
|
|
25
|
+
otherwise get a `401 unauthorized`. (`jjhub auth login` persists these to a config file
|
|
26
26
|
instead of needing them exported every shell — see "Server connection" below.)
|
|
27
|
-
3. **Invoke commands**: `npm run
|
|
28
|
-
directly if installed as a binary (`bin/
|
|
27
|
+
3. **Invoke commands**: `npm run jjhub -- <command> [args]` in development, or `jjhub <command>`
|
|
28
|
+
directly if installed as a binary (`bin/jjhub.mjs`).
|
|
29
29
|
4. **Initialize the overlay** for a repo before using any other command:
|
|
30
|
-
`
|
|
30
|
+
`jjhub repo init [owner/name]` (infers `owner/name` from the cwd's git origin if omitted).
|
|
31
31
|
|
|
32
32
|
The same JJHub server also backs a web UI (`npm run web:dev` from the repo root, in a
|
|
33
33
|
second terminal — see [`web/README.md`](../../web/README.md)); the CLI and the web UI are
|
|
@@ -104,7 +104,7 @@ mcp serve --http <port> the same tools over Streamable HTTP (POST
|
|
|
104
104
|
acp serve Agent Client Protocol agent over stdio (Zed's agent
|
|
105
105
|
panel, ...) — every operation as a slash command
|
|
106
106
|
agents-md print an AGENTS.md section teaching coding agents to
|
|
107
|
-
prefer
|
|
107
|
+
prefer jjhub over raw git/gh (jjhub agents-md >> AGENTS.md)
|
|
108
108
|
|
|
109
109
|
daemon <localRepoPath> [--once] [--interval 5] [--engine auto|subprocess|isomorphic] [--two-way]
|
|
110
110
|
sync a local jj working copy into JJHub (inbound; --two-way mirrors JJHub edits back)
|
|
@@ -113,22 +113,22 @@ daemon start [alias|localRepoPath] [--interval 5] [--engine ...] [--two-way]
|
|
|
113
113
|
daemon stop [alias] | daemon status [alias]
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
Anything else (`pr`, `issue`, ...) is passed through to `gh` — e.g. `
|
|
117
|
-
is
|
|
116
|
+
Anything else (`pr`, `issue`, ...) is passed through to `gh` — e.g. `jjhub pr view 7`. `jjhub auth`
|
|
117
|
+
is jjhub's own command (it manages the *JJHub server* connection); use `gh auth` for GitHub auth.
|
|
118
118
|
|
|
119
119
|
### Server connection: flags, env vars, or a config file
|
|
120
120
|
|
|
121
121
|
Precedence is `--flag` > env var (`JJHUB_URL`/`JJHUB_API_KEY`) > `~/.config/jjhub/config.json`
|
|
122
|
-
(written by `
|
|
122
|
+
(written by `jjhub auth login`). Run `jjhub auth login --url http://localhost:3000 --api-key <key>`
|
|
123
123
|
once and every subsequent command in that shell (any shell, any day) picks it up with no env
|
|
124
|
-
vars needed. `
|
|
124
|
+
vars needed. `jjhub auth status` confirms what's currently in effect.
|
|
125
125
|
|
|
126
126
|
### Identity & permissions (issue #43: GitHub-federated)
|
|
127
127
|
|
|
128
|
-
A JJHub user IS a GitHub account. `
|
|
128
|
+
A JJHub user IS a GitHub account. `jjhub auth login` runs an OAuth device flow against the
|
|
129
129
|
JJHub server's own authorization server: open the printed URL, sign in with GitHub, confirm
|
|
130
130
|
the code, and the CLI saves a JJHub-issued OAuth token. Every mutation is attributed to that
|
|
131
|
-
identity (visible in `
|
|
131
|
+
identity (visible in `jjhub op log`).
|
|
132
132
|
|
|
133
133
|
What you can do on a repo is asked of GitHub LIVE at request time (cached ~60s):
|
|
134
134
|
GitHub `admin` → owner, `maintain`/`write` → writer, `triage`/`read` → reader. There is no
|
|
@@ -142,26 +142,26 @@ credential: full access, RBAC bypassed, no attribution. Anonymous requests (no s
|
|
|
142
142
|
|
|
143
143
|
This RBAC is entirely JJHub-internal — a JJHub "owner" isn't checked against real GitHub
|
|
144
144
|
permissions at all. If the server has `JJHUB_REQUIRE_GITHUB_VERIFICATION=1` set,
|
|
145
|
-
`
|
|
145
|
+
`jjhub repo init` requires `--github-token <pat>` (or falls back to `$GITHUB_TOKEN`): the
|
|
146
146
|
server verifies that token has real `admin` access to the exact `owner/name` being created
|
|
147
147
|
via a live GitHub API call, rejecting creation (403) otherwise. The verified token also
|
|
148
148
|
becomes the new repo's GitHub connection automatically. See the top-level README's "GitHub
|
|
149
149
|
admin verification (optional mode)" section.
|
|
150
150
|
|
|
151
|
-
For exact, always-current syntax straight from the CLI binary, run `
|
|
151
|
+
For exact, always-current syntax straight from the CLI binary, run `jjhub help` — this file is
|
|
152
152
|
an expanded, example-rich companion to that output, not a replacement for it.
|
|
153
153
|
|
|
154
|
-
### Install into your repo (teach YOUR coding agents to prefer
|
|
154
|
+
### Install into your repo (teach YOUR coding agents to prefer jjhub)
|
|
155
155
|
|
|
156
156
|
[`agents-snippet.md`](./agents-snippet.md) is a short, imperative AGENTS.md
|
|
157
|
-
section — "version control in this repo goes through JJHub; prefer `
|
|
157
|
+
section — "version control in this repo goes through JJHub; prefer `jjhub
|
|
158
158
|
change/stack/undo` over raw git/gh mutations" — the same pattern as GitHub's
|
|
159
159
|
`gh skill install github/gh-stack`. Append it to a tracked repo's own
|
|
160
160
|
AGENTS.md so any AGENTS.md-aware coding agent (Claude Code, Copilot, Cursor,
|
|
161
161
|
Codex, ...) picks up the workflow automatically:
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
|
-
|
|
164
|
+
jjhub agents-md >> AGENTS.md # from the CLI
|
|
165
165
|
# or fetch it from a running server:
|
|
166
166
|
curl https://<your-jjhub>/.well-known/skills/jjhub-cli/agents-snippet.md >> AGENTS.md
|
|
167
167
|
```
|
|
@@ -171,14 +171,14 @@ curl https://<your-jjhub>/.well-known/skills/jjhub-cli/agents-snippet.md >> AGEN
|
|
|
171
171
|
### Create and land a change
|
|
172
172
|
|
|
173
173
|
```bash
|
|
174
|
-
npm run
|
|
175
|
-
npm run
|
|
176
|
-
npm run
|
|
177
|
-
npm run
|
|
178
|
-
npm run
|
|
174
|
+
npm run jjhub -- repo init owner/name
|
|
175
|
+
npm run jjhub -- change new "Fix: add user validation"
|
|
176
|
+
npm run jjhub -- change list # note the CHG-n id
|
|
177
|
+
npm run jjhub -- stack create "Fix bundle" --changes CHG-1
|
|
178
|
+
npm run jjhub -- stack land "Fix bundle"
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
-
A single change not part of a stack lands directly: `npm run
|
|
181
|
+
A single change not part of a stack lands directly: `npm run jjhub -- change land CHG-1`.
|
|
182
182
|
|
|
183
183
|
### Sync a local jj working copy into JJHub
|
|
184
184
|
|
|
@@ -188,22 +188,22 @@ jj bookmark track main --remote=origin # REQUIRED once per clone (issue #28):
|
|
|
188
188
|
# without it, already-landed commits look
|
|
189
189
|
# like new local work and the daemon could
|
|
190
190
|
# try to re-project them
|
|
191
|
-
npm run
|
|
191
|
+
npm run jjhub -- repo init alice/my-project
|
|
192
192
|
jj new -m "Implement feature X" && jj commit
|
|
193
|
-
npm run
|
|
194
|
-
npm run
|
|
193
|
+
npm run jjhub -- daemon . --once # one-shot sync; omit --once to loop every 5s
|
|
194
|
+
npm run jjhub -- op log # verify the sync landed as a new operation
|
|
195
195
|
```
|
|
196
196
|
|
|
197
197
|
### Resolve a conflict
|
|
198
198
|
|
|
199
199
|
```bash
|
|
200
|
-
npm run
|
|
201
|
-
npm run
|
|
202
|
-
npm run
|
|
200
|
+
npm run jjhub -- conflict list # note the conflict id
|
|
201
|
+
npm run jjhub -- conflict resolve CONFLICT-abc123 left # or: right | edited | preserve_unresolved
|
|
202
|
+
npm run jjhub -- conflict list # confirm it now reads Resolved
|
|
203
203
|
```
|
|
204
204
|
|
|
205
205
|
## Undo/redo caution
|
|
206
206
|
|
|
207
|
-
`
|
|
207
|
+
`jjhub undo` and `jjhub redo` move the repository's operation-log head pointer — they affect
|
|
208
208
|
*all* state (changes, stacks, bookmarks, conflicts), not just the last command's target.
|
|
209
|
-
Run `
|
|
209
|
+
Run `jjhub op log` first if you're not sure what the current head operation is before undoing.
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
# Version control in this repo goes through JJHub
|
|
2
2
|
|
|
3
3
|
This repository is tracked by JJHub (a change/stack/operation overlay on
|
|
4
|
-
GitHub). Use the `
|
|
5
|
-
`git`/`gh` — every `
|
|
6
|
-
reversible with `
|
|
4
|
+
GitHub). Use the `jjhub` CLI for version-control mutations instead of raw
|
|
5
|
+
`git`/`gh` — every `jjhub` action is attributed in an operation log and
|
|
6
|
+
reversible with `jjhub undo`, and landing is CI-gated.
|
|
7
7
|
|
|
8
|
-
- Start work: `
|
|
9
|
-
- Describe/retitle: `
|
|
10
|
-
- Amend after edits: `
|
|
8
|
+
- Start work: `jjhub change new "<title>"` (not a git branch).
|
|
9
|
+
- Describe/retitle: `jjhub change describe CHG-N --title t --description d`.
|
|
10
|
+
- Amend after edits: `jjhub change amend CHG-N` (descendants get flagged and
|
|
11
11
|
restack with one command — no force-push ceremony).
|
|
12
|
-
- Stacked work: `
|
|
13
|
-
reorder with `
|
|
14
|
-
`
|
|
15
|
-
- Ship a single change: `
|
|
12
|
+
- Stacked work: `jjhub stack create "<title>" --changes CHG-1,CHG-2`;
|
|
13
|
+
reorder with `jjhub stack reorder`; land root-to-tip with
|
|
14
|
+
`jjhub stack land <stackId>` (all-or-nothing, CI-gated).
|
|
15
|
+
- Ship a single change: `jjhub change land CHG-N`. Do NOT merge the PR with
|
|
16
16
|
`gh pr merge` — that bypasses the gate and the op log.
|
|
17
|
-
- Made a mistake: `
|
|
18
|
-
conflicts; `
|
|
19
|
-
- Conflicts: `
|
|
17
|
+
- Made a mistake: `jjhub undo` (works across changes, stacks, bookmarks, and
|
|
18
|
+
conflicts; `jjhub op log` shows what would be undone).
|
|
19
|
+
- Conflicts: `jjhub conflict list` / `jjhub conflict resolve <id> <state>` —
|
|
20
20
|
conflicts are durable objects; you can defer them and keep working.
|
|
21
21
|
- Machine output: append `--json` to any command.
|
|
22
22
|
- Repo context is inferred from the git `origin` remote; `--repo owner/name`
|
|
23
23
|
overrides.
|
|
24
24
|
|
|
25
|
-
Reads are fine with either tool. Any `
|
|
25
|
+
Reads are fine with either tool. Any `jjhub` command it doesn't recognize
|
|
26
26
|
(`pr`, `issue`, ...) passes through to the real `gh` unchanged. Full command
|
|
27
|
-
reference: run `
|
|
27
|
+
reference: run `jjhub help`, or see the served skill at
|
|
28
28
|
`/.well-known/skills/jjhub-cli/SKILL.md` on your JJHub server.
|