jj-octo 0.2.4 → 0.3.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
@@ -56,6 +56,14 @@ bun update --global --latest jj-octo
56
56
 
57
57
  It uses only GitHub's REST API, so that it works in a [Claude Code](https://claude.com/claude-code) cloud session. There, GitHub is reached through a proxy that allows REST calls for the session's repository and blocks GraphQL, which `gh pr` depends on.
58
58
 
59
+ Where git reaches github.com through a proxy that adds the credentials itself, as in a Claude Code cloud session that keeps the token outside the sandbox, have `jj-octo` use that proxy too:
60
+
61
+ ```
62
+ jj config set --repo jj-octo.github-auth git-proxy
63
+ ```
64
+
65
+ `jj-octo` then sends its requests through the `http.proxy` that git uses for `https://github.com`, trusts the certificate authorities in git's `http.sslCAInfo` for it, and sends a placeholder token that the proxy replaces. It reads git's settings on each run, so it follows a proxy that moves to another port. `token`, the default, sends your own token.
66
+
59
67
  ## Development
60
68
 
61
69
  ```
package/dist/jj-octo.js CHANGED
@@ -18112,7 +18112,7 @@ var layer14 = /* @__PURE__ */ layerMergedContext(/* @__PURE__ */ succeed6(fetch)
18112
18112
  // package.json
18113
18113
  var package_default = {
18114
18114
  name: "jj-octo",
18115
- version: "0.2.4",
18115
+ version: "0.3.0",
18116
18116
  description: "A jj subcommand for working with GitHub that supports stacking",
18117
18117
  license: "MIT",
18118
18118
  repository: {
@@ -18493,24 +18493,21 @@ var MergeRequest = Struct({
18493
18493
  });
18494
18494
  var StartedMerge = responseOf()(MergeRequest);
18495
18495
  var MergeResult = responseOf()(MergeRequest);
18496
- var token = gen2(function* () {
18497
- const fromEnvironment = yield* option2(Redacted2("GH_TOKEN").pipe(orElse(() => Redacted2("GITHUB_TOKEN"))));
18498
- if (isSome2(fromEnvironment)) {
18499
- return fromEnvironment.value;
18500
- }
18501
- const spawner = yield* ChildProcessSpawner;
18502
- const stored = (yield* spawner.string(make14("gh", ["auth", "token"]))).trim();
18503
- return stored === "" ? yield* fail6("no token") : make19(stored);
18504
- }).pipe(mapError2(() => new GitHubFailed({ message: "no GitHub token: set GH_TOKEN, or run `gh auth login`" })));
18505
- var GitHubLive = (repository) => {
18496
+ var GitHubLive = (repository, connection) => {
18506
18497
  const repo = (path) => `/repos/${repository.owner}/${repository.name}${path}`;
18507
18498
  return effect(GitHub, gen2(function* () {
18508
- const bearer = yield* token;
18509
- const client = (yield* HttpClient).pipe(mapRequest((request) => request.pipe(prependUrl("https://api.github.com"), acceptJson, bearerToken(bearer), setHeaders({
18499
+ const requestInit = match(connection.proxy, {
18500
+ onNone: () => ({}),
18501
+ onSome: ({ ca, url }) => match(ca, {
18502
+ onNone: () => ({ proxy: url }),
18503
+ onSome: (certificates) => ({ proxy: url, tls: { ca: certificates } })
18504
+ })
18505
+ });
18506
+ const client = (yield* HttpClient).pipe(mapRequest((request) => request.pipe(prependUrl("https://api.github.com"), acceptJson, bearerToken(connection.token), setHeaders({
18510
18507
  "user-agent": "jj-octo",
18511
18508
  "x-github-api-version": "2022-11-28"
18512
18509
  }))));
18513
- const send = (request) => client.execute(request).pipe(flatMap4((response) => response.status < 400 ? succeed6(response) : response.text.pipe(orElseSucceed2(() => ""), flatMap4((text) => fail6(new GitHubFailed({
18510
+ const send = (request) => client.execute(request).pipe(provideService2(RequestInit, requestInit), flatMap4((response) => response.status < 400 ? succeed6(response) : response.text.pipe(orElseSucceed2(() => ""), flatMap4((text) => fail6(new GitHubFailed({
18514
18511
  message: `${request.method} ${request.url} returned ${response.status}: ${text}`
18515
18512
  }))))), catchTag2("HttpClientError", (error) => fail6(new GitHubFailed({ message: error.message }))));
18516
18513
  const json = (schema) => (request) => send(request).pipe(flatMap4(schemaBodyJson(schema)), catchTags2({
@@ -18567,6 +18564,60 @@ var GitHubLive = (repository) => {
18567
18564
  }));
18568
18565
  };
18569
18566
 
18567
+ // src/clients/github/connection.ts
18568
+ var authKey = "jj-octo.github-auth";
18569
+ var ownToken = gen2(function* () {
18570
+ const fromEnvironment = yield* option2(Redacted2("GH_TOKEN").pipe(orElse(() => Redacted2("GITHUB_TOKEN"))));
18571
+ if (isSome2(fromEnvironment)) {
18572
+ return fromEnvironment.value;
18573
+ }
18574
+ const spawner = yield* ChildProcessSpawner;
18575
+ const stored = (yield* spawner.string(make14("gh", ["auth", "token"]))).trim();
18576
+ return stored === "" ? yield* fail6("no token") : make19(stored);
18577
+ }).pipe(mapError2(() => new GitHubFailed({ message: "no GitHub token: set GH_TOKEN, or run `gh auth login`" })));
18578
+ var gitSetting = (name) => gen2(function* () {
18579
+ const git = yield* Git;
18580
+ const value = (yield* git.read(["config", "--get-urlmatch", name, "https://github.com"]).pipe(orElseSucceed2(() => ""))).trim();
18581
+ return value === "" ? none2() : some2(value);
18582
+ });
18583
+ var gitProxy = gen2(function* () {
18584
+ const fs = yield* FileSystem;
18585
+ const url = yield* gitSetting("http.proxy");
18586
+ if (isNone2(url)) {
18587
+ return yield* new GitHubFailed({
18588
+ message: `${authKey} is git-proxy, but git has no http.proxy for https://github.com`
18589
+ });
18590
+ }
18591
+ const caFile = yield* gitSetting("http.sslCAInfo");
18592
+ const ca = isNone2(caFile) ? none2() : some2(yield* fs.readFileString(caFile.value).pipe(mapError2((error) => new GitHubFailed({
18593
+ message: `can't read git's http.sslCAInfo ${caFile.value}: ${error.message}`
18594
+ }))));
18595
+ const connection = {
18596
+ proxy: some2({ ca, url: url.value }),
18597
+ token: make19("proxy-injected")
18598
+ };
18599
+ return connection;
18600
+ });
18601
+ var connection = gen2(function* () {
18602
+ const jj = yield* Jj;
18603
+ const auth = (yield* jj.read(["config", "get", authKey]).pipe(orElseSucceed2(() => ""))).trim();
18604
+ switch (auth) {
18605
+ case "":
18606
+ case "token": {
18607
+ const own = { proxy: none2(), token: yield* ownToken };
18608
+ return own;
18609
+ }
18610
+ case "git-proxy": {
18611
+ return yield* gitProxy;
18612
+ }
18613
+ default: {
18614
+ return yield* new GitHubFailed({
18615
+ message: `${authKey} is ${JSON.stringify(auth)}; set it to token or git-proxy`
18616
+ });
18617
+ }
18618
+ }
18619
+ });
18620
+
18570
18621
  // src/clients/github/repository.ts
18571
18622
  var repositoryFromUrl = (url) => {
18572
18623
  const match = /github\.com[:/](?<owner>[^/]+)\/(?<name>[^/]+?)(?:\.git)?\/?$/u.exec(url.trim());
@@ -18585,7 +18636,7 @@ var GitHubFromOrigin = unwrap(gen2(function* () {
18585
18636
  if (isNone2(repository)) {
18586
18637
  return yield* new GitHubFailed({ message: "the `origin` remote isn't a GitHub repository" });
18587
18638
  }
18588
- return GitHubLive(repository.value);
18639
+ return GitHubLive(repository.value, yield* connection);
18589
18640
  }));
18590
18641
 
18591
18642
  // src/cli/gh/log.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jj-octo",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "A jj subcommand for working with GitHub that supports stacking",
5
5
  "license": "MIT",
6
6
  "repository": {