@prover-coder-ai/docker-git 1.0.22 → 1.0.24
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 +3 -0
- package/dist/src/docker-git/main.js +5 -2
- package/dist/src/docker-git/main.js.map +1 -1
- package/package.json +5 -1
- package/.jscpd.json +0 -16
- package/.package.json.release.bak +0 -110
- package/CHANGELOG.md +0 -133
- package/biome.json +0 -34
- package/eslint.config.mts +0 -305
- package/eslint.effect-ts-check.config.mjs +0 -220
- package/linter.config.json +0 -33
- package/src/app/main.ts +0 -18
- package/src/app/program.ts +0 -75
- package/src/docker-git/cli/input.ts +0 -29
- package/src/docker-git/cli/parser-apply.ts +0 -28
- package/src/docker-git/cli/parser-attach.ts +0 -22
- package/src/docker-git/cli/parser-auth.ts +0 -154
- package/src/docker-git/cli/parser-clone.ts +0 -50
- package/src/docker-git/cli/parser-create.ts +0 -3
- package/src/docker-git/cli/parser-mcp-playwright.ts +0 -24
- package/src/docker-git/cli/parser-options.ts +0 -211
- package/src/docker-git/cli/parser-panes.ts +0 -22
- package/src/docker-git/cli/parser-scrap.ts +0 -106
- package/src/docker-git/cli/parser-sessions.ts +0 -101
- package/src/docker-git/cli/parser-shared.ts +0 -51
- package/src/docker-git/cli/parser-state.ts +0 -86
- package/src/docker-git/cli/parser.ts +0 -82
- package/src/docker-git/cli/read-command.ts +0 -26
- package/src/docker-git/cli/usage.ts +0 -129
- package/src/docker-git/main.ts +0 -18
- package/src/docker-git/menu-actions.ts +0 -273
- package/src/docker-git/menu-auth-data.ts +0 -184
- package/src/docker-git/menu-auth-helpers.ts +0 -30
- package/src/docker-git/menu-auth.ts +0 -311
- package/src/docker-git/menu-buffer-input.ts +0 -18
- package/src/docker-git/menu-create.ts +0 -310
- package/src/docker-git/menu-input-handler.ts +0 -183
- package/src/docker-git/menu-input-utils.ts +0 -85
- package/src/docker-git/menu-input.ts +0 -2
- package/src/docker-git/menu-labeled-env.ts +0 -37
- package/src/docker-git/menu-menu.ts +0 -58
- package/src/docker-git/menu-project-auth-claude.ts +0 -70
- package/src/docker-git/menu-project-auth-data.ts +0 -292
- package/src/docker-git/menu-project-auth.ts +0 -271
- package/src/docker-git/menu-render-auth.ts +0 -65
- package/src/docker-git/menu-render-common.ts +0 -67
- package/src/docker-git/menu-render-layout.ts +0 -30
- package/src/docker-git/menu-render-project-auth.ts +0 -70
- package/src/docker-git/menu-render-select.ts +0 -250
- package/src/docker-git/menu-render.ts +0 -292
- package/src/docker-git/menu-select-actions.ts +0 -150
- package/src/docker-git/menu-select-connect.ts +0 -27
- package/src/docker-git/menu-select-load.ts +0 -33
- package/src/docker-git/menu-select-order.ts +0 -37
- package/src/docker-git/menu-select-runtime.ts +0 -143
- package/src/docker-git/menu-select-view.ts +0 -25
- package/src/docker-git/menu-select.ts +0 -145
- package/src/docker-git/menu-shared.ts +0 -256
- package/src/docker-git/menu-startup.ts +0 -83
- package/src/docker-git/menu-types.ts +0 -170
- package/src/docker-git/menu.ts +0 -303
- package/src/docker-git/program.ts +0 -154
- package/src/docker-git/tmux.ts +0 -292
- package/tests/app/main.test.ts +0 -65
- package/tests/docker-git/entrypoint-auth.test.ts +0 -40
- package/tests/docker-git/fixtures/project-item.ts +0 -24
- package/tests/docker-git/menu-select-connect.test.ts +0 -55
- package/tests/docker-git/menu-select-order.test.ts +0 -84
- package/tests/docker-git/menu-startup.test.ts +0 -51
- package/tests/docker-git/parser-network-options.test.ts +0 -47
- package/tests/docker-git/parser.test.ts +0 -340
- package/tsconfig.build.json +0 -8
- package/tsconfig.json +0 -20
- package/vite.config.ts +0 -32
- package/vite.docker-git.config.ts +0 -34
- package/vitest.config.ts +0 -85
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { handleAuthInput } from "./menu-auth.js"
|
|
2
|
-
import { handleCreateInput } from "./menu-create.js"
|
|
3
|
-
import { handleMenuInput } from "./menu-menu.js"
|
|
4
|
-
import { handleProjectAuthInput } from "./menu-project-auth.js"
|
|
5
|
-
import { handleSelectInput } from "./menu-select.js"
|
|
6
|
-
import type { MenuKeyInput, MenuRunner, MenuState, MenuViewContext, ViewState } from "./menu-types.js"
|
|
7
|
-
|
|
8
|
-
export type InputStage = "cold" | "active"
|
|
9
|
-
|
|
10
|
-
export type MenuInputContext = MenuViewContext & {
|
|
11
|
-
readonly busy: boolean
|
|
12
|
-
readonly view: ViewState
|
|
13
|
-
readonly inputStage: InputStage
|
|
14
|
-
readonly setInputStage: (stage: InputStage) => void
|
|
15
|
-
readonly selected: number
|
|
16
|
-
readonly setSelected: (update: (value: number) => number) => void
|
|
17
|
-
readonly setSkipInputs: (update: (value: number) => number) => void
|
|
18
|
-
readonly sshActive: boolean
|
|
19
|
-
readonly setSshActive: (active: boolean) => void
|
|
20
|
-
readonly state: MenuState
|
|
21
|
-
readonly runner: MenuRunner
|
|
22
|
-
readonly exit: () => void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
type ActiveView = Exclude<ViewState, { readonly _tag: "Menu" }>
|
|
26
|
-
|
|
27
|
-
const activateInput = (
|
|
28
|
-
input: string,
|
|
29
|
-
key: Pick<MenuKeyInput, "upArrow" | "downArrow" | "return">,
|
|
30
|
-
context: Pick<MenuInputContext, "inputStage" | "setInputStage">
|
|
31
|
-
): { readonly activated: boolean; readonly allowProcessing: boolean } => {
|
|
32
|
-
if (context.inputStage === "active") {
|
|
33
|
-
return { activated: false, allowProcessing: true }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (input.trim().length > 0) {
|
|
37
|
-
context.setInputStage("active")
|
|
38
|
-
return { activated: true, allowProcessing: true }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (key.upArrow || key.downArrow || key.return) {
|
|
42
|
-
context.setInputStage("active")
|
|
43
|
-
return { activated: true, allowProcessing: false }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (input.length > 0) {
|
|
47
|
-
context.setInputStage("active")
|
|
48
|
-
return { activated: true, allowProcessing: true }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return { activated: false, allowProcessing: false }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const shouldHandleMenuInput = (
|
|
55
|
-
input: string,
|
|
56
|
-
key: Pick<MenuKeyInput, "upArrow" | "downArrow" | "return">,
|
|
57
|
-
context: Pick<MenuInputContext, "inputStage" | "setInputStage">
|
|
58
|
-
): boolean => {
|
|
59
|
-
const activation = activateInput(input, key, context)
|
|
60
|
-
if (activation.activated && !activation.allowProcessing) {
|
|
61
|
-
return false
|
|
62
|
-
}
|
|
63
|
-
return activation.allowProcessing
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const handleMenuViewInput = (
|
|
67
|
-
input: string,
|
|
68
|
-
key: MenuKeyInput,
|
|
69
|
-
context: MenuInputContext
|
|
70
|
-
) => {
|
|
71
|
-
if (!shouldHandleMenuInput(input, key, context)) {
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
handleMenuInput(input, key, {
|
|
75
|
-
selected: context.selected,
|
|
76
|
-
setSelected: context.setSelected,
|
|
77
|
-
state: context.state,
|
|
78
|
-
runner: context.runner,
|
|
79
|
-
exit: context.exit,
|
|
80
|
-
setView: context.setView,
|
|
81
|
-
setMessage: context.setMessage,
|
|
82
|
-
setActiveDir: context.setActiveDir
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const handleCreateViewInput = (
|
|
87
|
-
input: string,
|
|
88
|
-
key: MenuKeyInput,
|
|
89
|
-
view: Extract<ViewState, { readonly _tag: "Create" }>,
|
|
90
|
-
context: MenuInputContext
|
|
91
|
-
) => {
|
|
92
|
-
handleCreateInput(input, key, view, {
|
|
93
|
-
state: context.state,
|
|
94
|
-
setView: context.setView,
|
|
95
|
-
setMessage: context.setMessage,
|
|
96
|
-
runner: context.runner,
|
|
97
|
-
setActiveDir: context.setActiveDir
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const handleAuthViewInput = (
|
|
102
|
-
input: string,
|
|
103
|
-
key: MenuKeyInput,
|
|
104
|
-
view: Extract<ViewState, { readonly _tag: "AuthMenu" | "AuthPrompt" }>,
|
|
105
|
-
context: MenuInputContext
|
|
106
|
-
) => {
|
|
107
|
-
handleAuthInput(input, key, view, {
|
|
108
|
-
state: context.state,
|
|
109
|
-
setView: context.setView,
|
|
110
|
-
setMessage: context.setMessage,
|
|
111
|
-
setActiveDir: context.setActiveDir,
|
|
112
|
-
runner: context.runner,
|
|
113
|
-
setSshActive: context.setSshActive,
|
|
114
|
-
setSkipInputs: context.setSkipInputs
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const handleProjectAuthViewInput = (
|
|
119
|
-
input: string,
|
|
120
|
-
key: MenuKeyInput,
|
|
121
|
-
view: Extract<ViewState, { readonly _tag: "ProjectAuthMenu" | "ProjectAuthPrompt" }>,
|
|
122
|
-
context: MenuInputContext
|
|
123
|
-
) => {
|
|
124
|
-
handleProjectAuthInput(input, key, view, {
|
|
125
|
-
runner: context.runner,
|
|
126
|
-
setView: context.setView,
|
|
127
|
-
setMessage: context.setMessage,
|
|
128
|
-
setActiveDir: context.setActiveDir
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const handleSelectViewInput = (
|
|
133
|
-
input: string,
|
|
134
|
-
key: MenuKeyInput,
|
|
135
|
-
view: Extract<ViewState, { readonly _tag: "SelectProject" }>,
|
|
136
|
-
context: MenuInputContext
|
|
137
|
-
) => {
|
|
138
|
-
handleSelectInput(input, key, view, {
|
|
139
|
-
setView: context.setView,
|
|
140
|
-
setMessage: context.setMessage,
|
|
141
|
-
setActiveDir: context.setActiveDir,
|
|
142
|
-
activeDir: context.state.activeDir,
|
|
143
|
-
runner: context.runner,
|
|
144
|
-
setSshActive: context.setSshActive,
|
|
145
|
-
setSkipInputs: context.setSkipInputs
|
|
146
|
-
})
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const handleActiveViewInput = (
|
|
150
|
-
input: string,
|
|
151
|
-
key: MenuKeyInput,
|
|
152
|
-
view: ActiveView,
|
|
153
|
-
context: MenuInputContext
|
|
154
|
-
) => {
|
|
155
|
-
if (view._tag === "Create") {
|
|
156
|
-
handleCreateViewInput(input, key, view, context)
|
|
157
|
-
return
|
|
158
|
-
}
|
|
159
|
-
if (view._tag === "AuthMenu" || view._tag === "AuthPrompt") {
|
|
160
|
-
handleAuthViewInput(input, key, view, context)
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
if (view._tag === "ProjectAuthMenu" || view._tag === "ProjectAuthPrompt") {
|
|
164
|
-
handleProjectAuthViewInput(input, key, view, context)
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
handleSelectViewInput(input, key, view, context)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export const handleUserInput = (
|
|
171
|
-
input: string,
|
|
172
|
-
key: MenuKeyInput,
|
|
173
|
-
context: MenuInputContext
|
|
174
|
-
) => {
|
|
175
|
-
if (context.busy || context.sshActive) {
|
|
176
|
-
return
|
|
177
|
-
}
|
|
178
|
-
if (context.view._tag === "Menu") {
|
|
179
|
-
handleMenuViewInput(input, key, context)
|
|
180
|
-
return
|
|
181
|
-
}
|
|
182
|
-
handleActiveViewInput(input, key, context.view, context)
|
|
183
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
export const parseMenuIndex = (input: string): number | null => {
|
|
2
|
-
const trimmed = input.trim()
|
|
3
|
-
if (trimmed.length === 0) {
|
|
4
|
-
return null
|
|
5
|
-
}
|
|
6
|
-
const parsed = Number(trimmed)
|
|
7
|
-
if (!Number.isInteger(parsed)) {
|
|
8
|
-
return null
|
|
9
|
-
}
|
|
10
|
-
const index = parsed - 1
|
|
11
|
-
return index >= 0 ? index : null
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type PromptStep = {
|
|
15
|
-
readonly key: string
|
|
16
|
-
readonly label: string
|
|
17
|
-
readonly required: boolean
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type PromptView = {
|
|
21
|
-
readonly step: number
|
|
22
|
-
readonly buffer: string
|
|
23
|
-
readonly values: Readonly<Record<string, string>>
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
type PromptContext<V extends PromptView> = {
|
|
27
|
-
readonly setView: (view: V) => void
|
|
28
|
-
readonly setMessage: (message: string | null) => void
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const submitPromptStep = <V extends PromptView>(
|
|
32
|
-
view: V,
|
|
33
|
-
steps: ReadonlyArray<PromptStep>,
|
|
34
|
-
context: PromptContext<V>,
|
|
35
|
-
onCancel: () => void,
|
|
36
|
-
onSubmit: (values: Readonly<Record<string, string>>) => void
|
|
37
|
-
): void => {
|
|
38
|
-
const step = steps[view.step]
|
|
39
|
-
if (!step) {
|
|
40
|
-
onCancel()
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const value = view.buffer.trim()
|
|
45
|
-
if (step.required && value.length === 0) {
|
|
46
|
-
context.setMessage(`${step.label} is required.`)
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const nextValues: Readonly<Record<string, string>> = { ...view.values, [step.key]: value }
|
|
51
|
-
const nextStep = view.step + 1
|
|
52
|
-
if (nextStep < steps.length) {
|
|
53
|
-
context.setView({ ...view, step: nextStep, buffer: "", values: nextValues })
|
|
54
|
-
context.setMessage(null)
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
onSubmit(nextValues)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
type MenuNumberInputContext = {
|
|
62
|
-
readonly setMessage: (message: string | null) => void
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export const handleMenuNumberInput = <A>(
|
|
66
|
-
input: string,
|
|
67
|
-
context: MenuNumberInputContext,
|
|
68
|
-
actionByIndex: (index: number) => A | null,
|
|
69
|
-
runAction: (action: A) => void
|
|
70
|
-
): void => {
|
|
71
|
-
const index = parseMenuIndex(input)
|
|
72
|
-
if (index === null) {
|
|
73
|
-
if (input.trim().length > 0) {
|
|
74
|
-
context.setMessage("Use arrows + Enter, or type a number from the list.")
|
|
75
|
-
}
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const action = actionByIndex(index)
|
|
80
|
-
if (action === null) {
|
|
81
|
-
context.setMessage(`Unknown action: ${input.trim()}`)
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
runAction(action)
|
|
85
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { parseEnvEntries } from "@effect-template/lib/usecases/env-file"
|
|
2
|
-
|
|
3
|
-
export const normalizeLabel = (value: string): string => {
|
|
4
|
-
const trimmed = value.trim()
|
|
5
|
-
if (trimmed.length === 0) {
|
|
6
|
-
return ""
|
|
7
|
-
}
|
|
8
|
-
const normalized = trimmed
|
|
9
|
-
.toUpperCase()
|
|
10
|
-
.replaceAll(/[^A-Z0-9]+/g, "_")
|
|
11
|
-
|
|
12
|
-
let start = 0
|
|
13
|
-
while (start < normalized.length && normalized[start] === "_") {
|
|
14
|
-
start += 1
|
|
15
|
-
}
|
|
16
|
-
let end = normalized.length
|
|
17
|
-
while (end > start && normalized[end - 1] === "_") {
|
|
18
|
-
end -= 1
|
|
19
|
-
}
|
|
20
|
-
const cleaned = normalized.slice(start, end)
|
|
21
|
-
return cleaned.length > 0 ? cleaned : ""
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const buildLabeledEnvKey = (baseKey: string, label: string): string => {
|
|
25
|
-
const normalized = normalizeLabel(label)
|
|
26
|
-
if (normalized.length === 0 || normalized === "DEFAULT") {
|
|
27
|
-
return baseKey
|
|
28
|
-
}
|
|
29
|
-
return `${baseKey}__${normalized}`
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const countKeyEntries = (envText: string, baseKey: string): number => {
|
|
33
|
-
const prefix = `${baseKey}__`
|
|
34
|
-
return parseEnvEntries(envText)
|
|
35
|
-
.filter((entry) => entry.value.trim().length > 0 && (entry.key === baseKey || entry.key.startsWith(prefix)))
|
|
36
|
-
.length
|
|
37
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { parseMenuSelection } from "@effect-template/lib/core/domain"
|
|
2
|
-
import { isRepoUrlInput } from "@effect-template/lib/usecases/menu-helpers"
|
|
3
|
-
import { Either } from "effect"
|
|
4
|
-
|
|
5
|
-
import { handleMenuActionSelection, type MenuSelectionContext } from "./menu-actions.js"
|
|
6
|
-
import { startCreateView } from "./menu-create.js"
|
|
7
|
-
import { menuItems } from "./menu-types.js"
|
|
8
|
-
|
|
9
|
-
const handleMenuNavigation = (
|
|
10
|
-
key: { readonly upArrow?: boolean; readonly downArrow?: boolean },
|
|
11
|
-
setSelected: (update: (value: number) => number) => void
|
|
12
|
-
) => {
|
|
13
|
-
if (key.upArrow) {
|
|
14
|
-
setSelected((prev) => (prev === 0 ? menuItems.length - 1 : prev - 1))
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
if (key.downArrow) {
|
|
18
|
-
setSelected((prev) => (prev === menuItems.length - 1 ? 0 : prev + 1))
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const handleMenuEnter = (context: MenuSelectionContext) => {
|
|
23
|
-
const action = menuItems[context.selected]?.id
|
|
24
|
-
if (!action) {
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
|
-
handleMenuActionSelection(action, context)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const handleMenuTextInput = (input: string, context: MenuSelectionContext): boolean => {
|
|
31
|
-
const trimmed = input.trim()
|
|
32
|
-
if (trimmed.length > 0 && isRepoUrlInput(trimmed)) {
|
|
33
|
-
startCreateView(context.setView, context.setMessage, trimmed)
|
|
34
|
-
return true
|
|
35
|
-
}
|
|
36
|
-
const selection = parseMenuSelection(input)
|
|
37
|
-
if (Either.isRight(selection)) {
|
|
38
|
-
handleMenuActionSelection(selection.right, context)
|
|
39
|
-
return true
|
|
40
|
-
}
|
|
41
|
-
return false
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const handleMenuInput = (
|
|
45
|
-
input: string,
|
|
46
|
-
key: { readonly upArrow?: boolean; readonly downArrow?: boolean; readonly return?: boolean },
|
|
47
|
-
context: MenuSelectionContext
|
|
48
|
-
) => {
|
|
49
|
-
if (key.upArrow || key.downArrow) {
|
|
50
|
-
handleMenuNavigation(key, context.setSelected)
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
if (key.return) {
|
|
54
|
-
handleMenuEnter(context)
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
handleMenuTextInput(input, context)
|
|
58
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { PlatformError } from "@effect/platform/Error"
|
|
2
|
-
import type * as FileSystem from "@effect/platform/FileSystem"
|
|
3
|
-
import { Effect } from "effect"
|
|
4
|
-
|
|
5
|
-
const oauthTokenFileName = ".oauth-token"
|
|
6
|
-
const legacyConfigFileName = ".config.json"
|
|
7
|
-
|
|
8
|
-
const hasFileAtPath = (
|
|
9
|
-
fs: FileSystem.FileSystem,
|
|
10
|
-
filePath: string
|
|
11
|
-
): Effect.Effect<boolean, PlatformError> =>
|
|
12
|
-
Effect.gen(function*(_) {
|
|
13
|
-
const exists = yield* _(fs.exists(filePath))
|
|
14
|
-
if (!exists) {
|
|
15
|
-
return false
|
|
16
|
-
}
|
|
17
|
-
const info = yield* _(fs.stat(filePath))
|
|
18
|
-
return info.type === "File"
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
const hasNonEmptyOauthToken = (
|
|
22
|
-
fs: FileSystem.FileSystem,
|
|
23
|
-
tokenPath: string
|
|
24
|
-
): Effect.Effect<boolean, PlatformError> =>
|
|
25
|
-
Effect.gen(function*(_) {
|
|
26
|
-
const hasFile = yield* _(hasFileAtPath(fs, tokenPath))
|
|
27
|
-
if (!hasFile) {
|
|
28
|
-
return false
|
|
29
|
-
}
|
|
30
|
-
const tokenValue = yield* _(fs.readFileString(tokenPath), Effect.orElseSucceed(() => ""))
|
|
31
|
-
return tokenValue.trim().length > 0
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
const hasLegacyClaudeAuthFile = (
|
|
35
|
-
fs: FileSystem.FileSystem,
|
|
36
|
-
accountPath: string
|
|
37
|
-
): Effect.Effect<boolean, PlatformError> =>
|
|
38
|
-
Effect.gen(function*(_) {
|
|
39
|
-
const entries = yield* _(fs.readDirectory(accountPath))
|
|
40
|
-
for (const entry of entries) {
|
|
41
|
-
if (!entry.startsWith(".claude") || !entry.endsWith(".json")) {
|
|
42
|
-
continue
|
|
43
|
-
}
|
|
44
|
-
const isFile = yield* _(hasFileAtPath(fs, `${accountPath}/${entry}`))
|
|
45
|
-
if (isFile) {
|
|
46
|
-
return true
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return false
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
export const hasClaudeAccountCredentials = (
|
|
53
|
-
fs: FileSystem.FileSystem,
|
|
54
|
-
accountPath: string
|
|
55
|
-
): Effect.Effect<boolean, PlatformError> =>
|
|
56
|
-
hasFileAtPath(fs, `${accountPath}/${legacyConfigFileName}`).pipe(
|
|
57
|
-
Effect.flatMap((hasConfig) => {
|
|
58
|
-
if (hasConfig) {
|
|
59
|
-
return Effect.succeed(true)
|
|
60
|
-
}
|
|
61
|
-
return hasNonEmptyOauthToken(fs, `${accountPath}/${oauthTokenFileName}`).pipe(
|
|
62
|
-
Effect.flatMap((hasOauthToken) => {
|
|
63
|
-
if (hasOauthToken) {
|
|
64
|
-
return Effect.succeed(true)
|
|
65
|
-
}
|
|
66
|
-
return hasLegacyClaudeAuthFile(fs, accountPath)
|
|
67
|
-
})
|
|
68
|
-
)
|
|
69
|
-
})
|
|
70
|
-
)
|