jj-octo 0.9.0 → 0.9.1
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 +2 -2
- package/dist/jj-octo.js +109 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,10 +42,10 @@ With `jj-octo.github-auth` set to `git-proxy`, it sends a placeholder token inst
|
|
|
42
42
|
|
|
43
43
|
A Claude Code [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web) runs in an Anthropic-hosted environment, or in your organization's self-hosted environment. Each needs its own setup.
|
|
44
44
|
|
|
45
|
-
The session's GitHub proxy can append a "Generated by Claude Code" footer to each pull request body that it creates or edits. `jj gh submit` would read the footer as an edit made on GitHub, and write it into the change.
|
|
45
|
+
The session's GitHub proxy can append a "Generated by Claude Code" footer to each pull request body that it creates or edits. `jj gh submit` would read the footer as an edit made on GitHub, and write it into the change. So where `CLAUDE_CODE_REMOTE` is `true`, as in a cloud session, `submit` leaves the footer out when it compares a pull request's body with its change's description. `jj-octo.ignore-claude-code-footer` overrides that: set it to `true` to leave the footer out elsewhere, or to `false` to keep it in a cloud session:
|
|
46
46
|
|
|
47
47
|
```
|
|
48
|
-
jj config set --repo jj-octo.ignore-claude-code-footer
|
|
48
|
+
jj config set --repo jj-octo.ignore-claude-code-footer false
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
### In an Anthropic-hosted environment
|
package/dist/jj-octo.js
CHANGED
|
@@ -1670,6 +1670,27 @@ var match2 = /* @__PURE__ */ dual(2, (self, {
|
|
|
1670
1670
|
onFailure,
|
|
1671
1671
|
onSuccess
|
|
1672
1672
|
}) => isFailure2(self) ? onFailure(self.failure) : onSuccess(self.success));
|
|
1673
|
+
var all = (input) => {
|
|
1674
|
+
if (Symbol.iterator in input) {
|
|
1675
|
+
const out = [];
|
|
1676
|
+
for (const e of input) {
|
|
1677
|
+
if (isFailure2(e)) {
|
|
1678
|
+
return e;
|
|
1679
|
+
}
|
|
1680
|
+
out.push(e.success);
|
|
1681
|
+
}
|
|
1682
|
+
return succeed2(out);
|
|
1683
|
+
}
|
|
1684
|
+
const out = {};
|
|
1685
|
+
for (const key of Object.keys(input)) {
|
|
1686
|
+
const e = input[key];
|
|
1687
|
+
if (isFailure2(e)) {
|
|
1688
|
+
return e;
|
|
1689
|
+
}
|
|
1690
|
+
assignProperty(out, key, e.success);
|
|
1691
|
+
}
|
|
1692
|
+
return succeed2(out);
|
|
1693
|
+
};
|
|
1673
1694
|
|
|
1674
1695
|
// node_modules/effect/dist/Tuple.js
|
|
1675
1696
|
var makeEquivalence = Tuple;
|
|
@@ -3812,7 +3833,7 @@ var uninterruptibleMask = (f) => withFiber((fiber) => {
|
|
|
3812
3833
|
fiber._stack.push(setInterruptibleTrue);
|
|
3813
3834
|
return f(interruptible);
|
|
3814
3835
|
});
|
|
3815
|
-
var
|
|
3836
|
+
var all2 = (arg, options) => {
|
|
3816
3837
|
if (isIterable(arg)) {
|
|
3817
3838
|
return options?.mode === "result" ? forEach(arg, result, options) : forEach(arg, identity, options);
|
|
3818
3839
|
} else if (options?.discard) {
|
|
@@ -4985,7 +5006,7 @@ var buildFromOptions = (options) => {
|
|
|
4985
5006
|
|
|
4986
5007
|
// node_modules/effect/dist/Effect.js
|
|
4987
5008
|
var isEffect2 = isEffect;
|
|
4988
|
-
var
|
|
5009
|
+
var all3 = all2;
|
|
4989
5010
|
var forEach2 = forEach;
|
|
4990
5011
|
var whileLoop2 = whileLoop;
|
|
4991
5012
|
var promise2 = promise;
|
|
@@ -10000,7 +10021,7 @@ var watchNode = (path, info, options) => callback3((queue) => acquireRelease2(sy
|
|
|
10000
10021
|
});
|
|
10001
10022
|
return watcher;
|
|
10002
10023
|
}), (watcher) => sync2(() => watcher.close())).pipe(tap2(() => sync2(() => options?.onReady?.()))));
|
|
10003
|
-
var watch2 = (backend, path, options) =>
|
|
10024
|
+
var watch2 = (backend, path, options) => all3([stat2(path), serviceOption2(WatchBackend)]).pipe(map7(([stat, callerBackend]) => orElse(callerBackend, () => backend).pipe(flatMap((_) => _.register(path, stat, options)), getOrElse(() => watchNode(path, stat, options)))), unwrap4);
|
|
10004
10025
|
var writeFile2 = (path, data, options) => callback2((resume, signal) => {
|
|
10005
10026
|
try {
|
|
10006
10027
|
NFS.writeFile(path, data, {
|
|
@@ -12232,6 +12253,10 @@ var orElse2 = /* @__PURE__ */ dual(2, (self, that) => {
|
|
|
12232
12253
|
onSuccess: (resolution) => isFailure2(resolution) ? evaluateAt(that(resolution.failure), provider, pathPrefix) : succeed6(resolution)
|
|
12233
12254
|
}));
|
|
12234
12255
|
});
|
|
12256
|
+
function all4(arg) {
|
|
12257
|
+
const configs = globalThis.Array.isArray(arg) ? arg : (Symbol.iterator in arg) ? [...arg] : arg;
|
|
12258
|
+
return make30((provider, pathPrefix) => globalThis.Array.isArray(configs) ? mapEager2(all3(configs.map((config) => evaluateAt(config, provider, pathPrefix))), all) : mapEager2(all3(map3(configs, (config) => evaluateAt(config, provider, pathPrefix))), all));
|
|
12259
|
+
}
|
|
12235
12260
|
var withDefault3 = /* @__PURE__ */ dual(2, (self, defaultValue) => {
|
|
12236
12261
|
return make30((provider, pathPrefix) => mapEager2(evaluateAt(self, provider, pathPrefix), (resolution) => isFailure2(resolution) ? succeed2(defaultValue) : resolution));
|
|
12237
12262
|
});
|
|
@@ -12355,6 +12380,9 @@ function schema(codec, path) {
|
|
|
12355
12380
|
}))), mapReasons((reason) => isDieReason2(reason) && isSourceError(reason.defect) ? makeFailReason(new ConfigError(reason.defect)).annotate(reasonAnnotations2(reason)) : reason));
|
|
12356
12381
|
});
|
|
12357
12382
|
}
|
|
12383
|
+
function String5(name) {
|
|
12384
|
+
return schema(String4, name);
|
|
12385
|
+
}
|
|
12358
12386
|
function Redacted2(name) {
|
|
12359
12387
|
return schema(Redacted(String4), name);
|
|
12360
12388
|
}
|
|
@@ -12632,7 +12660,7 @@ var makeSchemaPrimitive = (tag, schema) => {
|
|
|
12632
12660
|
return makePrimitive2(tag, (value) => mapError3(decode(value), (error) => error.message));
|
|
12633
12661
|
};
|
|
12634
12662
|
var Boolean4 = /* @__PURE__ */ makeSchemaPrimitive("Boolean", BooleanLiterals);
|
|
12635
|
-
var
|
|
12663
|
+
var String6 = /* @__PURE__ */ makePrimitive2("String", (value) => succeed6(value));
|
|
12636
12664
|
var Choice = (choices) => {
|
|
12637
12665
|
const choiceMap = new Map(choices);
|
|
12638
12666
|
const validChoices = choices.map(([key]) => format(key)).join(" | ");
|
|
@@ -12975,7 +13003,7 @@ var succeed9 = (value) => {
|
|
|
12975
13003
|
op.value = value;
|
|
12976
13004
|
return op;
|
|
12977
13005
|
};
|
|
12978
|
-
var
|
|
13006
|
+
var String7 = (options) => basePrompt(options, "text");
|
|
12979
13007
|
var Toggle = (options) => {
|
|
12980
13008
|
const opts = {
|
|
12981
13009
|
initial: false,
|
|
@@ -14431,9 +14459,9 @@ var makeSingle2 = (params) => {
|
|
|
14431
14459
|
parse
|
|
14432
14460
|
}, Proto10);
|
|
14433
14461
|
};
|
|
14434
|
-
var
|
|
14462
|
+
var String8 = (kind, name) => makeSingle2({
|
|
14435
14463
|
name,
|
|
14436
|
-
primitiveType:
|
|
14464
|
+
primitiveType: String6,
|
|
14437
14465
|
kind
|
|
14438
14466
|
});
|
|
14439
14467
|
var Boolean5 = (kind, name) => makeSingle2({
|
|
@@ -16234,7 +16262,7 @@ var generate5 = (executableName, shell, descriptor) => {
|
|
|
16234
16262
|
};
|
|
16235
16263
|
|
|
16236
16264
|
// node_modules/effect/dist/cli/Flag.js
|
|
16237
|
-
var
|
|
16265
|
+
var String9 = (name) => String8(flagKind, name);
|
|
16238
16266
|
var Boolean6 = (name) => Boolean5(flagKind, name);
|
|
16239
16267
|
var ChoiceWithValue2 = (name, choices) => ChoiceWithValue(flagKind, name, choices);
|
|
16240
16268
|
var withAlias2 = /* @__PURE__ */ dual(2, (self, alias) => withAlias(self, alias));
|
|
@@ -17190,7 +17218,7 @@ var promptSingle = (single) => {
|
|
|
17190
17218
|
message
|
|
17191
17219
|
})), (value) => commandLineArg(value2(value), "<redacted>"));
|
|
17192
17220
|
default:
|
|
17193
|
-
return map7(run3(
|
|
17221
|
+
return map7(run3(String7({
|
|
17194
17222
|
message
|
|
17195
17223
|
})), commandLineArg);
|
|
17196
17224
|
}
|
|
@@ -18292,7 +18320,7 @@ var layer14 = /* @__PURE__ */ layerMergedContext(/* @__PURE__ */ succeed6(fetch)
|
|
|
18292
18320
|
// package.json
|
|
18293
18321
|
var package_default = {
|
|
18294
18322
|
name: "jj-octo",
|
|
18295
|
-
version: "0.9.
|
|
18323
|
+
version: "0.9.1",
|
|
18296
18324
|
description: "A jj subcommand for GitHub that supports stacked pull requests and works in Claude Code cloud sessions",
|
|
18297
18325
|
license: "MIT",
|
|
18298
18326
|
repository: {
|
|
@@ -18346,7 +18374,7 @@ var asUserError = (program) => program.pipe(mapError3(({ message }) => userError
|
|
|
18346
18374
|
var withHelp = (summary, ...paragraphs) => (command) => command.pipe(withShortDescription(summary), withDescription3([summary, ...paragraphs].join(`
|
|
18347
18375
|
|
|
18348
18376
|
`)));
|
|
18349
|
-
var revisionFlag = (description) =>
|
|
18377
|
+
var revisionFlag = (description) => String9("revision").pipe(withAlias2("r"), withDefault5("@"), withDescription2(`${description}, the working copy by default`));
|
|
18350
18378
|
// src/clients/git.ts
|
|
18351
18379
|
class GitFailed extends TaggedError2("GitFailed") {
|
|
18352
18380
|
}
|
|
@@ -18364,7 +18392,7 @@ var gitLayer = ({ cwd, env } = {}) => effect(Git, gen2(function* () {
|
|
|
18364
18392
|
`, github: `${remote}
|
|
18365
18393
|
`, local: `${local}
|
|
18366
18394
|
` };
|
|
18367
|
-
yield*
|
|
18395
|
+
yield* all3(Object.entries(written).map(([name, text]) => fs.writeFileString(path.join(directory, name), text)));
|
|
18368
18396
|
const handle = yield* spawner.spawn(make16("git", [
|
|
18369
18397
|
"merge-file",
|
|
18370
18398
|
"-p",
|
|
@@ -18378,7 +18406,7 @@ var gitLayer = ({ cwd, env } = {}) => effect(Git, gen2(function* () {
|
|
|
18378
18406
|
"base",
|
|
18379
18407
|
"github"
|
|
18380
18408
|
], { cwd: directory }));
|
|
18381
|
-
const [text, stderr, code] = yield*
|
|
18409
|
+
const [text, stderr, code] = yield* all3([
|
|
18382
18410
|
mkString(decodeText(handle.stdout)),
|
|
18383
18411
|
mkString(decodeText(handle.stderr)),
|
|
18384
18412
|
handle.exitCode
|
|
@@ -18390,7 +18418,7 @@ var gitLayer = ({ cwd, env } = {}) => effect(Git, gen2(function* () {
|
|
|
18390
18418
|
})).pipe(catchTag2("PlatformError", (error) => fail6(new GitFailed({ message: `git merge-file failed: ${error.message}` })))),
|
|
18391
18419
|
read: (args) => scoped2(gen2(function* () {
|
|
18392
18420
|
const handle = yield* spawner.spawn(make16("git", args, { cwd, env, extendEnv: true }));
|
|
18393
|
-
const [stdout, stderr, code] = yield*
|
|
18421
|
+
const [stdout, stderr, code] = yield* all3([
|
|
18394
18422
|
mkString(decodeText(handle.stdout)),
|
|
18395
18423
|
mkString(decodeText(handle.stderr)),
|
|
18396
18424
|
handle.exitCode
|
|
@@ -18435,7 +18463,7 @@ var jjLayer = ({ cwd, env, printed } = {}) => effect(Jj, gen2(function* () {
|
|
|
18435
18463
|
const location2 = { cwd, env, extendEnv: true };
|
|
18436
18464
|
const captured = (args) => scoped2(gen2(function* () {
|
|
18437
18465
|
const handle = yield* spawner.spawn(make16("jj", args, location2));
|
|
18438
|
-
return yield*
|
|
18466
|
+
return yield* all3([
|
|
18439
18467
|
mkString(decodeText(handle.stdout)),
|
|
18440
18468
|
mkString(decodeText(handle.stderr)),
|
|
18441
18469
|
handle.exitCode
|
|
@@ -18476,10 +18504,13 @@ var jjConfig = (key) => gen2(function* () {
|
|
|
18476
18504
|
message: `${key} is ${JSON.stringify(value)}; set it to a string`
|
|
18477
18505
|
});
|
|
18478
18506
|
});
|
|
18479
|
-
var jjFlag = (key) => gen2(function* () {
|
|
18507
|
+
var jjFlag = (key, fallback = false) => gen2(function* () {
|
|
18480
18508
|
const value = yield* readJjConfig(key);
|
|
18481
|
-
if (value === undefined
|
|
18482
|
-
return
|
|
18509
|
+
if (value === undefined) {
|
|
18510
|
+
return fallback;
|
|
18511
|
+
}
|
|
18512
|
+
if (typeof value === "boolean") {
|
|
18513
|
+
return value;
|
|
18483
18514
|
}
|
|
18484
18515
|
return yield* new JjFailed({
|
|
18485
18516
|
message: `${key} is ${JSON.stringify(value)}; set it to true or false`
|
|
@@ -18891,6 +18922,9 @@ var init = gen2(function* () {
|
|
|
18891
18922
|
});
|
|
18892
18923
|
var initCommand = make32("init", {}, () => asUserError(init)).pipe(withHelp("Set up a git checkout for the other commands", "Makes it a jj repository colocated with git, unless it already is one, and copies git's name and email into the repository's jj config where jj has none. Where neither has them, set them with `jj config set --user`.", "Reads the default branch from `origin`, fetches and tracks it, and sets `trunk()` to it in the repository's config. jj's own `trunk()` guesses from branch names, so without this a default branch it doesn't guess would be the base of pull requests but not of local rebases. `submit`, `merge` and `sync` check that the two agree.", "Sets the `jj gh` alias to run `jj-octo` from `PATH`, in the repository's config, unless the repository has one, such as one that runs another build.", "Needs no GitHub token. Running it again changes nothing that is already set up. Run it again after the default branch changes on GitHub. Fails with what it couldn't set up, after setting up the rest. Where it can't make a colocated jj repository, such as in a git worktree, it sets up nothing else."));
|
|
18893
18924
|
|
|
18925
|
+
// src/clients/claude-code.ts
|
|
18926
|
+
var claudeCodeCloudSession = orDie2(String5("CLAUDE_CODE_REMOTE").pipe(withDefault3(""), map10((value) => value === "true")));
|
|
18927
|
+
|
|
18894
18928
|
// src/clients/clipboard.ts
|
|
18895
18929
|
class ClipboardFailed extends TaggedError2("ClipboardFailed") {
|
|
18896
18930
|
}
|
|
@@ -18909,50 +18943,62 @@ function run([html, text]) {
|
|
|
18909
18943
|
throw new Error("the pasteboard didn't take the links");
|
|
18910
18944
|
}
|
|
18911
18945
|
}`;
|
|
18912
|
-
var
|
|
18913
|
-
|
|
18914
|
-
|
|
18915
|
-
|
|
18916
|
-
|
|
18917
|
-
extendEnv: true,
|
|
18918
|
-
stdout: "ignore",
|
|
18919
|
-
...input === "stdin" ? { stderr: "ignore", stdin: make12(html).pipe(encodeText) } : { stderr: "inherit", stdin: "ignore" }
|
|
18920
|
-
}),
|
|
18921
|
-
name
|
|
18922
|
-
});
|
|
18946
|
+
var environment = all4({
|
|
18947
|
+
path: String5("PATH").pipe(withDefault3("")),
|
|
18948
|
+
wayland: String5("WAYLAND_DISPLAY").pipe(withDefault3(""))
|
|
18949
|
+
});
|
|
18950
|
+
var commandsFor = ({ html, text }, platform, wayland) => {
|
|
18923
18951
|
if (platform === "darwin") {
|
|
18924
|
-
return [
|
|
18952
|
+
return [
|
|
18953
|
+
{
|
|
18954
|
+
args: ["-l", "JavaScript", "-e", MACOS_SCRIPT, html, text],
|
|
18955
|
+
input: "arguments",
|
|
18956
|
+
name: "osascript"
|
|
18957
|
+
}
|
|
18958
|
+
];
|
|
18925
18959
|
}
|
|
18926
18960
|
if (platform !== "linux") {
|
|
18927
18961
|
return [];
|
|
18928
18962
|
}
|
|
18929
|
-
const xclip =
|
|
18930
|
-
|
|
18931
|
-
|
|
18963
|
+
const xclip = {
|
|
18964
|
+
args: ["-selection", "clipboard", "-t", "text/html"],
|
|
18965
|
+
input: "stdin",
|
|
18966
|
+
name: "xclip"
|
|
18967
|
+
};
|
|
18968
|
+
return wayland === "" ? [xclip] : [{ args: ["--type", "text/html"], input: "stdin", name: "wl-copy" }, xclip];
|
|
18932
18969
|
};
|
|
18933
|
-
var
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
18970
|
+
var childProcess = ({ args, input }, executable, html) => make16(executable, args, {
|
|
18971
|
+
detached: false,
|
|
18972
|
+
stdout: "ignore",
|
|
18973
|
+
...input === "stdin" ? { stderr: "ignore", stdin: make12(html).pipe(encodeText) } : { stderr: "inherit", stdin: "ignore" }
|
|
18974
|
+
});
|
|
18975
|
+
var clipboardLayer = ({ platform = process.platform } = {}) => effect(Clipboard, gen2(function* () {
|
|
18976
|
+
const { path, wayland } = yield* orDie2(environment);
|
|
18977
|
+
if (yield* claudeCodeCloudSession) {
|
|
18978
|
+
return Clipboard.of({ write: () => succeed6("unreachable") });
|
|
18979
|
+
}
|
|
18937
18980
|
const spawner = yield* ChildProcessSpawner;
|
|
18938
|
-
return {
|
|
18981
|
+
return Clipboard.of({
|
|
18939
18982
|
write: (content) => {
|
|
18940
|
-
const commands = commandsFor(content, platform,
|
|
18983
|
+
const commands = commandsFor(content, platform, wayland);
|
|
18941
18984
|
if (commands.length === 0) {
|
|
18942
18985
|
return fail6(new ClipboardFailed({
|
|
18943
18986
|
message: `copying to the clipboard needs macOS, or Linux with wl-copy or xclip, not ${platform}`
|
|
18944
18987
|
}));
|
|
18945
18988
|
}
|
|
18946
|
-
const
|
|
18947
|
-
|
|
18989
|
+
const [installed] = commands.flatMap((command) => {
|
|
18990
|
+
const executable = Bun.which(command.name, { PATH: path });
|
|
18991
|
+
return executable === null ? [] : [{ command, executable }];
|
|
18992
|
+
});
|
|
18948
18993
|
if (installed === undefined) {
|
|
18949
18994
|
const names = commands.map(({ name }) => name).join(" or ");
|
|
18950
18995
|
return fail6(new ClipboardFailed({ message: `couldn't find ${names}` }));
|
|
18951
18996
|
}
|
|
18952
|
-
const { command,
|
|
18953
|
-
|
|
18997
|
+
const { command, executable } = installed;
|
|
18998
|
+
const { name } = command;
|
|
18999
|
+
return spawner.exitCode(childProcess(command, executable, content.html)).pipe(catchTag2("PlatformError", (error) => fail6(new ClipboardFailed({ message: `${name} failed: ${error.message}` }))), flatMap4((code) => code === 0 ? succeed6("copied") : fail6(new ClipboardFailed({ message: `${name} exited with ${code}` }))));
|
|
18954
19000
|
}
|
|
18955
|
-
};
|
|
19001
|
+
});
|
|
18956
19002
|
}));
|
|
18957
19003
|
var ClipboardLive = clipboardLayer();
|
|
18958
19004
|
|
|
@@ -19036,7 +19082,7 @@ class NoPullRequests extends TaggedError2("NoPullRequests") {
|
|
|
19036
19082
|
var EMOJI = {
|
|
19037
19083
|
closed: "\uD83D\uDEAB",
|
|
19038
19084
|
draft: "\uD83D\uDCDD",
|
|
19039
|
-
merged: "\
|
|
19085
|
+
merged: "\uD83C\uDFC1",
|
|
19040
19086
|
ready: "\uD83D\uDC40"
|
|
19041
19087
|
};
|
|
19042
19088
|
var OPEN = {
|
|
@@ -19045,6 +19091,14 @@ var OPEN = {
|
|
|
19045
19091
|
merged: false,
|
|
19046
19092
|
ready: true
|
|
19047
19093
|
};
|
|
19094
|
+
var COPY_REPORT = {
|
|
19095
|
+
copied: "copied the links to the clipboard",
|
|
19096
|
+
unreachable: [
|
|
19097
|
+
"This Claude Code cloud session can't reach the user's clipboard.",
|
|
19098
|
+
"To give the user the links, put the Markdown links this command printed in your reply, outside a code block.",
|
|
19099
|
+
"The Claude app shows them as links, which paste into Slack as links."
|
|
19100
|
+
].join(" ")
|
|
19101
|
+
};
|
|
19048
19102
|
var markdownLinks = (pullRequests) => pullRequests.map(({ number, state, title, url }) => `${EMOJI[state]} [#${number} ${title}](${url})`).join(`
|
|
19049
19103
|
`);
|
|
19050
19104
|
var htmlLinks = (pullRequests) => `<meta charset="utf-8">${pullRequests.map(({ number, state, title, url }) => `${EMOJI[state]} <a href="${Bun.escapeHTML(url)}">#${number} ${Bun.escapeHTML(title)}</a>`).join("<br>")}`;
|
|
@@ -19052,7 +19106,7 @@ var pullRequestOf = (pullRequests, commitId, pushed) => fromNullishOr(pullReques
|
|
|
19052
19106
|
var stackPullRequests = (revision) => gen2(function* () {
|
|
19053
19107
|
const github = yield* GitHub;
|
|
19054
19108
|
const stack = yield* stackChanges(revision);
|
|
19055
|
-
const [targets, found] = yield*
|
|
19109
|
+
const [targets, found] = yield* all3([
|
|
19056
19110
|
bookmarkTargets,
|
|
19057
19111
|
forEach2(stack, ({ bookmark }) => github.pullRequestsFrom(bookmark), {
|
|
19058
19112
|
concurrency: "unbounded"
|
|
@@ -19069,14 +19123,14 @@ var links = ({
|
|
|
19069
19123
|
yield* log(text);
|
|
19070
19124
|
if (copy) {
|
|
19071
19125
|
const clipboard = yield* Clipboard;
|
|
19072
|
-
yield* clipboard.write({ html: htmlLinks(pullRequests), text });
|
|
19073
|
-
yield* error(
|
|
19126
|
+
const written = yield* clipboard.write({ html: htmlLinks(pullRequests), text });
|
|
19127
|
+
yield* error(COPY_REPORT[written]);
|
|
19074
19128
|
}
|
|
19075
19129
|
});
|
|
19076
19130
|
var linksCommand = make32("links", {
|
|
19077
|
-
copy: Boolean6("copy").pipe(withDefault5(false), withDescription2("Also copy the links to the clipboard, as links that Slack pastes")),
|
|
19131
|
+
copy: Boolean6("copy").pipe(withDefault5(false), withDescription2("Also copy the links to the clipboard, as links that Slack pastes, or in a Claude Code cloud session say how to give them to the user")),
|
|
19078
19132
|
revision: revisionFlag("A change of the stack to list")
|
|
19079
|
-
}, (options) => asUserError(links(options).pipe(provide3([GitHubFromOrigin, ClipboardLive])))).pipe(withHelp("Print the stack's pull requests as Markdown links", "Prints one line per pull request, top first: \uD83D\uDCDD for a draft, \uD83D\uDC40 for one ready for review, \
|
|
19133
|
+
}, (options) => asUserError(links(options).pipe(provide3([GitHubFromOrigin, ClipboardLive])))).pipe(withHelp("Print the stack's pull requests as Markdown links", "Prints one line per pull request, top first: \uD83D\uDCDD for a draft, \uD83D\uDC40 for one ready for review, \uD83C\uDFC1 for a merged one and \uD83D\uDEAB for one closed unmerged, then a Markdown link showing its number and title.", "A change's pull request is the open one from its branch, or else the newest closed one whose head is the change or the commit pushed for it. A change with no pull request is left out, as is one that `sync` abandoned because its pull request merged. Fails where no change has one.", "With `--copy`, also puts the links on the clipboard as HTML, which Slack and other apps paste as links. That runs `osascript` on macOS, which also copies the Markdown as plain text, and `wl-copy` or `xclip` on Linux, which copy the HTML alone.", "In a Claude Code cloud session, where `CLAUDE_CODE_REMOTE` is `true`, `--copy` copies nothing. It tells the agent to put the Markdown in its reply, which the Claude app shows as links that paste into Slack.", "Fails if the changes aren't a chain, if one has conflicts, or if one doesn't have exactly one bookmark, as `log` does. Changes nothing, locally or on GitHub."));
|
|
19080
19134
|
|
|
19081
19135
|
// src/cli/gh/log.ts
|
|
19082
19136
|
var logLines2 = (entries) => {
|
|
@@ -19095,7 +19149,7 @@ var log2 = (revision) => gen2(function* () {
|
|
|
19095
19149
|
const github = yield* GitHub;
|
|
19096
19150
|
const stack = yield* stackChanges(revision);
|
|
19097
19151
|
const targets = yield* bookmarkTargets;
|
|
19098
|
-
const pullRequests = yield*
|
|
19152
|
+
const pullRequests = yield* all3(stack.map(({ bookmark }) => github.openPullRequest(bookmark)), { concurrency: "unbounded" });
|
|
19099
19153
|
return logLines2(stack.map((change, index) => ({
|
|
19100
19154
|
bookmark: change.bookmark,
|
|
19101
19155
|
pullRequest: pullRequests[index] ?? none2(),
|
|
@@ -19233,7 +19287,7 @@ class DescriptionConflict extends TaggedError2("DescriptionConflict") {
|
|
|
19233
19287
|
var kept = (text) => ({ send: false, text });
|
|
19234
19288
|
var sent = (text) => ({ send: true, text });
|
|
19235
19289
|
var ignoreClaudeCodeFooterKey = "jj-octo.ignore-claude-code-footer";
|
|
19236
|
-
var ignoresClaudeCodeFooter = jjFlag(ignoreClaudeCodeFooterKey);
|
|
19290
|
+
var ignoresClaudeCodeFooter = flatMap4(claudeCodeCloudSession, (cloudSession) => jjFlag(ignoreClaudeCodeFooterKey, cloudSession));
|
|
19237
19291
|
var descriptionsOf = (commits) => commits.length === 0 ? succeed6(new Map) : readLog(commits.join(" | "), String.raw`commit_id ++ "\t" ++ description.escape_json() ++ "\n"`).pipe(map7((output) => new Map(lines2(output).map((line) => {
|
|
19238
19292
|
const [commit = "", json = '""'] = line.split("\t");
|
|
19239
19293
|
return [commit, parseDescription(json)];
|
|
@@ -19542,7 +19596,7 @@ var changedOnGitHub = (bookmarks) => gen2(function* () {
|
|
|
19542
19596
|
var syncStack = (revision, trunk) => gen2(function* () {
|
|
19543
19597
|
const downstack = downstackRevset(revision);
|
|
19544
19598
|
const before = yield* bookmarksBeforeFetch(downstack);
|
|
19545
|
-
const [heads, onGitHub] = yield*
|
|
19599
|
+
const [heads, onGitHub] = yield* all3([mergedHeadsOf(before), changedOnGitHub(before)], {
|
|
19546
19600
|
concurrency: "unbounded"
|
|
19547
19601
|
});
|
|
19548
19602
|
const merged = yield* mergedIn(before, heads);
|
|
@@ -19584,7 +19638,7 @@ class SeveralStacks extends TaggedError2("SeveralStacks") {
|
|
|
19584
19638
|
}
|
|
19585
19639
|
var stackContaining = (pullRequests) => gen2(function* () {
|
|
19586
19640
|
const github = yield* GitHub;
|
|
19587
|
-
const found = yield*
|
|
19641
|
+
const found = yield* all3(pullRequests.map((pullRequest) => github.stackOf(pullRequest)), { concurrency: "unbounded" });
|
|
19588
19642
|
const stacks = dedupeWith(found.flatMap((stack) => toArray(stack)), (a, b) => a.number === b.number);
|
|
19589
19643
|
if (stacks.length > 1) {
|
|
19590
19644
|
return yield* new SeveralStacks({
|
|
@@ -19603,7 +19657,7 @@ var publish = (stack, { draft, overwriteDescriptions, trunk }) => gen2(function*
|
|
|
19603
19657
|
const records = yield* PrDescriptions;
|
|
19604
19658
|
const bookmarks = stack.map(({ bookmark }) => bookmark);
|
|
19605
19659
|
const bases = basesFor(bookmarks, trunk);
|
|
19606
|
-
const found = yield*
|
|
19660
|
+
const found = yield* all3(stack.map((change, index) => github.openPullRequest(change.bookmark).pipe(map7((pullRequest) => ({ base: bases[index] ?? trunk, change, pullRequest })))), { concurrency: "unbounded" });
|
|
19607
19661
|
const targets = yield* bookmarkTargets;
|
|
19608
19662
|
const pushedDescriptions = yield* descriptionsOf(bookmarks.flatMap((bookmark) => targets.get(bookmark)?.origin ?? []));
|
|
19609
19663
|
const ignoreClaudeCodeFooter = yield* ignoresClaudeCodeFooter;
|