@@ -2,7 +2,7 @@ import type * as CommandExecutor from "@effect/platform/CommandExecutor"
22import type { PlatformError } from "@effect/platform/Error"
33import * as FileSystem from "@effect/platform/FileSystem"
44import * as Path from "@effect/platform/Path"
5- import { Effect , pipe } from "effect"
5+ import { Effect } from "effect"
66import { runCommandExitCode } from "../shell/command-runner.js"
77import { CommandFailedError } from "../shell/errors.js"
88import { defaultProjectsRoot } from "./menu-helpers.js"
@@ -17,17 +17,19 @@ import {
1717 isGitRepo ,
1818 successExitCode
1919} from "./state-repo/git-commands.js"
20+ import {
21+ githubAuthLoginHint ,
22+ normalizeOriginUrlIfNeeded ,
23+ shouldLogGithubAuthHintForStateSyncFailure
24+ } from "./state-repo/github-auth-state.js"
2025import type { GitAuthEnv } from "./state-repo/github-auth.js"
2126import { isGithubHttpsRemote , resolveGithubToken , withGithubAskpassEnv } from "./state-repo/github-auth.js"
2227import { ensureStateGitignore } from "./state-repo/gitignore.js"
2328import { runStateSyncOps , runStateSyncWithToken } from "./state-repo/sync-ops.js"
2429
2530type StateRepoEnv = FileSystem . FileSystem | Path . Path | CommandExecutor . CommandExecutor
26-
2731const resolveStateRoot = ( path : Path . Path , cwd : string ) : string => path . resolve ( defaultProjectsRoot ( cwd ) )
28-
2932const managedRepositoryCachePaths : ReadonlyArray < string > = [ ".cache/git-mirrors" , ".cache/packages" ]
30-
3133const ensureStateIgnoreAndUntrackCaches = (
3234 fs : FileSystem . FileSystem ,
3335 path : Path . Path ,
@@ -53,7 +55,6 @@ export const stateSync = (
5355 const fs = yield * _ ( FileSystem . FileSystem )
5456 const path = yield * _ ( Path . Path )
5557 const root = resolveStateRoot ( path , process . cwd ( ) )
56-
5758 const repoExit = yield * _ ( gitExitCode ( root , [ "rev-parse" , "--is-inside-work-tree" ] , gitBaseEnv ) )
5859 if ( repoExit !== successExitCode ) {
5960 yield * _ ( Effect . logWarning ( `State dir is not a git repository: ${ root } ` ) )
@@ -62,9 +63,7 @@ export const stateSync = (
6263 Effect . fail ( new CommandFailedError ( { command : "git rev-parse --is-inside-work-tree" , exitCode : repoExit } ) )
6364 )
6465 }
65-
6666 yield * _ ( ensureStateIgnoreAndUntrackCaches ( fs , path , root ) )
67-
6867 const originUrlExit = yield * _ ( gitExitCode ( root , [ "remote" , "get-url" , "origin" ] , gitBaseEnv ) )
6968 if ( originUrlExit !== successExitCode ) {
7069 yield * _ ( Effect . logWarning ( `State dir has no origin remote: ${ root } ` ) )
@@ -73,33 +72,38 @@ export const stateSync = (
7372 Effect . fail ( new CommandFailedError ( { command : "git remote get-url origin" , exitCode : originUrlExit } ) )
7473 )
7574 }
76- const originUrl = yield * _ (
75+ const rawOriginUrl = yield * _ (
7776 gitCapture ( root , [ "remote" , "get-url" , "origin" ] , gitBaseEnv ) . pipe ( Effect . map ( ( value ) => value . trim ( ) ) )
7877 )
78+ const originUrl = yield * _ ( normalizeOriginUrlIfNeeded ( root , rawOriginUrl ) )
7979 const token = yield * _ ( resolveGithubToken ( fs , path , root ) )
8080 const syncEffect = token && token . length > 0 && isGithubHttpsRemote ( originUrl )
8181 ? runStateSyncWithToken ( token , root , originUrl , message )
8282 : runStateSyncOps ( root , originUrl , message , gitBaseEnv )
83-
84- yield * _ ( syncEffect )
83+ yield * _ (
84+ syncEffect . pipe (
85+ Effect . tapError ( ( error ) =>
86+ shouldLogGithubAuthHintForStateSyncFailure ( originUrl , token , error )
87+ ? Effect . logWarning ( githubAuthLoginHint )
88+ : Effect . void
89+ )
90+ )
91+ )
8592 } ) . pipe ( Effect . asVoid )
8693
8794export const autoSyncState = ( message : string ) : Effect . Effect < void , never , StateRepoEnv > =>
8895 Effect . gen ( function * ( _ ) {
8996 const path = yield * _ ( Path . Path )
9097 const root = resolveStateRoot ( path , process . cwd ( ) )
91-
9298 const repoOk = yield * _ ( isGitRepo ( root ) )
9399 if ( ! repoOk ) {
94100 return
95101 }
96-
97102 const originOk = yield * _ ( hasOriginRemote ( root ) )
98103 const enabled = isAutoSyncEnabled ( process . env [ autoSyncEnvKey ] , originOk )
99104 if ( ! enabled ) {
100105 return
101106 }
102-
103107 const strictValue = process . env [ autoSyncStrictEnvKey ]
104108 const strict = strictValue !== undefined && strictValue . trim ( ) . length > 0 ? isTruthyEnv ( strictValue ) : false
105109 const effect = stateSync ( message )
@@ -243,80 +247,5 @@ export const stateInit = (
243247 : doInit ( gitBaseEnv )
244248}
245249
246- export const stateStatus = Effect . gen ( function * ( _ ) {
247- const path = yield * _ ( Path . Path )
248- const root = resolveStateRoot ( path , process . cwd ( ) )
249- const output = yield * _ ( gitCapture ( root , [ "status" , "-sb" , "--porcelain=v1" ] , gitBaseEnv ) )
250- yield * _ ( Effect . log ( output . trim ( ) . length > 0 ? output . trimEnd ( ) : "(clean)" ) )
251- } ) . pipe ( Effect . asVoid )
252-
253- export const statePull = Effect . gen ( function * ( _ ) {
254- const fs = yield * _ ( FileSystem . FileSystem )
255- const path = yield * _ ( Path . Path )
256- const root = resolveStateRoot ( path , process . cwd ( ) )
257- const originUrlExit = yield * _ ( gitExitCode ( root , [ "remote" , "get-url" , "origin" ] , gitBaseEnv ) )
258- if ( originUrlExit !== successExitCode ) {
259- yield * _ ( git ( root , [ "pull" , "--rebase" ] , gitBaseEnv ) )
260- return
261- }
262- const originUrl = yield * _ (
263- gitCapture ( root , [ "remote" , "get-url" , "origin" ] , gitBaseEnv ) . pipe ( Effect . map ( ( value ) => value . trim ( ) ) )
264- )
265- const token = yield * _ ( resolveGithubToken ( fs , path , root ) )
266- const effect = token && token . length > 0 && isGithubHttpsRemote ( originUrl )
267- ? withGithubAskpassEnv ( token , ( env ) => git ( root , [ "pull" , "--rebase" ] , env ) )
268- : git ( root , [ "pull" , "--rebase" ] , gitBaseEnv )
269- yield * _ ( effect )
270- } ) . pipe ( Effect . asVoid )
271-
272- export const statePush = Effect . gen ( function * ( _ ) {
273- const fs = yield * _ ( FileSystem . FileSystem )
274- const path = yield * _ ( Path . Path )
275- const root = resolveStateRoot ( path , process . cwd ( ) )
276- const originUrlExit = yield * _ ( gitExitCode ( root , [ "remote" , "get-url" , "origin" ] , gitBaseEnv ) )
277- if ( originUrlExit !== successExitCode ) {
278- yield * _ ( git ( root , [ "push" , "-u" , "origin" , "HEAD" ] , gitBaseEnv ) )
279- return
280- }
281- const originUrl = yield * _ (
282- gitCapture ( root , [ "remote" , "get-url" , "origin" ] , gitBaseEnv ) . pipe ( Effect . map ( ( value ) => value . trim ( ) ) )
283- )
284- const token = yield * _ ( resolveGithubToken ( fs , path , root ) )
285- const effect = token && token . length > 0 && isGithubHttpsRemote ( originUrl )
286- ? withGithubAskpassEnv (
287- token ,
288- ( env ) =>
289- pipe (
290- gitCapture ( root , [ "rev-parse" , "--abbrev-ref" , "HEAD" ] , env ) ,
291- Effect . map ( ( value ) => value . trim ( ) ) ,
292- Effect . map ( ( branch ) => ( branch === "HEAD" ? "main" : branch ) ) ,
293- Effect . flatMap ( ( branch ) => git ( root , [ "push" , "--no-verify" , originUrl , `HEAD:refs/heads/${ branch } ` ] , env ) )
294- )
295- )
296- : git ( root , [ "push" , "--no-verify" , "-u" , "origin" , "HEAD" ] , gitBaseEnv )
297- yield * _ ( effect )
298- } ) . pipe ( Effect . asVoid )
299-
300- export const stateCommit = (
301- message : string
302- ) : Effect . Effect <
303- void ,
304- CommandFailedError | PlatformError ,
305- FileSystem . FileSystem | Path . Path | CommandExecutor . CommandExecutor
306- > =>
307- Effect . gen ( function * ( _ ) {
308- const fs = yield * _ ( FileSystem . FileSystem )
309- const path = yield * _ ( Path . Path )
310- const root = resolveStateRoot ( path , process . cwd ( ) )
311-
312- yield * _ ( ensureStateIgnoreAndUntrackCaches ( fs , path , root ) )
313- yield * _ ( git ( root , [ "add" , "-A" ] , gitBaseEnv ) )
314- const diffExit = yield * _ ( gitExitCode ( root , [ "diff" , "--cached" , "--quiet" ] , gitBaseEnv ) )
315-
316- if ( diffExit === successExitCode ) {
317- yield * _ ( Effect . log ( "Nothing to commit." ) )
318- return
319- }
320-
321- yield * _ ( git ( root , [ "commit" , "-m" , message ] , gitBaseEnv ) )
322- } ) . pipe ( Effect . asVoid )
250+ export { stateCommit , stateStatus } from "./state-repo/local-ops.js"
251+ export { statePull , statePush } from "./state-repo/pull-push.js"
0 commit comments