diff --git a/README.md b/README.md index 28ad751b..888c06dc 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,9 @@ pnpm run docker-git clone https://github.com/agiens/crm/tree/vova-fork --force # Clone an issue URL (creates isolated workspace + issue branch) pnpm run docker-git clone https://github.com/agiens/crm/issues/123 --force +# Open an existing docker-git project by repo/issue URL (runs up + tmux attach) +pnpm run docker-git open https://github.com/agiens/crm/issues/123 + # Reset only project env defaults (keep workspace volume/data) pnpm run docker-git clone https://github.com/agiens/crm/issues/123 --force-env diff --git a/package.json b/package.json index 60a00d95..d8a59aa4 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "changeset-publish": "node -e \"if (!process.env.NPM_TOKEN) { console.log('Skipping publish: NPM_TOKEN is not set'); process.exit(0); }\" && changeset publish", "changeset-version": "changeset version", "clone": "pnpm --filter ./packages/app build && node packages/app/dist/main.js clone", + "open": "pnpm --filter ./packages/app build && node packages/app/dist/main.js open", "docker-git": "pnpm --filter ./packages/app build:docker-git && node packages/app/dist/src/docker-git/main.js", "e2e": "bash scripts/e2e/run-all.sh", "e2e:clone-cache": "bash scripts/e2e/clone-cache.sh", diff --git a/packages/app/package.json b/packages/app/package.json index 9070b7fd..4ce872ec 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -22,6 +22,7 @@ "build:docker-git": "tsc -p tsconfig.build.json", "check": "pnpm run typecheck", "clone": "pnpm -C ../.. run clone", + "open": "pnpm -C ../.. run open", "docker-git": "node dist/src/docker-git/main.js", "list": "pnpm -C ../.. run list", "prestart": "pnpm run build", diff --git a/packages/app/src/app/program.ts b/packages/app/src/app/program.ts index 30f3a6ce..ab9ecb9d 100644 --- a/packages/app/src/app/program.ts +++ b/packages/app/src/app/program.ts @@ -1,17 +1,17 @@ -import { listProjects, readCloneRequest, runDockerGitClone } from "@effect-template/lib" +import { listProjects, readCloneRequest, runDockerGitClone, runDockerGitOpen } from "@effect-template/lib" import { Console, Effect, Match, pipe } from "effect" /** * Compose the CLI program as a single effect. * - * @returns Effect that either runs docker-git clone or prints usage. + * @returns Effect that either runs docker-git clone/open or prints usage. * - * @pure false - uses Console output and spawns commands when cloning + * @pure false - uses Console output and spawns commands when running shortcuts * @effect Console, CommandExecutor, Path - * @invariant forall args in Argv: clone(args) -> docker_git_invoked(args) + * @invariant forall args in Argv: shortcut(args) -> docker_git_invoked(args) * @precondition true - * @postcondition clone(args) -> docker_git_invoked(args); otherwise usage printed - * @complexity O(build + clone) + * @postcondition shortcut(args) -> docker_git_invoked(args); otherwise usage printed + * @complexity O(build + shortcut) * @throws Never - all errors are typed in the Effect error channel */ // CHANGE: replace greeting demo with deterministic usage text @@ -28,32 +28,35 @@ const usageText = [ "Usage:", " pnpm docker-git", " pnpm clone [ref]", + " pnpm open ", " pnpm list", "", "Notes:", " - docker-git is the interactive TUI.", - " - clone builds + runs docker-git clone for you." + " - clone builds + runs docker-git clone for you.", + " - open builds + runs docker-git open for existing projects." ].join("\n") // PURITY: SHELL // EFFECT: Effect const runHelp = Console.log(usageText) -// CHANGE: route between clone runner and help based on CLI context -// WHY: allow pnpm run clone while keeping a single entrypoint -// QUOTE(ТЗ): "pnpm run clone " +// CHANGE: route between shortcut runners and help based on CLI context +// WHY: allow pnpm run clone/open while keeping a single entrypoint +// QUOTE(ТЗ): "Добавить команду open." // REF: user-request-2026-01-27 // SOURCE: n/a -// FORMAT THEOREM: forall argv: clone(argv) -> docker_git_invoked(argv) +// FORMAT THEOREM: forall argv: shortcut(argv) -> docker_git_invoked(argv) // PURITY: SHELL // EFFECT: Effect -// INVARIANT: help is printed when clone is not requested -// COMPLEXITY: O(build + clone) +// INVARIANT: help is printed when shortcut is not requested +// COMPLEXITY: O(build + shortcut) const runDockerGit = pipe( readCloneRequest, Effect.flatMap((request) => Match.value(request).pipe( Match.when({ _tag: "Clone" }, ({ args }) => runDockerGitClone(args)), + Match.when({ _tag: "Open" }, ({ args }) => runDockerGitOpen(args)), Match.when({ _tag: "None" }, () => runHelp), Match.exhaustive ) diff --git a/packages/app/src/docker-git/cli/parser.ts b/packages/app/src/docker-git/cli/parser.ts index 29d17423..542666a0 100644 --- a/packages/app/src/docker-git/cli/parser.ts +++ b/packages/app/src/docker-git/cli/parser.ts @@ -75,6 +75,7 @@ export const parseArgs = (args: ReadonlyArray): Either.Either parseAuth(rest)) ) .pipe( + Match.when("open", () => parseAttach(rest)), Match.when("apply", () => parseApply(rest)), Match.when("state", () => parseState(rest)), Match.orElse(() => Either.left(unknownCommandError)) diff --git a/packages/app/src/docker-git/cli/usage.ts b/packages/app/src/docker-git/cli/usage.ts index 0c3befe4..a2d8962c 100644 --- a/packages/app/src/docker-git/cli/usage.ts +++ b/packages/app/src/docker-git/cli/usage.ts @@ -5,6 +5,7 @@ import type { ParseError } from "@effect-template/lib/core/domain" export const usageText = `docker-git menu docker-git create --repo-url [options] docker-git clone [options] +docker-git open [] [options] docker-git apply [] [options] docker-git mcp-playwright [] [options] docker-git attach [] [options] @@ -22,9 +23,10 @@ Commands: menu Interactive menu (default when no args) create, init Generate docker development environment clone Create + run container and clone repo + open Open existing docker-git project workspace apply Apply docker-git config to an existing project/container (current dir by default) mcp-playwright Enable Playwright MCP + Chromium sidecar for an existing project dir - attach, tmux Open tmux workspace for a docker-git project + attach, tmux Alias for open panes, terms List tmux panes for a docker-git project scrap Export/import project scrap (session snapshot + rebuildable deps) sessions List/kill/log container terminal processes @@ -50,7 +52,7 @@ Options: --network-mode Compose network mode: shared|project (default: shared) --shared-network Shared Docker network name when network-mode=shared (default: docker-git-shared) --out-dir Output directory (default: //[/issue-|/pr-]) - --project-dir Project directory for attach (default: .) + --project-dir Project directory for open/attach (default: .) --archive Scrap snapshot directory (default: .orch/scrap/session) --mode Scrap mode (default: session) --git-token