@united-robotics/cli 0.4.2 → 0.4.3
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/dist/index.js +17 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
5
|
+
import { chmodSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
6
6
|
import { homedir, tmpdir } from "os";
|
|
7
7
|
import { basename, join } from "path";
|
|
8
8
|
import { spawnSync } from "child_process";
|
|
@@ -41,14 +41,16 @@ program.command("team").argument("<cmd>").action(async (cmd) => {
|
|
|
41
41
|
var project = program.command("project");
|
|
42
42
|
project.command("ls").option("--team <teamId>").action(async (opts) => console.log(JSON.stringify(await api(`/api/projects${opts.team ? `?team=${encodeURIComponent(opts.team)}` : ""}`), null, 2)));
|
|
43
43
|
project.command("show").argument("<projectId>").action(async (projectId) => console.log(JSON.stringify({ projectId, repos: await projectRepos(projectId) }, null, 2)));
|
|
44
|
-
project.command("clone").argument("<projectId>").option("--dest <path>").option("--no-submodules", "clone primary repo only").option("--name <name>", "Git user.name for Vercel-compatible commits", "exis[ai]").option("--email <email>", "Git user.email for Vercel-compatible commits", "gotexis@gmail.com").action(async (projectId, opts) => {
|
|
44
|
+
project.command("clone").argument("<projectId>").option("--dest <path>").option("--in-place", "clone into the current directory so AGENTS.md and workspace files land at the project root").option("--no-submodules", "clone primary repo only").option("--name <name>", "Git user.name for Vercel-compatible commits", "exis[ai]").option("--email <email>", "Git user.email for Vercel-compatible commits", "gotexis@gmail.com").action(async (projectId, opts) => {
|
|
45
45
|
const repos = await projectRepos(projectId);
|
|
46
46
|
const primary = repos.find((r) => r.kind === "primary") ?? repos[0];
|
|
47
47
|
if (!primary) throw new Error("No repo found");
|
|
48
48
|
const token = await projectGithubToken(projectId);
|
|
49
49
|
const credentials = createGitAskpass(token.token);
|
|
50
50
|
try {
|
|
51
|
-
|
|
51
|
+
if (opts.inPlace && opts.dest) throw new Error("Use either --in-place or --dest, not both.");
|
|
52
|
+
const dest = opts.inPlace ? "." : opts.dest;
|
|
53
|
+
if (opts.inPlace) assertInPlaceCloneTarget(process.cwd());
|
|
52
54
|
const cloneArgs = ["clone", primary.url];
|
|
53
55
|
if (dest) cloneArgs.push(dest);
|
|
54
56
|
runGit(cloneArgs, { cwd: process.cwd(), env: credentials.env, authHint: true });
|
|
@@ -113,9 +115,12 @@ program.command("codex").argument("<cmd>").option("--project <projectId>", "proj
|
|
|
113
115
|
if (cmd !== "onboard") throw new Error("supported: ur codex onboard");
|
|
114
116
|
const cfg = load();
|
|
115
117
|
const loginToken = opts.includeToken ? cfg.token ?? "<TOKEN>" : "<TOKEN>";
|
|
116
|
-
console.log(`Establish new agent workspace by globally installing \`@united-robotics/cli\` module (ensuring there is a working node, nvm and git) and authenticate using token "ur login --token ${loginToken}". Then run \`ur project ls\` and \`ur project clone ${opts.project}\`; clone
|
|
118
|
+
console.log(`Establish new agent workspace in the current empty Codex project root by globally installing \`@united-robotics/cli\` module (ensuring there is a working node, nvm and git) and authenticate using token "ur login --token ${loginToken}". Then run \`ur project ls\` and \`ur project clone ${opts.project} --in-place\`; in-place clone puts AGENTS.md and workspace files at the Codex project root, while internally obtaining the short-lived project-wide GitHub token, initializing private submodules, and applying the Vercel-compatible git identity. When GitHub write access is needed manually, use \`ur github token --project ${opts.project}\` for a short-lived GitHub App token, but avoid printing that token in logs unless necessary. Use that project root as codex project base from now on, and familiarize yourself.`);
|
|
119
|
+
});
|
|
120
|
+
program.parseAsync().catch((error) => {
|
|
121
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
122
|
+
process.exit(1);
|
|
117
123
|
});
|
|
118
|
-
program.parseAsync();
|
|
119
124
|
async function projectRepos(projectId) {
|
|
120
125
|
return await api(`/api/projects/${projectId}/repos`);
|
|
121
126
|
}
|
|
@@ -162,12 +167,18 @@ function runGit(args, options = { cwd: process.cwd() }) {
|
|
|
162
167
|
if (status !== 0 && !options.allowFailure) {
|
|
163
168
|
if (options.authHint && /repository not found|authentication failed|could not read username|terminal prompts disabled/i.test(`${result.stdout}
|
|
164
169
|
${result.stderr}`)) {
|
|
165
|
-
throw new Error("GitHub authentication failed while accessing a private repo. The repo may exist, but GitHub credentials were unavailable or rejected. Re-run `ur login`, then `ur project clone <projectId
|
|
170
|
+
throw new Error("GitHub authentication failed while accessing a private repo. The repo may exist, but GitHub credentials were unavailable or rejected. Re-run `ur login`, then `ur project clone <projectId> --in-place` from an empty project root so the CLI can inject a short-lived GitHub App token internally.");
|
|
166
171
|
}
|
|
167
172
|
throw new Error(`git ${safeArgs(args)} failed with exit ${status}`);
|
|
168
173
|
}
|
|
169
174
|
return { status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
170
175
|
}
|
|
176
|
+
function assertInPlaceCloneTarget(cwd) {
|
|
177
|
+
const entries = readdirSync(cwd).filter((entry) => ![".DS_Store"].includes(entry));
|
|
178
|
+
if (entries.length > 0) {
|
|
179
|
+
throw new Error(`Cannot in-place clone into a non-empty directory (${cwd}). Start from an empty Codex project root, or use --dest <path> intentionally.`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
171
182
|
function gitBin() {
|
|
172
183
|
return process.env.UR_GIT_BIN || (process.platform === "darwin" ? "/usr/bin/git" : "git");
|
|
173
184
|
}
|