@prover-coder-ai/docker-git 1.0.20 → 1.0.21
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/.package.json.release.bak +1 -1
- package/CHANGELOG.md +6 -0
- package/dist/main.js +60 -35
- package/dist/main.js.map +1 -1
- package/dist/src/docker-git/cli/parser-apply.js +22 -0
- package/dist/src/docker-git/cli/parser-clone.js +3 -4
- package/dist/src/docker-git/cli/parser-options.js +44 -19
- package/dist/src/docker-git/cli/parser.js +2 -1
- package/dist/src/docker-git/cli/usage.js +6 -1
- package/dist/src/docker-git/program.js +2 -1
- package/package.json +1 -1
- package/src/docker-git/cli/parser-apply.ts +28 -0
- package/src/docker-git/cli/parser-clone.ts +3 -9
- package/src/docker-git/cli/parser-options.ts +65 -22
- package/src/docker-git/cli/parser.ts +2 -0
- package/src/docker-git/cli/usage.ts +6 -1
- package/src/docker-git/program.ts +2 -0
- package/tests/docker-git/entrypoint-auth.test.ts +14 -3
- package/tests/docker-git/parser.test.ts +89 -17
package/CHANGELOG.md
CHANGED
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NodeContext, NodeRuntime } from "@effect/platform-node";
|
|
2
|
-
import { Match, Effect, pipe,
|
|
2
|
+
import { Data, Match, Effect, pipe, Either, Duration, Console } from "effect";
|
|
3
3
|
import * as CommandExecutor from "@effect/platform/CommandExecutor";
|
|
4
4
|
import { ExitCode } from "@effect/platform/CommandExecutor";
|
|
5
5
|
import * as Path from "@effect/platform/Path";
|
|
@@ -28,6 +28,36 @@ const resolveCloneRequest = (argv, npmLifecycleEvent) => {
|
|
|
28
28
|
}
|
|
29
29
|
return emptyRequest;
|
|
30
30
|
};
|
|
31
|
+
class FileExistsError extends Data.TaggedError("FileExistsError") {
|
|
32
|
+
}
|
|
33
|
+
class ConfigNotFoundError extends Data.TaggedError("ConfigNotFoundError") {
|
|
34
|
+
}
|
|
35
|
+
class ConfigDecodeError extends Data.TaggedError("ConfigDecodeError") {
|
|
36
|
+
}
|
|
37
|
+
class InputCancelledError extends Data.TaggedError("InputCancelledError") {
|
|
38
|
+
}
|
|
39
|
+
class InputReadError extends Data.TaggedError("InputReadError") {
|
|
40
|
+
}
|
|
41
|
+
class DockerCommandError extends Data.TaggedError("DockerCommandError") {
|
|
42
|
+
}
|
|
43
|
+
class DockerAccessError extends Data.TaggedError("DockerAccessError") {
|
|
44
|
+
}
|
|
45
|
+
class CloneFailedError extends Data.TaggedError("CloneFailedError") {
|
|
46
|
+
}
|
|
47
|
+
class PortProbeError extends Data.TaggedError("PortProbeError") {
|
|
48
|
+
}
|
|
49
|
+
class CommandFailedError extends Data.TaggedError("CommandFailedError") {
|
|
50
|
+
}
|
|
51
|
+
class AuthError extends Data.TaggedError("AuthError") {
|
|
52
|
+
}
|
|
53
|
+
class ScrapArchiveNotFoundError extends Data.TaggedError("ScrapArchiveNotFoundError") {
|
|
54
|
+
}
|
|
55
|
+
class ScrapArchiveInvalidError extends Data.TaggedError("ScrapArchiveInvalidError") {
|
|
56
|
+
}
|
|
57
|
+
class ScrapTargetDirUnsupportedError extends Data.TaggedError("ScrapTargetDirUnsupportedError") {
|
|
58
|
+
}
|
|
59
|
+
class ScrapWipeRefusedError extends Data.TaggedError("ScrapWipeRefusedError") {
|
|
60
|
+
}
|
|
31
61
|
const trimLeftChar = (value, char) => {
|
|
32
62
|
let start = 0;
|
|
33
63
|
while (start < value.length && value[start] === char) {
|
|
@@ -160,36 +190,6 @@ const runCommandCapture = (spec, okExitCodes, onFailure) => Effect.scoped(Effect
|
|
|
160
190
|
yield* _(ensureExitCode(Number(exitCode), okExitCodes, onFailure));
|
|
161
191
|
return new TextDecoder("utf-8").decode(bytes);
|
|
162
192
|
}));
|
|
163
|
-
class FileExistsError extends Data.TaggedError("FileExistsError") {
|
|
164
|
-
}
|
|
165
|
-
class ConfigNotFoundError extends Data.TaggedError("ConfigNotFoundError") {
|
|
166
|
-
}
|
|
167
|
-
class ConfigDecodeError extends Data.TaggedError("ConfigDecodeError") {
|
|
168
|
-
}
|
|
169
|
-
class InputCancelledError extends Data.TaggedError("InputCancelledError") {
|
|
170
|
-
}
|
|
171
|
-
class InputReadError extends Data.TaggedError("InputReadError") {
|
|
172
|
-
}
|
|
173
|
-
class DockerCommandError extends Data.TaggedError("DockerCommandError") {
|
|
174
|
-
}
|
|
175
|
-
class DockerAccessError extends Data.TaggedError("DockerAccessError") {
|
|
176
|
-
}
|
|
177
|
-
class CloneFailedError extends Data.TaggedError("CloneFailedError") {
|
|
178
|
-
}
|
|
179
|
-
class PortProbeError extends Data.TaggedError("PortProbeError") {
|
|
180
|
-
}
|
|
181
|
-
class CommandFailedError extends Data.TaggedError("CommandFailedError") {
|
|
182
|
-
}
|
|
183
|
-
class AuthError extends Data.TaggedError("AuthError") {
|
|
184
|
-
}
|
|
185
|
-
class ScrapArchiveNotFoundError extends Data.TaggedError("ScrapArchiveNotFoundError") {
|
|
186
|
-
}
|
|
187
|
-
class ScrapArchiveInvalidError extends Data.TaggedError("ScrapArchiveInvalidError") {
|
|
188
|
-
}
|
|
189
|
-
class ScrapTargetDirUnsupportedError extends Data.TaggedError("ScrapTargetDirUnsupportedError") {
|
|
190
|
-
}
|
|
191
|
-
class ScrapWipeRefusedError extends Data.TaggedError("ScrapWipeRefusedError") {
|
|
192
|
-
}
|
|
193
193
|
const successExitCode$1 = Number(ExitCode(0));
|
|
194
194
|
const readCloneRequest = Effect.sync(() => resolveCloneRequest(process.argv.slice(2), process.env["npm_lifecycle_event"]));
|
|
195
195
|
const runDockerGitClone = (args) => Effect.gen(function* (_) {
|
|
@@ -215,6 +215,9 @@ const TemplateConfigSchema = Schema.Struct({
|
|
|
215
215
|
sshPort: Schema.Number.pipe(Schema.int()),
|
|
216
216
|
repoUrl: Schema.String,
|
|
217
217
|
repoRef: Schema.String,
|
|
218
|
+
gitTokenLabel: Schema.optional(Schema.String),
|
|
219
|
+
codexAuthLabel: Schema.optional(Schema.String),
|
|
220
|
+
claudeAuthLabel: Schema.optional(Schema.String),
|
|
218
221
|
targetDir: Schema.String,
|
|
219
222
|
volumeName: Schema.String,
|
|
220
223
|
dockerGitPath: Schema.optionalWith(Schema.String, {
|
|
@@ -275,6 +278,23 @@ const runDockerPsNames = (cwd) => pipe(runCommandCapture({
|
|
|
275
278
|
}, [Number(ExitCode(0))], (exitCode) => new CommandFailedError({ command: "docker ps", exitCode })), Effect.map((output) => output.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0)));
|
|
276
279
|
const isParseError = (error) => error._tag === "UnknownCommand" || error._tag === "UnknownOption" || error._tag === "MissingOptionValue" || error._tag === "MissingRequiredOption" || error._tag === "InvalidOption" || error._tag === "UnexpectedArgument";
|
|
277
280
|
const renderDockerAccessHeadline = (issue) => issue === "PermissionDenied" ? "Cannot access Docker daemon socket: permission denied." : "Cannot connect to Docker daemon.";
|
|
281
|
+
const renderDockerAccessActionPlan = (issue) => {
|
|
282
|
+
const permissionDeniedPlan = [
|
|
283
|
+
"Action plan:",
|
|
284
|
+
"1) In the same shell, run: `groups $USER` and make sure group `docker` is present.",
|
|
285
|
+
"2) Re-login to refresh group memberships and run command again.",
|
|
286
|
+
"3) If DOCKER_HOST is set to rootless socket, keep running: `export DOCKER_HOST=unix:///run/user/$UID/docker.sock`.",
|
|
287
|
+
"4) If using a dedicated socket not in /run/user, set DOCKER_HOST explicitly and re-run.",
|
|
288
|
+
"Tip: this app now auto-tries a rootless socket fallback on first permission error."
|
|
289
|
+
];
|
|
290
|
+
const daemonUnavailablePlan = [
|
|
291
|
+
"Action plan:",
|
|
292
|
+
"1) Check daemon status: `systemctl --user status docker` or `systemctl status docker`.",
|
|
293
|
+
"2) Start daemon: `systemctl --user start docker` (or `systemctl start docker` for system Docker).",
|
|
294
|
+
"3) Retry command in a new shell."
|
|
295
|
+
];
|
|
296
|
+
return issue === "PermissionDenied" ? permissionDeniedPlan.join("\n") : daemonUnavailablePlan.join("\n");
|
|
297
|
+
};
|
|
278
298
|
const renderPrimaryError = (error) => Match.value(error).pipe(Match.when({ _tag: "FileExistsError" }, ({ path }) => `File already exists: ${path} (use --force to overwrite)`), Match.when({ _tag: "DockerCommandError" }, ({ exitCode }) => [
|
|
279
299
|
`docker compose failed with exit code ${exitCode}`,
|
|
280
300
|
"Hint: ensure Docker daemon is running and current user can access /var/run/docker.sock (for example via the docker group).",
|
|
@@ -283,12 +303,13 @@ const renderPrimaryError = (error) => Match.value(error).pipe(Match.when({ _tag:
|
|
|
283
303
|
renderDockerAccessHeadline(issue),
|
|
284
304
|
"Hint: ensure Docker daemon is running and current user can access the docker socket.",
|
|
285
305
|
"Hint: if you use rootless Docker, set DOCKER_HOST to your user socket (for example unix:///run/user/$UID/docker.sock).",
|
|
306
|
+
renderDockerAccessActionPlan(issue),
|
|
286
307
|
`Details: ${details}`
|
|
287
308
|
].join("\n")), Match.when({ _tag: "CloneFailedError" }, ({ repoRef, repoUrl, targetDir }) => `Clone failed for ${repoUrl} (${repoRef}) into ${targetDir}`), Match.when({ _tag: "PortProbeError" }, ({ message, port }) => `SSH port check failed for ${port}: ${message}`), Match.when({ _tag: "CommandFailedError" }, ({ command, exitCode }) => `${command} failed with exit code ${exitCode}`), Match.when({ _tag: "ScrapArchiveNotFoundError" }, ({ path }) => `Scrap archive not found: ${path} (run docker-git scrap export first)`), Match.when({ _tag: "ScrapArchiveInvalidError" }, ({ message, path }) => `Invalid scrap archive: ${path}
|
|
288
|
-
Details: ${message}`), Match.when({ _tag: "ScrapTargetDirUnsupportedError" }, ({ reason,
|
|
309
|
+
Details: ${message}`), Match.when({ _tag: "ScrapTargetDirUnsupportedError" }, ({ reason, targetDir }) => [
|
|
289
310
|
`Cannot use scrap with targetDir ${targetDir}.`,
|
|
290
311
|
`Reason: ${reason}`,
|
|
291
|
-
`Hint: scrap currently supports workspaces under
|
|
312
|
+
`Hint: scrap currently supports workspaces under the ssh home directory only (for example: ~/repo).`
|
|
292
313
|
].join("\n")), Match.when({ _tag: "ScrapWipeRefusedError" }, ({ reason, targetDir }) => [
|
|
293
314
|
`Refusing to wipe workspace for scrap import (targetDir ${targetDir}).`,
|
|
294
315
|
`Reason: ${reason}`,
|
|
@@ -503,13 +524,17 @@ Env global: ${config.template.envGlobalPath}
|
|
|
503
524
|
Env project: ${config.template.envProjectPath}
|
|
504
525
|
Codex auth: ${config.template.codexAuthPath} -> ${config.template.codexHome}`;
|
|
505
526
|
const isDockerGitConfig = (entry) => entry.endsWith("docker-git.json");
|
|
506
|
-
const shouldSkipDir = (entry) => entry === ".git" || entry === ".orch" || entry === ".docker-git";
|
|
527
|
+
const shouldSkipDir = (entry) => entry === ".git" || entry === ".orch" || entry === ".docker-git" || entry === ".cache";
|
|
528
|
+
const isNotFoundStatError = (error) => error._tag === "SystemError" && error.reason === "NotFound";
|
|
507
529
|
const processDockerGitEntry = (fs, path, dir, entry, state) => Effect.gen(function* (_) {
|
|
508
530
|
if (shouldSkipDir(entry)) {
|
|
509
531
|
return;
|
|
510
532
|
}
|
|
511
533
|
const resolved = path.join(dir, entry);
|
|
512
|
-
const info = yield* _(fs.stat(resolved));
|
|
534
|
+
const info = yield* _(fs.stat(resolved).pipe(Effect.catchTag("SystemError", (error) => isNotFoundStatError(error) ? Effect.succeed(null) : Effect.fail(error))));
|
|
535
|
+
if (info === null) {
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
513
538
|
if (info.type === "Directory") {
|
|
514
539
|
state.stack.push(resolved);
|
|
515
540
|
return;
|