@meistrari/remy-cli 1.20.0 → 1.21.0-rc.0
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/README.md +12 -0
- package/dist/remy.js +235 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,6 +36,16 @@ remy
|
|
|
36
36
|
|
|
37
37
|
On first use, Remy opens browser-based device authorization, validates your Coding Agent identity, and opens the session dashboard. Later, the same command takes you straight to that dashboard.
|
|
38
38
|
|
|
39
|
+
## Update Remy
|
|
40
|
+
|
|
41
|
+
Run `remy update` to install a newer CLI release using the package manager that owns your installation (mise, Bun, pnpm, or npm). No sign-in is required. Use `remy --version` to print the installed version.
|
|
42
|
+
|
|
43
|
+
Stable versions check npm’s `latest` channel. Release candidates check both `rc` and `latest` and choose the newer version; Remy never downgrades. To switch from stable to RC, use the explicit `@rc` install command above.
|
|
44
|
+
|
|
45
|
+
Each interactive `remy` or `remy dashboard` startup checks for an update before sign-in or the splash. When one is available, type `y` or `yes`, then Enter, to upgrade. Press Enter or type `n` to continue with the current version. Lookup failures or a two-second timeout let startup continue. After a successful upgrade, Remy exits and asks you to run it again. Installation failures exit with an error so you can resolve the package-manager problem and retry.
|
|
46
|
+
|
|
47
|
+
Help, version, sign-in/out, direct session commands, and redirected/noninteractive invocations do not run startup checks or prompt. Development checkouts skip checks; local project and temporary `bunx`/`npx` installations must be updated through their original caller. Remy refuses to install if it cannot identify the owning manager.
|
|
48
|
+
|
|
39
49
|
## Your everyday workflow
|
|
40
50
|
|
|
41
51
|
The dashboard is the starting point for all interactive work. It refreshes the visible session page every 10 seconds, so new sessions and status changes appear while you keep it open. If an update fails, Remy keeps showing the last successful list and retries on the next interval.
|
|
@@ -187,6 +197,8 @@ remy help | --help | -h
|
|
|
187
197
|
remy login [--env production|staging] [--api-url <url> --auth-api-url <url> --requester-application-id <uuid> --target-application-id <uuid>]
|
|
188
198
|
remy logout [--api-url <url>]
|
|
189
199
|
remy whoami
|
|
200
|
+
remy update
|
|
201
|
+
remy --version | -v
|
|
190
202
|
remy dashboard
|
|
191
203
|
remy new [--repository <owner/name> ... --installation <id> --model <name> --reasoning-effort <low|medium|high|xhigh> --attach <path> ... --no-tui --json] <prompt>
|
|
192
204
|
remy --session <session-id> [--no-tui] [--json] [prompt]
|
package/dist/remy.js
CHANGED
|
@@ -17,10 +17,10 @@ var __export = (target, all) => {
|
|
|
17
17
|
|
|
18
18
|
// src/commands.ts
|
|
19
19
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
20
|
-
import { spawn } from "child_process";
|
|
20
|
+
import { spawn as spawn2 } from "child_process";
|
|
21
21
|
import { mkdir as mkdir6, readFile as readFile5, readdir as readdir3, rename as rename4, unlink as unlink3, writeFile as writeFile4 } from "fs/promises";
|
|
22
22
|
import { homedir as homedir3, tmpdir as tmpdir2 } from "os";
|
|
23
|
-
import { dirname as dirname6, join as
|
|
23
|
+
import { dirname as dirname6, join as join8 } from "path";
|
|
24
24
|
|
|
25
25
|
// ../../node_modules/.bun/@meistrari+auth-cli@1.6.1+aff0271b2b55d60c/node_modules/@meistrari/auth-cli/dist/index.mjs
|
|
26
26
|
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
@@ -34234,6 +34234,141 @@ function formatSessionJson({
|
|
|
34234
34234
|
})}
|
|
34235
34235
|
`;
|
|
34236
34236
|
}
|
|
34237
|
+
// src/version.ts
|
|
34238
|
+
var remyCliVersion = "1.21.0-rc.0";
|
|
34239
|
+
|
|
34240
|
+
// src/self-update.ts
|
|
34241
|
+
import { spawn } from "child_process";
|
|
34242
|
+
import { realpath } from "fs/promises";
|
|
34243
|
+
import { join as join3, relative, isAbsolute } from "path";
|
|
34244
|
+
import { createInterface } from "readline/promises";
|
|
34245
|
+
var {semver } = globalThis.Bun;
|
|
34246
|
+
var packageName = "@meistrari/remy-cli";
|
|
34247
|
+
var versionSchema = exports_external2.string().regex(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-rc\.(0|[1-9]\d*))?$/);
|
|
34248
|
+
var tagsSchema = exports_external2.object({ latest: versionSchema, rc: versionSchema.optional() });
|
|
34249
|
+
function createCliUpdates({
|
|
34250
|
+
currentVersion,
|
|
34251
|
+
entryPath,
|
|
34252
|
+
fetchClient,
|
|
34253
|
+
runProcess,
|
|
34254
|
+
confirm
|
|
34255
|
+
}) {
|
|
34256
|
+
return {
|
|
34257
|
+
currentVersion,
|
|
34258
|
+
confirm,
|
|
34259
|
+
async check(signal) {
|
|
34260
|
+
if (currentVersion === "0.0.0")
|
|
34261
|
+
return null;
|
|
34262
|
+
const response = await fetchClient(`https://registry.npmjs.org/-/package/${encodeURIComponent(packageName)}/dist-tags`, {
|
|
34263
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(2000)]),
|
|
34264
|
+
headers: { accept: "application/json" }
|
|
34265
|
+
});
|
|
34266
|
+
if (!response.ok)
|
|
34267
|
+
throw new Error(`Cannot check Remy releases (HTTP ${response.status}).`);
|
|
34268
|
+
const tags = tagsSchema.parse(await response.json());
|
|
34269
|
+
const latest = currentVersion.includes("-rc.") && tags.rc && semver.order(tags.rc, tags.latest) > 0 ? tags.rc : tags.latest;
|
|
34270
|
+
return semver.order(latest, currentVersion) > 0 ? latest : null;
|
|
34271
|
+
},
|
|
34272
|
+
async install(version5, signal) {
|
|
34273
|
+
versionSchema.parse(version5);
|
|
34274
|
+
if (currentVersion === "0.0.0")
|
|
34275
|
+
throw new Error("This is a development checkout. Update the checkout instead of running remy update.");
|
|
34276
|
+
const runningEntry = await realpath(entryPath);
|
|
34277
|
+
const probeSignal = AbortSignal.any([signal, AbortSignal.timeout(5000)]);
|
|
34278
|
+
const probe = async (argv2) => {
|
|
34279
|
+
try {
|
|
34280
|
+
const result2 = await runProcess({ argv: argv2, signal: probeSignal, display: false });
|
|
34281
|
+
return result2.exitCode === 0 ? result2.stdout.trim() : "";
|
|
34282
|
+
} catch {
|
|
34283
|
+
signal.throwIfAborted();
|
|
34284
|
+
return "";
|
|
34285
|
+
}
|
|
34286
|
+
};
|
|
34287
|
+
const matchesEntry = async (candidate) => {
|
|
34288
|
+
try {
|
|
34289
|
+
return await realpath(candidate) === runningEntry;
|
|
34290
|
+
} catch {
|
|
34291
|
+
return false;
|
|
34292
|
+
}
|
|
34293
|
+
};
|
|
34294
|
+
let argv;
|
|
34295
|
+
let updatedEntry = runningEntry;
|
|
34296
|
+
const miseRoot = await probe(["mise", "where", `npm:${packageName}@${currentVersion}`]);
|
|
34297
|
+
const miseRelative = miseRoot ? relative(miseRoot, runningEntry) : "";
|
|
34298
|
+
const usesMise = miseRoot !== "" && miseRelative !== "" && !miseRelative.startsWith("..") && !isAbsolute(miseRelative);
|
|
34299
|
+
if (usesMise) {
|
|
34300
|
+
argv = ["mise", "upgrade", `npm:${packageName}@${version5}`, "--bump", "--no-prune"];
|
|
34301
|
+
} else {
|
|
34302
|
+
const bunBin = await probe(["bun", "pm", "bin", "-g"]);
|
|
34303
|
+
if (bunBin && await matchesEntry(join3(bunBin, "remy"))) {
|
|
34304
|
+
argv = ["bun", "add", "--global", `${packageName}@${version5}`];
|
|
34305
|
+
updatedEntry = join3(bunBin, "remy");
|
|
34306
|
+
}
|
|
34307
|
+
for (const manager of ["pnpm", "npm"]) {
|
|
34308
|
+
if (argv)
|
|
34309
|
+
break;
|
|
34310
|
+
const root = await probe([manager, "root", "--global"]);
|
|
34311
|
+
const candidate = join3(root, packageName, "dist", "remy.js");
|
|
34312
|
+
if (root && await matchesEntry(candidate)) {
|
|
34313
|
+
argv = [manager, "install", "--global", `${packageName}@${version5}`];
|
|
34314
|
+
updatedEntry = candidate;
|
|
34315
|
+
}
|
|
34316
|
+
}
|
|
34317
|
+
}
|
|
34318
|
+
signal.throwIfAborted();
|
|
34319
|
+
if (!argv)
|
|
34320
|
+
throw new Error("Cannot identify the manager for this Remy installation. Reinstall @meistrari/remy-cli with the manager you originally used (mise, bun, pnpm, or npm). Local and temporary bunx/npx installs must be updated by their caller.");
|
|
34321
|
+
const result = await runProcess({ argv, signal, display: true });
|
|
34322
|
+
if (result.exitCode !== 0)
|
|
34323
|
+
throw new Error(`Remy update failed: ${argv[0]} exited with code ${result.exitCode}. Resolve the package manager error and retry remy update.`);
|
|
34324
|
+
if (usesMise) {
|
|
34325
|
+
const located = await runProcess({ argv: ["mise", "where", `npm:${packageName}@${version5}`], signal, display: false });
|
|
34326
|
+
if (located.exitCode !== 0 || !located.stdout.trim())
|
|
34327
|
+
throw new Error("Update finished but the new mise installation could not be located. Check remy --version before retrying.");
|
|
34328
|
+
updatedEntry = join3(located.stdout.trim(), miseRelative);
|
|
34329
|
+
}
|
|
34330
|
+
const verified = await runProcess({ argv: [process.execPath, updatedEntry, "--version"], signal, display: false });
|
|
34331
|
+
if (verified.exitCode !== 0 || verified.stdout.trim() !== version5)
|
|
34332
|
+
throw new Error("The package manager finished, but the installed Remy version could not be verified. Check remy --version before retrying.");
|
|
34333
|
+
}
|
|
34334
|
+
};
|
|
34335
|
+
}
|
|
34336
|
+
var runUpdateProcess = async ({ argv, signal, display }) => {
|
|
34337
|
+
signal.throwIfAborted();
|
|
34338
|
+
return await new Promise((resolve, reject) => {
|
|
34339
|
+
const [executable, ...args] = argv;
|
|
34340
|
+
if (!executable) {
|
|
34341
|
+
reject(new Error("Missing update executable."));
|
|
34342
|
+
return;
|
|
34343
|
+
}
|
|
34344
|
+
const child = spawn(executable, args, { signal, stdio: ["ignore", "pipe", display ? "inherit" : "ignore"] });
|
|
34345
|
+
let stdout = "";
|
|
34346
|
+
child.stdout?.on("data", (chunk) => {
|
|
34347
|
+
if (display)
|
|
34348
|
+
process.stderr.write(chunk);
|
|
34349
|
+
else
|
|
34350
|
+
stdout += chunk.toString();
|
|
34351
|
+
});
|
|
34352
|
+
child.on("error", reject);
|
|
34353
|
+
child.on("close", (code) => resolve({ exitCode: code ?? 1, stdout }));
|
|
34354
|
+
});
|
|
34355
|
+
};
|
|
34356
|
+
async function confirmCliUpdate({ version: version5, signal, interrupt }) {
|
|
34357
|
+
const prompt = createInterface({ input: process.stdin, output: process.stderr });
|
|
34358
|
+
prompt.once("SIGINT", interrupt);
|
|
34359
|
+
const closed = new Promise((resolve) => prompt.once("close", () => resolve("")));
|
|
34360
|
+
try {
|
|
34361
|
+
const answer = await Promise.race([
|
|
34362
|
+
prompt.question(`Remy ${version5} is available. Upgrade now? [y/N] `, { signal }),
|
|
34363
|
+
closed
|
|
34364
|
+
]);
|
|
34365
|
+
signal.throwIfAborted();
|
|
34366
|
+
return /^y(?:es)?$/i.test(answer.trim());
|
|
34367
|
+
} finally {
|
|
34368
|
+
prompt.close();
|
|
34369
|
+
process.stdin.pause();
|
|
34370
|
+
}
|
|
34371
|
+
}
|
|
34237
34372
|
|
|
34238
34373
|
// src/session-agent-options.ts
|
|
34239
34374
|
function newSessionModelLabel(model) {
|
|
@@ -34252,7 +34387,7 @@ var defaultNewSessionAgent = {
|
|
|
34252
34387
|
// src/sessions/session-controller.ts
|
|
34253
34388
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
34254
34389
|
import { mkdir as mkdir4, readFile as readFile4, rename as rename3, writeFile as writeFile2 } from "fs/promises";
|
|
34255
|
-
import { dirname as dirname4, join as
|
|
34390
|
+
import { dirname as dirname4, join as join4 } from "path";
|
|
34256
34391
|
|
|
34257
34392
|
// ../../packages/supervisor-protocol/src/agent-event-wrapper.ts
|
|
34258
34393
|
var wrappedSessionStartedAgentEventSchema = sessionStartedAgentEventSchema.extend({
|
|
@@ -36103,7 +36238,7 @@ function resolveSessionCachePath({
|
|
|
36103
36238
|
sessionId
|
|
36104
36239
|
}) {
|
|
36105
36240
|
const stateBase = resolveStateBase(environment);
|
|
36106
|
-
return
|
|
36241
|
+
return join4(stateBase, "remy", "sessions", `${sessionId}.json`);
|
|
36107
36242
|
}
|
|
36108
36243
|
async function readSessionCache(path) {
|
|
36109
36244
|
try {
|
|
@@ -36121,7 +36256,7 @@ async function writeSessionCache({
|
|
|
36121
36256
|
}) {
|
|
36122
36257
|
const directory = dirname4(path);
|
|
36123
36258
|
await mkdir4(directory, { recursive: true, mode: 448 });
|
|
36124
|
-
const temporaryPath =
|
|
36259
|
+
const temporaryPath = join4(directory, `.session.${process.pid}.${randomUUID3()}.tmp`);
|
|
36125
36260
|
await writeFile2(temporaryPath, `${JSON.stringify(cache, null, 4)}
|
|
36126
36261
|
`, { mode: 384 });
|
|
36127
36262
|
await rename3(temporaryPath, path);
|
|
@@ -36140,7 +36275,7 @@ function resolveStateBase(environment) {
|
|
|
36140
36275
|
}
|
|
36141
36276
|
if (!environment.HOME)
|
|
36142
36277
|
throw new Error("HOME is required when XDG_STATE_HOME is not set; refusing to write Remy session cache in the current directory.");
|
|
36143
|
-
return
|
|
36278
|
+
return join4(environment.HOME, ".local/state");
|
|
36144
36279
|
}
|
|
36145
36280
|
function isMissingFileError2(error93) {
|
|
36146
36281
|
return error93 instanceof Error && "code" in error93 && error93.code === "ENOENT";
|
|
@@ -36159,7 +36294,7 @@ async function sleepMs(ms, signal) {
|
|
|
36159
36294
|
|
|
36160
36295
|
// src/sessions/downloads.ts
|
|
36161
36296
|
import { link, mkdir as mkdir5, mkdtemp, open as open4, rm } from "fs/promises";
|
|
36162
|
-
import { basename as basename2, extname, join as
|
|
36297
|
+
import { basename as basename2, extname, join as join5, resolve } from "path";
|
|
36163
36298
|
var downloadGrantSchema = exports_external2.object({
|
|
36164
36299
|
url: exports_external2.url(),
|
|
36165
36300
|
method: exports_external2.literal("GET"),
|
|
@@ -36182,16 +36317,16 @@ async function downloadSessionFile({ client, sessionId, file: file3, directory,
|
|
|
36182
36317
|
throw new Error(`File download failed (HTTP ${bytes.status}). Try again to request a fresh download.`);
|
|
36183
36318
|
const destination = resolve(directory);
|
|
36184
36319
|
await mkdir5(destination, { recursive: true });
|
|
36185
|
-
const staging = await mkdtemp(
|
|
36320
|
+
const staging = await mkdtemp(join5(destination, ".remy-download-"));
|
|
36186
36321
|
try {
|
|
36187
|
-
const temporaryPath =
|
|
36322
|
+
const temporaryPath = join5(staging, "content");
|
|
36188
36323
|
await saveDownloadStream({ body: bytes.body, path: temporaryPath, signal });
|
|
36189
36324
|
const filename = safeFilename(file3.filename);
|
|
36190
36325
|
const extension = extname(filename);
|
|
36191
36326
|
const stem = filename.slice(0, filename.length - extension.length);
|
|
36192
36327
|
for (let suffix = 0;suffix < 1000; suffix += 1) {
|
|
36193
36328
|
signal.throwIfAborted();
|
|
36194
|
-
const path =
|
|
36329
|
+
const path = join5(destination, suffix === 0 ? filename : `${stem} (${suffix})${extension}`);
|
|
36195
36330
|
try {
|
|
36196
36331
|
await link(temporaryPath, path);
|
|
36197
36332
|
return path;
|
|
@@ -37597,7 +37732,7 @@ function renderPathCompletionMenu({ completions, selectedIndex, width, maxRows }
|
|
|
37597
37732
|
// src/tui/path-completion.ts
|
|
37598
37733
|
import { readdir } from "fs/promises";
|
|
37599
37734
|
import { homedir } from "os";
|
|
37600
|
-
import { basename as basename3, dirname as dirname5, isAbsolute, join as
|
|
37735
|
+
import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute2, join as join6, relative as relative2, resolve as resolve2, sep } from "path";
|
|
37601
37736
|
var maximumCandidates = 50;
|
|
37602
37737
|
async function completePathToken({ text, cwd, homeDirectory = homedir() }) {
|
|
37603
37738
|
const token = activePathToken(text);
|
|
@@ -37605,8 +37740,8 @@ async function completePathToken({ text, cwd, homeDirectory = homedir() }) {
|
|
|
37605
37740
|
return [];
|
|
37606
37741
|
const pathText = token.startsWith("@") ? token.slice(1) : token;
|
|
37607
37742
|
const pathUsesTilde = pathText === "~" || pathText.startsWith("~/");
|
|
37608
|
-
const expandedPath = pathText === "~" ? homeDirectory : pathText.startsWith("~/") ?
|
|
37609
|
-
const absolutePath =
|
|
37743
|
+
const expandedPath = pathText === "~" ? homeDirectory : pathText.startsWith("~/") ? join6(homeDirectory, pathText.slice(2)) : pathText;
|
|
37744
|
+
const absolutePath = isAbsolute2(expandedPath) ? expandedPath : resolve2(cwd, expandedPath);
|
|
37610
37745
|
const directory = pathText === "" || pathText === "~" || pathText.endsWith("/") ? absolutePath : dirname5(absolutePath);
|
|
37611
37746
|
const prefix = pathText === "" || pathText === "~" || pathText.endsWith("/") ? "" : basename3(absolutePath);
|
|
37612
37747
|
let entries;
|
|
@@ -37616,8 +37751,8 @@ async function completePathToken({ text, cwd, homeDirectory = homedir() }) {
|
|
|
37616
37751
|
return [];
|
|
37617
37752
|
}
|
|
37618
37753
|
return entries.filter((entry) => entry.name.toLowerCase().startsWith(prefix.toLowerCase())).sort((left, right) => left.name.localeCompare(right.name)).slice(0, maximumCandidates).map((entry) => {
|
|
37619
|
-
const completedPath =
|
|
37620
|
-
const replacementPath = pathUsesTilde ? `~/${
|
|
37754
|
+
const completedPath = join6(directory, entry.name);
|
|
37755
|
+
const replacementPath = pathUsesTilde ? `~/${relative2(homeDirectory, completedPath)}` : isAbsolute2(pathText) ? completedPath : relative2(cwd, completedPath) || entry.name;
|
|
37621
37756
|
const normalized = replacementPath.split(sep).join("/");
|
|
37622
37757
|
const suffix = entry.isDirectory() ? "/" : "";
|
|
37623
37758
|
const completed = `${normalized}${suffix}`;
|
|
@@ -40517,7 +40652,7 @@ import { Buffer as Buffer2 } from "buffer";
|
|
|
40517
40652
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
40518
40653
|
import { mkdtemp as mkdtemp2, open as open5, readdir as readdir2, rm as rm2, stat, writeFile as writeFile3 } from "fs/promises";
|
|
40519
40654
|
import { homedir as homedir2, tmpdir } from "os";
|
|
40520
|
-
import { basename as basename4, isAbsolute as
|
|
40655
|
+
import { basename as basename4, isAbsolute as isAbsolute3, join as join7, resolve as resolve3 } from "path";
|
|
40521
40656
|
var directoryArchiveMediaType = "application/gzip";
|
|
40522
40657
|
var directoryArchiveSuffix = ".tar.gz";
|
|
40523
40658
|
var maxPortableFilenameBytes = 255;
|
|
@@ -40561,7 +40696,7 @@ async function writePastedImage({
|
|
|
40561
40696
|
const extension = extensionForMediaType(mediaType);
|
|
40562
40697
|
if (!extension)
|
|
40563
40698
|
throw new Error(`Unsupported pasted image MIME type: ${mediaType}`);
|
|
40564
|
-
const filePath =
|
|
40699
|
+
const filePath = join7(temporaryDirectory, `remy-paste-${randomUUID4()}.${extension}`);
|
|
40565
40700
|
await writeFile3(filePath, bytes, { mode: 384 });
|
|
40566
40701
|
return filePath;
|
|
40567
40702
|
}
|
|
@@ -40646,9 +40781,9 @@ async function createDirectoryArchive(directoryPath) {
|
|
|
40646
40781
|
});
|
|
40647
40782
|
if (Object.keys(files).length === 0)
|
|
40648
40783
|
throw new Error(`Directory attachment contains no regular files: ${directoryPath}`);
|
|
40649
|
-
const temporaryDirectory = await mkdtemp2(
|
|
40784
|
+
const temporaryDirectory = await mkdtemp2(join7(tmpdir(), "remy-directory-attachment-"));
|
|
40650
40785
|
const filename = directoryArchiveFilename(rootName);
|
|
40651
|
-
const archivePath =
|
|
40786
|
+
const archivePath = join7(temporaryDirectory, filename);
|
|
40652
40787
|
try {
|
|
40653
40788
|
await Bun.Archive.write(archivePath, files, { compress: "gzip" });
|
|
40654
40789
|
if ((await stat(archivePath)).size > fileUploadMaxBytes)
|
|
@@ -40670,7 +40805,7 @@ async function collectDirectoryFiles({
|
|
|
40670
40805
|
entries.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
|
|
40671
40806
|
let byteSize = collectedByteSize;
|
|
40672
40807
|
for (const entry of entries) {
|
|
40673
|
-
const entryPath =
|
|
40808
|
+
const entryPath = join7(directoryPath, entry.name);
|
|
40674
40809
|
const entryArchivePath = `${archivePath}/${entry.name}`;
|
|
40675
40810
|
if (entry.isDirectory()) {
|
|
40676
40811
|
byteSize = await collectDirectoryFiles({
|
|
@@ -40739,7 +40874,7 @@ function truncateUtf8(value, maxBytes) {
|
|
|
40739
40874
|
function promptFilePaths({ text, cwd, selectedPaths }) {
|
|
40740
40875
|
const paths = new Map;
|
|
40741
40876
|
for (const selectedPath of selectedPaths)
|
|
40742
|
-
paths.set(
|
|
40877
|
+
paths.set(isAbsolute3(selectedPath) ? selectedPath : resolve3(cwd, selectedPath), true);
|
|
40743
40878
|
const tokens = text.match(/[([{]*@?(?:"[^"]*"|'[^']*'|`[^`]*`)|(?:\\.|[^\s\\])+/g) ?? [];
|
|
40744
40879
|
for (const quotedToken of tokens) {
|
|
40745
40880
|
const wrappedToken = quotedToken.replace(/^[([{]+/, "").replace(/[),.;:!?\]}]+$/, "");
|
|
@@ -40748,12 +40883,12 @@ function promptFilePaths({ text, cwd, selectedPaths }) {
|
|
|
40748
40883
|
const pathText = token.startsWith("@") ? token.slice(1) : token;
|
|
40749
40884
|
if (!pathText)
|
|
40750
40885
|
continue;
|
|
40751
|
-
const explicit = token.startsWith("@") || pathText.startsWith("./") || pathText.startsWith("../") ||
|
|
40886
|
+
const explicit = token.startsWith("@") || pathText.startsWith("./") || pathText.startsWith("../") || isAbsolute3(pathText) || pathText.startsWith("~/");
|
|
40752
40887
|
const pathShaped = explicit || pathText.includes("/") || pathText.includes("\\") || pathText.includes(".");
|
|
40753
40888
|
if (!pathShaped)
|
|
40754
40889
|
continue;
|
|
40755
|
-
const expandedPath = pathText.startsWith("~/") ?
|
|
40756
|
-
const filePath =
|
|
40890
|
+
const expandedPath = pathText.startsWith("~/") ? join7(homedir2(), pathText.slice(2)) : pathText;
|
|
40891
|
+
const filePath = isAbsolute3(expandedPath) ? expandedPath : resolve3(cwd, expandedPath);
|
|
40757
40892
|
paths.set(filePath, paths.get(filePath) || explicit);
|
|
40758
40893
|
}
|
|
40759
40894
|
return [...paths].map(([filePath, explicit]) => ({ filePath, explicit }));
|
|
@@ -40775,6 +40910,7 @@ function isPng(bytes) {
|
|
|
40775
40910
|
|
|
40776
40911
|
// src/tui/remy-splash.ts
|
|
40777
40912
|
import { bold as bold6, BoxRenderable as BoxRenderable4, fg as fg11, NativeImage, StyledText as StyledText10, TextRenderable as TextRenderable5, bg as bg4 } from "@opentui/core";
|
|
40913
|
+
|
|
40778
40914
|
// src/tui/remy-mark.ts
|
|
40779
40915
|
var remyPixelFieldSource = new URL("../assets/remy-pixel-field.png", import.meta.url);
|
|
40780
40916
|
function shouldShowRemySplash({ width, height }) {
|
|
@@ -40792,7 +40928,6 @@ var compactMarkRows = 9;
|
|
|
40792
40928
|
var compactMinWidth = 48;
|
|
40793
40929
|
var compactMinHeight = 20;
|
|
40794
40930
|
var markBrightnessGain = 4.2;
|
|
40795
|
-
var remyCliVersion = "1.20.0";
|
|
40796
40931
|
async function showRemySplash({
|
|
40797
40932
|
createRenderer = createRemyRenderer,
|
|
40798
40933
|
durationMs = splashDurationMs,
|
|
@@ -41149,6 +41284,34 @@ async function dispatchCliCommandWithShutdown({
|
|
|
41149
41284
|
dependencies.output.writeStdout(helpUsage(command.topic));
|
|
41150
41285
|
return 0;
|
|
41151
41286
|
}
|
|
41287
|
+
if (command.name === "version") {
|
|
41288
|
+
dependencies.output.writeStdout(`${dependencies.updates.currentVersion}
|
|
41289
|
+
`);
|
|
41290
|
+
return 0;
|
|
41291
|
+
}
|
|
41292
|
+
if (command.name === "update") {
|
|
41293
|
+
if (dependencies.updates.currentVersion === "0.0.0")
|
|
41294
|
+
throw new Error("This is a development checkout. Update the checkout instead of running remy update.");
|
|
41295
|
+
const version5 = await dependencies.updates.check(dependencies.abortSignal);
|
|
41296
|
+
if (version5)
|
|
41297
|
+
await installCliUpdate({ dependencies, version: version5 });
|
|
41298
|
+
else
|
|
41299
|
+
dependencies.output.writeStdout(`Remy ${dependencies.updates.currentVersion} is up to date.
|
|
41300
|
+
`);
|
|
41301
|
+
return 0;
|
|
41302
|
+
}
|
|
41303
|
+
if (command.name === "dashboard" && isInteractiveTerminal(dependencies)) {
|
|
41304
|
+
let version5 = null;
|
|
41305
|
+
try {
|
|
41306
|
+
version5 = await dependencies.updates.check(dependencies.abortSignal);
|
|
41307
|
+
} catch {
|
|
41308
|
+
throwIfAborted2(dependencies.abortSignal);
|
|
41309
|
+
}
|
|
41310
|
+
if (version5 && await dependencies.updates.confirm({ version: version5, signal: dependencies.abortSignal, interrupt })) {
|
|
41311
|
+
await installCliUpdate({ dependencies, version: version5 });
|
|
41312
|
+
return 0;
|
|
41313
|
+
}
|
|
41314
|
+
}
|
|
41152
41315
|
if (command.name === "login")
|
|
41153
41316
|
return await openExplicitLogin({ dependencies, flags: command.flags, interrupt });
|
|
41154
41317
|
if (command.name === "logout")
|
|
@@ -41168,6 +41331,13 @@ async function dispatchCliCommandWithShutdown({
|
|
|
41168
41331
|
return await attachSession({ dependencies, sessionId: command.sessionId, noTui: command.noTui, json: command.json, prompt: command.prompt });
|
|
41169
41332
|
return await createNewSession({ dependencies, command });
|
|
41170
41333
|
}
|
|
41334
|
+
async function installCliUpdate({ dependencies, version: version5 }) {
|
|
41335
|
+
dependencies.output.writeStderr(`Updating Remy ${dependencies.updates.currentVersion} to ${version5}...
|
|
41336
|
+
`);
|
|
41337
|
+
await dependencies.updates.install(version5, dependencies.abortSignal);
|
|
41338
|
+
dependencies.output.writeStdout(`Remy updated to ${version5}. Run remy again to use the new version.
|
|
41339
|
+
`);
|
|
41340
|
+
}
|
|
41171
41341
|
function createCliShutdown({ abortSignal }) {
|
|
41172
41342
|
const controller = new AbortController;
|
|
41173
41343
|
const abortFromProcess = (signal) => {
|
|
@@ -41307,7 +41477,7 @@ ${approvalUrl}
|
|
|
41307
41477
|
tokenPath: paths.tokenPath,
|
|
41308
41478
|
candidatePath: candidateTokenPath,
|
|
41309
41479
|
backupPath: previousTokenPath,
|
|
41310
|
-
quarantinePath:
|
|
41480
|
+
quarantinePath: join8(dirname6(paths.tokenPath), `.tokens.quarantine.${process.pid}.${randomUUID5()}.json`)
|
|
41311
41481
|
};
|
|
41312
41482
|
await writeCredentialPromotionJournal({ stateDirectory: dirname6(paths.tokenPath), journal, ...dependencies.credentialStateFilesystem });
|
|
41313
41483
|
journalPrepared = true;
|
|
@@ -42199,7 +42369,7 @@ async function runAttachedSession({
|
|
|
42199
42369
|
client: operations.client,
|
|
42200
42370
|
sessionId,
|
|
42201
42371
|
file: file3,
|
|
42202
|
-
directory:
|
|
42372
|
+
directory: join8(dependencies.environment.HOME ?? homedir3(), "Downloads"),
|
|
42203
42373
|
signal,
|
|
42204
42374
|
fetchClient: globalThis.fetch
|
|
42205
42375
|
}),
|
|
@@ -42424,10 +42594,10 @@ async function collectAllUsers({
|
|
|
42424
42594
|
}
|
|
42425
42595
|
}
|
|
42426
42596
|
function resolveSessionCachePathForCommand({ dependencies, sessionId }) {
|
|
42427
|
-
const stateBase = dependencies.environment.XDG_STATE_HOME ?? (dependencies.environment.HOME ?
|
|
42597
|
+
const stateBase = dependencies.environment.XDG_STATE_HOME ?? (dependencies.environment.HOME ? join8(dependencies.environment.HOME, ".local/state") : undefined);
|
|
42428
42598
|
if (!stateBase)
|
|
42429
42599
|
throw new Error("HOME is required when XDG_STATE_HOME is not set; refusing to read Remy session cache.");
|
|
42430
|
-
return
|
|
42600
|
+
return join8(stateBase, "remy", "sessions", `${sessionId}.json`);
|
|
42431
42601
|
}
|
|
42432
42602
|
function isInteractiveTerminal(dependencies) {
|
|
42433
42603
|
return dependencies.isTerminal?.() ?? (process.stdin.isTTY === true && process.stdout.isTTY === true);
|
|
@@ -42445,6 +42615,18 @@ function parseCommand(argv) {
|
|
|
42445
42615
|
throw new Error(`${commandName} does not accept arguments.`);
|
|
42446
42616
|
return { name: "help", topic: "root" };
|
|
42447
42617
|
}
|
|
42618
|
+
if (commandName === "--version" || commandName === "-v") {
|
|
42619
|
+
if (rest.length > 0)
|
|
42620
|
+
throw new Error(`${commandName} does not accept arguments.`);
|
|
42621
|
+
return { name: "version" };
|
|
42622
|
+
}
|
|
42623
|
+
if (commandName === "update") {
|
|
42624
|
+
if (isHelpRequest(rest))
|
|
42625
|
+
return { name: "help", topic: "update" };
|
|
42626
|
+
if (rest.length > 0)
|
|
42627
|
+
throw new Error("remy update does not accept arguments.");
|
|
42628
|
+
return { name: "update" };
|
|
42629
|
+
}
|
|
42448
42630
|
if (commandName === "dashboard") {
|
|
42449
42631
|
if (isHelpRequest(rest))
|
|
42450
42632
|
return { name: "help", topic: "dashboard" };
|
|
@@ -42477,7 +42659,7 @@ function parseCommand(argv) {
|
|
|
42477
42659
|
}
|
|
42478
42660
|
if (commandName.startsWith("--"))
|
|
42479
42661
|
throw new Error(`Unknown root flag ${commandName}. Use --session <session-id> to attach or remy new to create a session.`);
|
|
42480
|
-
throw new Error(`Unknown command ${commandName}. Expected login, logout, whoami, or
|
|
42662
|
+
throw new Error(`Unknown command ${commandName}. Expected dashboard, login, logout, whoami, new, or update.`);
|
|
42481
42663
|
}
|
|
42482
42664
|
function isHelpRequest(argv) {
|
|
42483
42665
|
return argv.length === 1 && isHelpFlag(argv[0]);
|
|
@@ -42486,6 +42668,17 @@ function isHelpFlag(value) {
|
|
|
42486
42668
|
return value === "--help" || value === "-h";
|
|
42487
42669
|
}
|
|
42488
42670
|
function helpUsage(topic) {
|
|
42671
|
+
if (topic === "update") {
|
|
42672
|
+
return `Usage: remy update
|
|
42673
|
+
|
|
42674
|
+
Install a newer Remy CLI release using the original package manager (mise, bun, pnpm, or npm).
|
|
42675
|
+
Stable installations stay on latest; RC installations also check rc. No sign-in is required.
|
|
42676
|
+
After updating, run Remy again. Local and temporary installations must be updated by their caller.
|
|
42677
|
+
|
|
42678
|
+
Options:
|
|
42679
|
+
--help, -h Show this help
|
|
42680
|
+
`;
|
|
42681
|
+
}
|
|
42489
42682
|
if (topic === "login") {
|
|
42490
42683
|
return `Usage: remy login [options]
|
|
42491
42684
|
|
|
@@ -42577,6 +42770,8 @@ Commands:
|
|
|
42577
42770
|
Sign in
|
|
42578
42771
|
remy logout [--api-url <url>] Sign out
|
|
42579
42772
|
remy whoami Show signed-in identity
|
|
42773
|
+
remy update Update the installed CLI
|
|
42774
|
+
remy --version Show the installed version
|
|
42580
42775
|
remy help Show this help
|
|
42581
42776
|
|
|
42582
42777
|
Options:
|
|
@@ -42701,7 +42896,7 @@ async function readOptionalCliConfiguration(path) {
|
|
|
42701
42896
|
async function createCandidateTokenPath(activeTokenPath) {
|
|
42702
42897
|
const directory = dirname6(activeTokenPath);
|
|
42703
42898
|
await mkdir6(directory, { recursive: true, mode: 448 });
|
|
42704
|
-
return
|
|
42899
|
+
return join8(directory, `.tokens.${process.pid}.${randomUUID5()}.tmp`);
|
|
42705
42900
|
}
|
|
42706
42901
|
async function removeCandidateToken({
|
|
42707
42902
|
path,
|
|
@@ -42730,7 +42925,7 @@ async function removeCommittedTokenRecoveryArtifacts({
|
|
|
42730
42925
|
for (const entry of entries) {
|
|
42731
42926
|
if (!isCommittedTokenRecoveryArtifact(entry))
|
|
42732
42927
|
continue;
|
|
42733
|
-
await removeCandidateToken({ path:
|
|
42928
|
+
await removeCandidateToken({ path: join8(directory, entry), removeTokenFile });
|
|
42734
42929
|
}
|
|
42735
42930
|
}
|
|
42736
42931
|
function isCommittedTokenRecoveryArtifact(entry) {
|
|
@@ -42801,6 +42996,13 @@ function createDefaultCommandDependencies(argv, sourceEnvironment) {
|
|
|
42801
42996
|
};
|
|
42802
42997
|
return {
|
|
42803
42998
|
argv,
|
|
42999
|
+
updates: createCliUpdates({
|
|
43000
|
+
currentVersion: remyCliVersion,
|
|
43001
|
+
entryPath: process.argv[1] ?? "",
|
|
43002
|
+
fetchClient: fetch,
|
|
43003
|
+
runProcess: runUpdateProcess,
|
|
43004
|
+
confirm: confirmCliUpdate
|
|
43005
|
+
}),
|
|
42804
43006
|
environment: {
|
|
42805
43007
|
HOME: environment.HOME,
|
|
42806
43008
|
XDG_CONFIG_HOME: environment.XDG_CONFIG_HOME,
|
|
@@ -42833,7 +43035,7 @@ async function runBrowserLauncher(command) {
|
|
|
42833
43035
|
if (!executable)
|
|
42834
43036
|
throw new Error("Browser launcher command is empty.");
|
|
42835
43037
|
return await new Promise((resolve4, reject) => {
|
|
42836
|
-
const child =
|
|
43038
|
+
const child = spawn2(executable, arguments_, { stdio: "ignore" });
|
|
42837
43039
|
child.once("error", reject);
|
|
42838
43040
|
child.once("exit", (code) => resolve4(code ?? 1));
|
|
42839
43041
|
});
|