@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,220 +0,0 @@
|
|
|
1
|
-
// CHANGE: add Effect-TS compliance lint profile
|
|
2
|
-
// WHY: detect current deviations from strict Effect-TS guidance
|
|
3
|
-
// QUOTE(TZ): n/a
|
|
4
|
-
// REF: AGENTS.md Effect-TS compliance checks
|
|
5
|
-
// SOURCE: n/a
|
|
6
|
-
// PURITY: SHELL
|
|
7
|
-
// EFFECT: eslint config
|
|
8
|
-
// INVARIANT: config only flags explicit policy deviations
|
|
9
|
-
// COMPLEXITY: O(1)/O(1)
|
|
10
|
-
import eslintComments from "@eslint-community/eslint-plugin-eslint-comments"
|
|
11
|
-
import globals from "globals"
|
|
12
|
-
import tseslint from "typescript-eslint"
|
|
13
|
-
|
|
14
|
-
const restrictedImports = [
|
|
15
|
-
{
|
|
16
|
-
name: "node:fs",
|
|
17
|
-
message: "Use @effect/platform FileSystem instead of node:fs."
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: "fs",
|
|
21
|
-
message: "Use @effect/platform FileSystem instead of fs."
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: "node:fs/promises",
|
|
25
|
-
message: "Use @effect/platform FileSystem instead of node:fs/promises."
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: "node:path/posix",
|
|
29
|
-
message: "Use @effect/platform Path instead of node:path/posix."
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
name: "node:path",
|
|
33
|
-
message: "Use @effect/platform Path instead of node:path."
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: "path",
|
|
37
|
-
message: "Use @effect/platform Path instead of path."
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: "node:child_process",
|
|
41
|
-
message: "Use @effect/platform Command instead of node:child_process."
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: "child_process",
|
|
45
|
-
message: "Use @effect/platform Command instead of child_process."
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: "node:process",
|
|
49
|
-
message: "Use @effect/platform Runtime instead of node:process."
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
name: "process",
|
|
53
|
-
message: "Use @effect/platform Runtime instead of process."
|
|
54
|
-
}
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
const restrictedSyntaxBase = [
|
|
58
|
-
{
|
|
59
|
-
selector: "SwitchStatement",
|
|
60
|
-
message: "Switch is forbidden. Use Match.exhaustive."
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
selector: "TryStatement",
|
|
64
|
-
message: "Avoid try/catch in product code. Use Effect.try / Effect.catch*."
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
selector: "AwaitExpression",
|
|
68
|
-
message: "Avoid await. Use Effect.gen / Effect.flatMap."
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
selector: "FunctionDeclaration[async=true], FunctionExpression[async=true], ArrowFunctionExpression[async=true]",
|
|
72
|
-
message: "Avoid async/await. Use Effect.gen / Effect.tryPromise."
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
selector: "NewExpression[callee.name='Promise']",
|
|
76
|
-
message: "Avoid new Promise. Use Effect.async / Effect.tryPromise."
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
selector: "CallExpression[callee.object.name='Promise']",
|
|
80
|
-
message: "Avoid Promise.*. Use Effect combinators."
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
selector: "CallExpression[callee.name='require']",
|
|
84
|
-
message: "Avoid require(). Use ES module imports."
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
selector: "TSAsExpression",
|
|
88
|
-
message: "Casting is only allowed in src/core/axioms.ts."
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
selector: "TSTypeAssertion",
|
|
92
|
-
message: "Casting is only allowed in src/core/axioms.ts."
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
selector: "CallExpression[callee.name='makeFilesystemService']",
|
|
96
|
-
message: "Do not instantiate FilesystemService directly. Provide Layer and access via Tag."
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
selector: "CallExpression[callee.property.name='catchAll']",
|
|
100
|
-
message: "Avoid catchAll that discards typed errors; map or propagate explicitly."
|
|
101
|
-
}
|
|
102
|
-
]
|
|
103
|
-
|
|
104
|
-
const restrictedSyntaxCore = [
|
|
105
|
-
...restrictedSyntaxBase,
|
|
106
|
-
{
|
|
107
|
-
selector: "TSUnknownKeyword",
|
|
108
|
-
message: "unknown is allowed only at shell boundaries with decoding."
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
selector: "CallExpression[callee.property.name='runSyncExit']",
|
|
112
|
-
message: "Effect.runSyncExit is shell-only. Move to a runner."
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
selector: "CallExpression[callee.property.name='runSync']",
|
|
116
|
-
message: "Effect.runSync is shell-only. Move to a runner."
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
selector: "CallExpression[callee.property.name='runPromise']",
|
|
120
|
-
message: "Effect.runPromise is shell-only. Move to a runner."
|
|
121
|
-
}
|
|
122
|
-
]
|
|
123
|
-
|
|
124
|
-
const restrictedSyntaxCoreNoAs = [
|
|
125
|
-
...restrictedSyntaxCore.filter((rule) =>
|
|
126
|
-
rule.selector !== "TSAsExpression" && rule.selector !== "TSTypeAssertion"
|
|
127
|
-
)
|
|
128
|
-
]
|
|
129
|
-
|
|
130
|
-
const restrictedSyntaxBaseNoServiceFactory = [
|
|
131
|
-
...restrictedSyntaxBase.filter((rule) =>
|
|
132
|
-
rule.selector !== "CallExpression[callee.name='makeFilesystemService']"
|
|
133
|
-
)
|
|
134
|
-
]
|
|
135
|
-
|
|
136
|
-
export default tseslint.config(
|
|
137
|
-
{
|
|
138
|
-
name: "effect-ts-compliance-check",
|
|
139
|
-
files: ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts"],
|
|
140
|
-
languageOptions: {
|
|
141
|
-
parser: tseslint.parser,
|
|
142
|
-
globals: { ...globals.node }
|
|
143
|
-
},
|
|
144
|
-
plugins: {
|
|
145
|
-
"@typescript-eslint": tseslint.plugin,
|
|
146
|
-
"eslint-comments": eslintComments
|
|
147
|
-
},
|
|
148
|
-
rules: {
|
|
149
|
-
"no-console": "error",
|
|
150
|
-
"no-restricted-imports": ["error", {
|
|
151
|
-
paths: restrictedImports,
|
|
152
|
-
patterns: [
|
|
153
|
-
{
|
|
154
|
-
group: ["node:*"],
|
|
155
|
-
message: "Do not import from node:* directly. Use @effect/platform-node or @effect/platform services."
|
|
156
|
-
}
|
|
157
|
-
]
|
|
158
|
-
}],
|
|
159
|
-
"no-restricted-syntax": ["error", ...restrictedSyntaxBase],
|
|
160
|
-
"@typescript-eslint/no-explicit-any": "error",
|
|
161
|
-
"@typescript-eslint/ban-ts-comment": ["error", {
|
|
162
|
-
"ts-ignore": true,
|
|
163
|
-
"ts-nocheck": true,
|
|
164
|
-
"ts-check": false,
|
|
165
|
-
"ts-expect-error": true
|
|
166
|
-
}],
|
|
167
|
-
"@typescript-eslint/no-restricted-types": ["error", {
|
|
168
|
-
types: {
|
|
169
|
-
Promise: {
|
|
170
|
-
message: "Avoid Promise in types. Use Effect.Effect<A, E, R>."
|
|
171
|
-
},
|
|
172
|
-
"Promise<*>": {
|
|
173
|
-
message: "Avoid Promise<T>. Use Effect.Effect<T, E, R>."
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}],
|
|
177
|
-
"eslint-comments/no-use": "error",
|
|
178
|
-
"eslint-comments/no-unlimited-disable": "error",
|
|
179
|
-
"eslint-comments/disable-enable-pair": "error",
|
|
180
|
-
"eslint-comments/no-unused-disable": "error"
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
name: "effect-ts-compliance-core",
|
|
185
|
-
files: ["src/core/**/*.ts"],
|
|
186
|
-
rules: {
|
|
187
|
-
"no-restricted-syntax": ["error", ...restrictedSyntaxCore],
|
|
188
|
-
"no-restricted-imports": ["error", {
|
|
189
|
-
paths: restrictedImports,
|
|
190
|
-
patterns: [
|
|
191
|
-
{
|
|
192
|
-
group: [
|
|
193
|
-
"../shell/**",
|
|
194
|
-
"../../shell/**",
|
|
195
|
-
"../../../shell/**",
|
|
196
|
-
"./shell/**",
|
|
197
|
-
"src/shell/**",
|
|
198
|
-
"shell/**"
|
|
199
|
-
],
|
|
200
|
-
message: "CORE must not import from SHELL."
|
|
201
|
-
}
|
|
202
|
-
]
|
|
203
|
-
}]
|
|
204
|
-
}
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
name: "effect-ts-compliance-axioms",
|
|
208
|
-
files: ["src/core/axioms.ts"],
|
|
209
|
-
rules: {
|
|
210
|
-
"no-restricted-syntax": ["error", ...restrictedSyntaxCoreNoAs]
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
name: "effect-ts-compliance-filesystem-service",
|
|
215
|
-
files: ["src/shell/services/filesystem.ts"],
|
|
216
|
-
rules: {
|
|
217
|
-
"no-restricted-syntax": ["error", ...restrictedSyntaxBaseNoServiceFactory]
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
)
|
package/linter.config.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"priorityLevels": [
|
|
3
|
-
{
|
|
4
|
-
"level": 1,
|
|
5
|
-
"name": "Critical Compiler Errors",
|
|
6
|
-
"rules": [
|
|
7
|
-
"ts(2835)",
|
|
8
|
-
"ts(2307)",
|
|
9
|
-
"@prover-coder-ai/suggest-members/suggest-members",
|
|
10
|
-
"@prover-coder-ai/suggest-members/suggest-imports",
|
|
11
|
-
"@prover-coder-ai/suggest-members/suggest-module-paths",
|
|
12
|
-
"@prover-coder-ai/suggest-members/suggest-exports",
|
|
13
|
-
"@prover-coder-ai/suggest-members/suggest-missing-names",
|
|
14
|
-
"@typescript-eslint/no-explicit-any"
|
|
15
|
-
]
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"level": 2,
|
|
19
|
-
"name": "Critical Compiler Errors",
|
|
20
|
-
"rules": ["all"]
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"level": 3,
|
|
24
|
-
"name": "Critical Compiler Errors (Code must follow Clean Code and best practices)",
|
|
25
|
-
"rules": ["max-lines-per-function", "max-lines"]
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"level": 4,
|
|
29
|
-
"name": "Critical Compiler Errors (Code must follow Clean Code and best practices)",
|
|
30
|
-
"rules": ["complexity", "max-params", "max-depth"]
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
}
|
package/src/app/main.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { NodeContext, NodeRuntime } from "@effect/platform-node"
|
|
2
|
-
import { Effect, pipe } from "effect"
|
|
3
|
-
|
|
4
|
-
import { program } from "./program.js"
|
|
5
|
-
|
|
6
|
-
// CHANGE: run the program through the Node platform runtime with its layer
|
|
7
|
-
// WHY: ensure effects execute under the platform runtime with proper teardown/logging behavior
|
|
8
|
-
// QUOTE(TZ): "\u0414\u0430 \u0434\u0430\u0432\u0430\u0439 \u0442\u0430\u043a \u044d\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f"
|
|
9
|
-
// REF: user-2025-12-19-platform-node
|
|
10
|
-
// SOURCE: https://effect.website/docs/platform/runtime/ "runMain helps you execute a main effect with built-in error handling, logging, and signal management."
|
|
11
|
-
// FORMAT THEOREM: forall args in Argv: decode(args) = v -> runMain(program)
|
|
12
|
-
// PURITY: SHELL
|
|
13
|
-
// EFFECT: Effect<string, S.ParseError, Console>
|
|
14
|
-
// INVARIANT: program executed with NodeContext.layer
|
|
15
|
-
// COMPLEXITY: O(1)/O(1)
|
|
16
|
-
const main = pipe(program, Effect.provide(NodeContext.layer))
|
|
17
|
-
|
|
18
|
-
NodeRuntime.runMain(main)
|
package/src/app/program.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { listProjects, readCloneRequest, runDockerGitClone } from "@effect-template/lib"
|
|
2
|
-
import { Console, Effect, Match, pipe } from "effect"
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Compose the CLI program as a single effect.
|
|
6
|
-
*
|
|
7
|
-
* @returns Effect that either runs docker-git clone or prints usage.
|
|
8
|
-
*
|
|
9
|
-
* @pure false - uses Console output and spawns commands when cloning
|
|
10
|
-
* @effect Console, CommandExecutor, Path
|
|
11
|
-
* @invariant forall args in Argv: clone(args) -> docker_git_invoked(args)
|
|
12
|
-
* @precondition true
|
|
13
|
-
* @postcondition clone(args) -> docker_git_invoked(args); otherwise usage printed
|
|
14
|
-
* @complexity O(build + clone)
|
|
15
|
-
* @throws Never - all errors are typed in the Effect error channel
|
|
16
|
-
*/
|
|
17
|
-
// CHANGE: replace greeting demo with deterministic usage text
|
|
18
|
-
// WHY: greeting was scaffolding noise and should not ship in docker-git tooling
|
|
19
|
-
// QUOTE(ТЗ): "Можешь удалить использование greting ...? Это старый мусор который остался"
|
|
20
|
-
// REF: user-request-2026-02-06-remove-greeting
|
|
21
|
-
// SOURCE: n/a
|
|
22
|
-
// FORMAT THEOREM: usageText is constant -> deterministic(help)
|
|
23
|
-
// PURITY: CORE
|
|
24
|
-
// EFFECT: n/a
|
|
25
|
-
// INVARIANT: usageText does not depend on argv/env
|
|
26
|
-
// COMPLEXITY: O(1)
|
|
27
|
-
const usageText = [
|
|
28
|
-
"Usage:",
|
|
29
|
-
" pnpm docker-git",
|
|
30
|
-
" pnpm clone <repo-url> [ref]",
|
|
31
|
-
" pnpm list",
|
|
32
|
-
"",
|
|
33
|
-
"Notes:",
|
|
34
|
-
" - docker-git is the interactive TUI.",
|
|
35
|
-
" - clone builds + runs docker-git clone for you."
|
|
36
|
-
].join("\n")
|
|
37
|
-
|
|
38
|
-
// PURITY: SHELL
|
|
39
|
-
// EFFECT: Effect<void, never, Console>
|
|
40
|
-
const runHelp = Console.log(usageText)
|
|
41
|
-
|
|
42
|
-
// CHANGE: route between clone runner and help based on CLI context
|
|
43
|
-
// WHY: allow pnpm run clone <url> while keeping a single entrypoint
|
|
44
|
-
// QUOTE(ТЗ): "pnpm run clone <url>"
|
|
45
|
-
// REF: user-request-2026-01-27
|
|
46
|
-
// SOURCE: n/a
|
|
47
|
-
// FORMAT THEOREM: forall argv: clone(argv) -> docker_git_invoked(argv)
|
|
48
|
-
// PURITY: SHELL
|
|
49
|
-
// EFFECT: Effect<void, Error, Console | CommandExecutor | Path>
|
|
50
|
-
// INVARIANT: help is printed when clone is not requested
|
|
51
|
-
// COMPLEXITY: O(build + clone)
|
|
52
|
-
const runDockerGit = pipe(
|
|
53
|
-
readCloneRequest,
|
|
54
|
-
Effect.flatMap((request) =>
|
|
55
|
-
Match.value(request).pipe(
|
|
56
|
-
Match.when({ _tag: "Clone" }, ({ args }) => runDockerGitClone(args)),
|
|
57
|
-
Match.when({ _tag: "None" }, () => runHelp),
|
|
58
|
-
Match.exhaustive
|
|
59
|
-
)
|
|
60
|
-
)
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
const readListFlag = Effect.sync(() => {
|
|
64
|
-
const command = process.argv.slice(2)[0] ?? ""
|
|
65
|
-
return command === "list" || command === "ls"
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
export const program = Effect.gen(function*(_) {
|
|
69
|
-
const isList = yield* _(readListFlag)
|
|
70
|
-
if (isList) {
|
|
71
|
-
yield* _(listProjects)
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
yield* _(runDockerGit)
|
|
75
|
-
})
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import * as Terminal from "@effect/platform/Terminal"
|
|
2
|
-
import { Effect } from "effect"
|
|
3
|
-
|
|
4
|
-
import { InputCancelledError, InputReadError } from "@effect-template/lib/shell/errors"
|
|
5
|
-
|
|
6
|
-
const normalizeMessage = (error: Error): string => error.message
|
|
7
|
-
|
|
8
|
-
const toReadError = (error: Error): InputReadError => new InputReadError({ message: normalizeMessage(error) })
|
|
9
|
-
|
|
10
|
-
const mapReadLineError = (_error: Terminal.QuitException): InputCancelledError => new InputCancelledError({})
|
|
11
|
-
|
|
12
|
-
// CHANGE: prompt for a single line of user input
|
|
13
|
-
// WHY: provide an interactive CLI without raw terminal mode issues
|
|
14
|
-
// QUOTE(ТЗ): "Хочу что бы открылось менюшка"
|
|
15
|
-
// REF: user-request-2026-01-07
|
|
16
|
-
// SOURCE: n/a
|
|
17
|
-
// FORMAT THEOREM: forall p: prompt(p) -> line(p)
|
|
18
|
-
// PURITY: SHELL
|
|
19
|
-
// EFFECT: Effect<string, InputCancelledError | InputReadError, never>
|
|
20
|
-
// INVARIANT: restores raw mode if it was enabled before prompting
|
|
21
|
-
// COMPLEXITY: O(1)
|
|
22
|
-
export const promptLine = (
|
|
23
|
-
prompt: string
|
|
24
|
-
): Effect.Effect<string, InputCancelledError | InputReadError, Terminal.Terminal> =>
|
|
25
|
-
Effect.gen(function*(_) {
|
|
26
|
-
const terminal = yield* _(Terminal.Terminal)
|
|
27
|
-
yield* _(terminal.display(prompt).pipe(Effect.mapError(toReadError)))
|
|
28
|
-
return yield* _(terminal.readLine.pipe(Effect.mapError(mapReadLineError)))
|
|
29
|
-
})
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Either } from "effect"
|
|
2
|
-
|
|
3
|
-
import { type ApplyCommand, type ParseError } from "@effect-template/lib/core/domain"
|
|
4
|
-
|
|
5
|
-
import { parseProjectDirWithOptions } from "./parser-shared.js"
|
|
6
|
-
|
|
7
|
-
// CHANGE: parse "apply" command for existing docker-git projects
|
|
8
|
-
// WHY: update managed docker-git config on the current project/container without creating a new project
|
|
9
|
-
// QUOTE(ТЗ): "Не создавать новый... а прямо в текущем обновить её на актуальную"
|
|
10
|
-
// REF: issue-72-followup-apply-current-config
|
|
11
|
-
// SOURCE: n/a
|
|
12
|
-
// FORMAT THEOREM: forall argv: parseApply(argv) = cmd -> deterministic(cmd)
|
|
13
|
-
// PURITY: CORE
|
|
14
|
-
// EFFECT: Effect<ApplyCommand, ParseError, never>
|
|
15
|
-
// INVARIANT: projectDir is never empty
|
|
16
|
-
// COMPLEXITY: O(n) where n = |argv|
|
|
17
|
-
export const parseApply = (
|
|
18
|
-
args: ReadonlyArray<string>
|
|
19
|
-
): Either.Either<ApplyCommand, ParseError> =>
|
|
20
|
-
Either.map(parseProjectDirWithOptions(args), ({ projectDir, raw }) => ({
|
|
21
|
-
_tag: "Apply",
|
|
22
|
-
projectDir,
|
|
23
|
-
runUp: raw.up ?? true,
|
|
24
|
-
gitTokenLabel: raw.gitTokenLabel,
|
|
25
|
-
codexTokenLabel: raw.codexTokenLabel,
|
|
26
|
-
claudeTokenLabel: raw.claudeTokenLabel,
|
|
27
|
-
enableMcpPlaywright: raw.enableMcpPlaywright
|
|
28
|
-
}))
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Either } from "effect"
|
|
2
|
-
|
|
3
|
-
import { type AttachCommand, type ParseError } from "@effect-template/lib/core/domain"
|
|
4
|
-
|
|
5
|
-
import { parseProjectDirArgs } from "./parser-shared.js"
|
|
6
|
-
|
|
7
|
-
// CHANGE: parse attach command into a project selection
|
|
8
|
-
// WHY: allow "docker-git attach" to open a tmux workspace
|
|
9
|
-
// QUOTE(ТЗ): "окей Давай подключим tmux"
|
|
10
|
-
// REF: user-request-2026-02-02-tmux
|
|
11
|
-
// SOURCE: n/a
|
|
12
|
-
// FORMAT THEOREM: forall argv: parseAttach(argv) = cmd -> deterministic(cmd)
|
|
13
|
-
// PURITY: CORE
|
|
14
|
-
// EFFECT: Effect<AttachCommand, ParseError, never>
|
|
15
|
-
// INVARIANT: projectDir is never empty
|
|
16
|
-
// COMPLEXITY: O(n) where n = |argv|
|
|
17
|
-
export const parseAttach = (args: ReadonlyArray<string>): Either.Either<AttachCommand, ParseError> => {
|
|
18
|
-
return Either.map(parseProjectDirArgs(args), ({ projectDir }) => ({
|
|
19
|
-
_tag: "Attach",
|
|
20
|
-
projectDir
|
|
21
|
-
}))
|
|
22
|
-
}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { Either, Match } from "effect"
|
|
2
|
-
|
|
3
|
-
import type { RawOptions } from "@effect-template/lib/core/command-options"
|
|
4
|
-
import { type AuthCommand, type Command, type ParseError } from "@effect-template/lib/core/domain"
|
|
5
|
-
|
|
6
|
-
import { parseRawOptions } from "./parser-options.js"
|
|
7
|
-
|
|
8
|
-
type AuthOptions = {
|
|
9
|
-
readonly envGlobalPath: string
|
|
10
|
-
readonly codexAuthPath: string
|
|
11
|
-
readonly claudeAuthPath: string
|
|
12
|
-
readonly label: string | null
|
|
13
|
-
readonly token: string | null
|
|
14
|
-
readonly scopes: string | null
|
|
15
|
-
readonly authWeb: boolean
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const missingArgument = (name: string): ParseError => ({
|
|
19
|
-
_tag: "MissingRequiredOption",
|
|
20
|
-
option: name
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const invalidArgument = (name: string, reason: string): ParseError => ({
|
|
24
|
-
_tag: "InvalidOption",
|
|
25
|
-
option: name,
|
|
26
|
-
reason
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
const normalizeLabel = (value: string | undefined): string | null => {
|
|
30
|
-
const trimmed = value?.trim() ?? ""
|
|
31
|
-
return trimmed.length === 0 ? null : trimmed
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const defaultEnvGlobalPath = ".docker-git/.orch/env/global.env"
|
|
35
|
-
const defaultCodexAuthPath = ".docker-git/.orch/auth/codex"
|
|
36
|
-
const defaultClaudeAuthPath = ".docker-git/.orch/auth/claude"
|
|
37
|
-
|
|
38
|
-
const resolveAuthOptions = (raw: RawOptions): AuthOptions => ({
|
|
39
|
-
envGlobalPath: raw.envGlobalPath ?? defaultEnvGlobalPath,
|
|
40
|
-
codexAuthPath: raw.codexAuthPath ?? defaultCodexAuthPath,
|
|
41
|
-
claudeAuthPath: defaultClaudeAuthPath,
|
|
42
|
-
label: normalizeLabel(raw.label),
|
|
43
|
-
token: normalizeLabel(raw.token),
|
|
44
|
-
scopes: normalizeLabel(raw.scopes),
|
|
45
|
-
authWeb: raw.authWeb === true
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
const buildGithubCommand = (action: string, options: AuthOptions): Either.Either<AuthCommand, ParseError> =>
|
|
49
|
-
Match.value(action).pipe(
|
|
50
|
-
Match.when("login", () =>
|
|
51
|
-
options.authWeb && options.token !== null
|
|
52
|
-
? Either.left(invalidArgument("--token", "cannot be combined with --web"))
|
|
53
|
-
: Either.right<AuthCommand>({
|
|
54
|
-
_tag: "AuthGithubLogin",
|
|
55
|
-
label: options.label,
|
|
56
|
-
token: options.authWeb ? null : options.token,
|
|
57
|
-
scopes: options.scopes,
|
|
58
|
-
envGlobalPath: options.envGlobalPath
|
|
59
|
-
})),
|
|
60
|
-
Match.when("status", () =>
|
|
61
|
-
Either.right<AuthCommand>({
|
|
62
|
-
_tag: "AuthGithubStatus",
|
|
63
|
-
envGlobalPath: options.envGlobalPath
|
|
64
|
-
})),
|
|
65
|
-
Match.when("logout", () =>
|
|
66
|
-
Either.right<AuthCommand>({
|
|
67
|
-
_tag: "AuthGithubLogout",
|
|
68
|
-
label: options.label,
|
|
69
|
-
envGlobalPath: options.envGlobalPath
|
|
70
|
-
})),
|
|
71
|
-
Match.orElse(() => Either.left(invalidArgument("auth action", `unknown action '${action}'`)))
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
const buildCodexCommand = (action: string, options: AuthOptions): Either.Either<AuthCommand, ParseError> =>
|
|
75
|
-
Match.value(action).pipe(
|
|
76
|
-
Match.when("login", () =>
|
|
77
|
-
Either.right<AuthCommand>({
|
|
78
|
-
_tag: "AuthCodexLogin",
|
|
79
|
-
label: options.label,
|
|
80
|
-
codexAuthPath: options.codexAuthPath
|
|
81
|
-
})),
|
|
82
|
-
Match.when("status", () =>
|
|
83
|
-
Either.right<AuthCommand>({
|
|
84
|
-
_tag: "AuthCodexStatus",
|
|
85
|
-
label: options.label,
|
|
86
|
-
codexAuthPath: options.codexAuthPath
|
|
87
|
-
})),
|
|
88
|
-
Match.when("logout", () =>
|
|
89
|
-
Either.right<AuthCommand>({
|
|
90
|
-
_tag: "AuthCodexLogout",
|
|
91
|
-
label: options.label,
|
|
92
|
-
codexAuthPath: options.codexAuthPath
|
|
93
|
-
})),
|
|
94
|
-
Match.orElse(() => Either.left(invalidArgument("auth action", `unknown action '${action}'`)))
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
const buildClaudeCommand = (action: string, options: AuthOptions): Either.Either<AuthCommand, ParseError> =>
|
|
98
|
-
Match.value(action).pipe(
|
|
99
|
-
Match.when("login", () =>
|
|
100
|
-
Either.right<AuthCommand>({
|
|
101
|
-
_tag: "AuthClaudeLogin",
|
|
102
|
-
label: options.label,
|
|
103
|
-
claudeAuthPath: options.claudeAuthPath
|
|
104
|
-
})),
|
|
105
|
-
Match.when("status", () =>
|
|
106
|
-
Either.right<AuthCommand>({
|
|
107
|
-
_tag: "AuthClaudeStatus",
|
|
108
|
-
label: options.label,
|
|
109
|
-
claudeAuthPath: options.claudeAuthPath
|
|
110
|
-
})),
|
|
111
|
-
Match.when("logout", () =>
|
|
112
|
-
Either.right<AuthCommand>({
|
|
113
|
-
_tag: "AuthClaudeLogout",
|
|
114
|
-
label: options.label,
|
|
115
|
-
claudeAuthPath: options.claudeAuthPath
|
|
116
|
-
})),
|
|
117
|
-
Match.orElse(() => Either.left(invalidArgument("auth action", `unknown action '${action}'`)))
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
const buildAuthCommand = (
|
|
121
|
-
provider: string,
|
|
122
|
-
action: string,
|
|
123
|
-
options: AuthOptions
|
|
124
|
-
): Either.Either<AuthCommand, ParseError> =>
|
|
125
|
-
Match.value(provider).pipe(
|
|
126
|
-
Match.when("github", () => buildGithubCommand(action, options)),
|
|
127
|
-
Match.when("gh", () => buildGithubCommand(action, options)),
|
|
128
|
-
Match.when("codex", () => buildCodexCommand(action, options)),
|
|
129
|
-
Match.when("claude", () => buildClaudeCommand(action, options)),
|
|
130
|
-
Match.when("cc", () => buildClaudeCommand(action, options)),
|
|
131
|
-
Match.orElse(() => Either.left(invalidArgument("auth provider", `unknown provider '${provider}'`)))
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
// CHANGE: parse docker-git auth subcommands
|
|
135
|
-
// WHY: keep auth flows in the same typed CLI parser
|
|
136
|
-
// QUOTE(ТЗ): "система авторизации"
|
|
137
|
-
// REF: user-request-2026-01-28-auth
|
|
138
|
-
// SOURCE: n/a
|
|
139
|
-
// FORMAT THEOREM: forall argv: parseAuth(argv) = cmd | error
|
|
140
|
-
// PURITY: CORE
|
|
141
|
-
// EFFECT: Effect<Command, ParseError, never>
|
|
142
|
-
// INVARIANT: no IO or side effects
|
|
143
|
-
// COMPLEXITY: O(n) where n = |argv|
|
|
144
|
-
export const parseAuth = (args: ReadonlyArray<string>): Either.Either<Command, ParseError> => {
|
|
145
|
-
if (args.length < 2) {
|
|
146
|
-
return Either.left(missingArgument(args.length === 0 ? "auth provider" : "auth action"))
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const provider = args[0] ?? ""
|
|
150
|
-
const action = args[1] ?? ""
|
|
151
|
-
const rest = args.slice(2)
|
|
152
|
-
|
|
153
|
-
return Either.flatMap(parseRawOptions(rest), (raw) => buildAuthCommand(provider, action, resolveAuthOptions(raw)))
|
|
154
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { Either } from "effect"
|
|
2
|
-
|
|
3
|
-
import { buildCreateCommand, nonEmpty } from "@effect-template/lib/core/command-builders"
|
|
4
|
-
import type { RawOptions } from "@effect-template/lib/core/command-options"
|
|
5
|
-
import { type Command, type ParseError, resolveRepoInput } from "@effect-template/lib/core/domain"
|
|
6
|
-
|
|
7
|
-
import { parseRawOptions } from "./parser-options.js"
|
|
8
|
-
import { resolveWorkspaceRepoPath, splitPositionalRepo } from "./parser-shared.js"
|
|
9
|
-
|
|
10
|
-
const applyCloneDefaults = (
|
|
11
|
-
raw: RawOptions,
|
|
12
|
-
rawRepoUrl: string,
|
|
13
|
-
resolvedRepo: ReturnType<typeof resolveRepoInput>
|
|
14
|
-
): RawOptions => {
|
|
15
|
-
const repoPath = resolveWorkspaceRepoPath(resolvedRepo)
|
|
16
|
-
const targetHome = "~"
|
|
17
|
-
return {
|
|
18
|
-
...raw,
|
|
19
|
-
repoUrl: rawRepoUrl,
|
|
20
|
-
outDir: raw.outDir ?? `.docker-git/${repoPath}`,
|
|
21
|
-
targetDir: raw.targetDir ?? `${targetHome}/workspaces/${repoPath}`
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// CHANGE: parse clone command with positional repo url
|
|
26
|
-
// WHY: allow "docker-git clone <url>" to build + run a container
|
|
27
|
-
// QUOTE(ТЗ): "docker-git clone url"
|
|
28
|
-
// REF: user-request-2026-01-27
|
|
29
|
-
// SOURCE: n/a
|
|
30
|
-
// FORMAT THEOREM: forall argv: parseClone(argv) = cmd -> deterministic(cmd)
|
|
31
|
-
// PURITY: CORE
|
|
32
|
-
// EFFECT: Effect<Command, ParseError, never>
|
|
33
|
-
// INVARIANT: first positional arg is treated as repo url
|
|
34
|
-
// COMPLEXITY: O(n) where n = |argv|
|
|
35
|
-
export const parseClone = (args: ReadonlyArray<string>): Either.Either<Command, ParseError> => {
|
|
36
|
-
const { positionalRepoUrl, restArgs } = splitPositionalRepo(args)
|
|
37
|
-
|
|
38
|
-
return Either.gen(function*(_) {
|
|
39
|
-
const raw = yield* _(parseRawOptions(restArgs))
|
|
40
|
-
const rawRepoUrl = yield* _(nonEmpty("--repo-url", raw.repoUrl ?? positionalRepoUrl))
|
|
41
|
-
const resolvedRepo = resolveRepoInput(rawRepoUrl)
|
|
42
|
-
const withDefaults = applyCloneDefaults(raw, rawRepoUrl, resolvedRepo)
|
|
43
|
-
const withRef = resolvedRepo.repoRef !== undefined && raw.repoRef === undefined
|
|
44
|
-
? { ...withDefaults, repoRef: resolvedRepo.repoRef }
|
|
45
|
-
: withDefaults
|
|
46
|
-
const openSsh = raw.openSsh ?? true
|
|
47
|
-
const create = yield* _(buildCreateCommand(withRef))
|
|
48
|
-
return { ...create, waitForClone: true, openSsh }
|
|
49
|
-
})
|
|
50
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Either } from "effect"
|
|
2
|
-
|
|
3
|
-
import { type McpPlaywrightUpCommand, type ParseError } from "@effect-template/lib/core/domain"
|
|
4
|
-
|
|
5
|
-
import { parseProjectDirWithOptions } from "./parser-shared.js"
|
|
6
|
-
|
|
7
|
-
// CHANGE: parse "mcp-playwright" command for existing docker-git projects
|
|
8
|
-
// WHY: allow enabling Playwright MCP in an already created container/project dir
|
|
9
|
-
// QUOTE(ТЗ): "Добавить возможность поднимать MCP Playrgiht в контейнере который уже создан"
|
|
10
|
-
// REF: issue-29
|
|
11
|
-
// SOURCE: n/a
|
|
12
|
-
// FORMAT THEOREM: forall argv: parseMcpPlaywright(argv) = cmd -> deterministic(cmd)
|
|
13
|
-
// PURITY: CORE
|
|
14
|
-
// EFFECT: Effect<McpPlaywrightUpCommand, ParseError, never>
|
|
15
|
-
// INVARIANT: projectDir is never empty
|
|
16
|
-
// COMPLEXITY: O(n) where n = |argv|
|
|
17
|
-
export const parseMcpPlaywright = (
|
|
18
|
-
args: ReadonlyArray<string>
|
|
19
|
-
): Either.Either<McpPlaywrightUpCommand, ParseError> =>
|
|
20
|
-
Either.map(parseProjectDirWithOptions(args), ({ projectDir, raw }) => ({
|
|
21
|
-
_tag: "McpPlaywrightUp",
|
|
22
|
-
projectDir,
|
|
23
|
-
runUp: raw.up ?? true
|
|
24
|
-
}))
|