| … | … | @@ -37,6 +37,14 @@ export const usage = `pgh repo — browse repos served by the daemon |
| 37 | 37 | a fresh corestore + P2P doorbell |
| 38 | 38 | auto-admission (no url)` |
| 39 | 39 | |
| 40 | // A repo name must start alphanumeric and stay within git-safe punctuation — |
| 41 | // same shape pear-git-v3 enforces in lib/repo-name.js. |
| 42 | const VALID_REPO_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/ |
| 43 | |
| 44 | // Values that mean "a variable was stringified", never a repo someone meant. |
| 45 | // `undefined` is not hypothetical: there is one on the live fleet. |
| 46 | const SENTINELS = new Set(['undefined', 'null', 'nan', 'false', 'true', '[object object]']) |
| 47 | |
| 40 | 48 | export async function run (client, args) { |
| 41 | 49 | const sub = args[0] |
| 42 | 50 | |
| … | … | @@ -233,6 +241,29 @@ export async function run (client, args) { |
| 233 | 241 | return client.call('repo-revoke-writer', { name, userId }) |
| 234 | 242 | } |
| 235 | 243 | |
| 236 | | // Default: treat first arg as repo name → show |
| 244 | // Default: treat the first arg as a repo NAME → show it. |
| 245 | // |
| 246 | // GUARDED, because this path has a side effect it does not look like it has: |
| 247 | // repo-info resolves through getForRepo(), which mints a per-repo tracker on |
| 248 | // demand, and RefReconcilerManager.ensureFor() runs `git init --bare` when |
| 249 | // the path is missing. So a READ materializes a repo. Typing |
| 250 | // `pgh repo --help` created a bare repo called `--help`; 16 empty repos on |
| 251 | // the live fleet were produced this way, named after flags (`--help`), |
| 252 | // subcommand words (`list`, `create`, `new`, `help`, `comment`), orgs and |
| 253 | // projects that were never repos, and one literal `undefined`. |
| 254 | // |
| 255 | // The daemon should not create on read either — that is the deeper fix, in |
| 256 | // repo-info — but the CLI has no business forwarding these in the first place. |
| 257 | if (sub.startsWith('-')) { |
| 258 | // A flag reaching here means an unknown option, not a repo called "--help". |
| 259 | throw new Error(usage) |
| 260 | } |
| 261 | if (SENTINELS.has(sub.toLowerCase())) { |
| 262 | throw new Error(`refusing to treat "${sub}" as a repo name — it looks like a ` + |
| 263 | 'stringified value, not something you meant to type.\n\n' + usage) |
| 264 | } |
| 265 | if (!VALID_REPO_NAME.test(sub)) { |
| 266 | throw new Error(`invalid repo name: ${JSON.stringify(sub)}\n\n` + usage) |
| 267 | } |
| 237 | 268 | return client.call('repo-info', { name: sub }) |
| 238 | 269 | } |