aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/superpowers/specs/2026-10-19-clone-tool-design.md78
1 files changed, 78 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-10-19-clone-tool-design.md b/docs/superpowers/specs/2026-10-19-clone-tool-design.md
new file mode 100644
index 0000000..09d3be5
--- /dev/null
+++ b/docs/superpowers/specs/2026-10-19-clone-tool-design.md
@@ -0,0 +1,78 @@
+# Clone tool: design
+
+Date: 2026-10-19. Status: implemented (2026-10-19).
+
+## Goal
+
+Ask the assistant to clone a public repository ("clone this repo:
+https://github.com/owner/repo") and have it land in the right folder of
+`~/Programming/GIT`: `GITHUB/`, `GITLAB/`, `FORGE/`, or a folder already
+approved for that host. Public repositories only, plain `git clone`, no
+SSH aliases or keys.
+
+The assistant must not decide two things alone: a host with no folder yet,
+and a repository that is already cloned. Both are asked, with a concrete
+action, never a bare "skip".
+
+## Tool
+
+`examples/tools/clone.toml`, installed to
+`~/.config/desktop-assistant/tools/` like the others. No change to
+`assistant.py`.
+
+```toml
+command = ["clone.sh", "{url}", "{to}", "{update}"]
+timeout = 300
+```
+
+- `url`: the repository URL.
+- `to`: only when the user approved a new host folder; the folder name.
+- `update`: `1` to pull an existing clone.
+
+`examples/tools/clone.sh`:
+
+- Parses `https://host/owner/repo` and `git@host:owner/repo` alike; `repo`
+ is the last path segment with a trailing `/` and a `.git` suffix removed.
+ Both `host` and `repo` are validated as plain names, so neither can
+ escape the tree.
+- Resolves `host -> folder` from the mapping file. Absent, it is seeded
+ with `github.com -> GITHUB`, `gitlab.com -> GITLAB`,
+ `forge.slackware.nl -> FORGE`.
+- Target is `<root>/<folder>/<repo>` (`CLONE_ROOT`, default
+ `~/Programming/GIT`).
+- Known host, target free: `git clone` and report it. No question.
+- Unknown host: prints the folder to offer (hostname without its last
+ label, uppercased: `codeberg.org -> CODEBERG`) and does nothing.
+- Target exists: prints "already cloned" and does nothing. With
+ `update=1`, runs `git pull --ff-only` and reports the result; a diverged
+ clone is an error, not a merge.
+- A `to` given for an unknown host clones there and appends
+ `host<TAB>folder` to the mapping, so that host is known from then on.
+ An existing mapping is never duplicated or overwritten.
+
+## Mapping file
+
+`~/.config/desktop-assistant/clone-hosts` (`CLONE_MAP`), one
+`host<TAB>folder` line per host, user-editable. It lives outside the tool
+directory so reinstalling the tools does not lose it, and the file is the
+single source of truth: nothing is hardcoded in the script beyond the
+seed.
+
+## Check
+
+`test-clone.sh`: a scratch `CLONE_ROOT` and `CLONE_MAP`, and a `git` stub
+on `PATH` that records its argv and creates the target, so no network and
+no real tree. Covers seeding, clone argv, trailing slash and `.git`, the
+unknown-host message, the approved folder being remembered and used on
+the next clone without a question, no duplicate map line, the
+already-cloned message, the update argv, and the refused inputs.
+
+Live, against the running model: ask for a known host and an unknown host,
+accept the offered folder, ask for the same host again (must ask nothing),
+then ask for an existing repo (must offer an update, never a second
+clone).
+
+## Not included
+
+Private repositories (no credentials), clone depth or branches, and
+opening the clone in an editor or agent after it lands.