replicas-cli 0.2.369 → 0.2.371
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.mjs +446 -227
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7335,7 +7335,7 @@ var require_dist = __commonJS({
|
|
|
7335
7335
|
// src/index.ts
|
|
7336
7336
|
import "dotenv/config";
|
|
7337
7337
|
import { Command, InvalidArgumentError } from "commander";
|
|
7338
|
-
import
|
|
7338
|
+
import chalk25 from "chalk";
|
|
7339
7339
|
|
|
7340
7340
|
// src/commands/login.ts
|
|
7341
7341
|
import http from "http";
|
|
@@ -9212,24 +9212,18 @@ When you run services on ports \u2014 such as a web app, API server, or database
|
|
|
9212
9212
|
|
|
9213
9213
|
## Running Services for Preview
|
|
9214
9214
|
|
|
9215
|
-
|
|
9215
|
+
Always start services with \`replicas service start\` (see \`REPLICAS.md\`, "Long-running services"). It daemonizes the process so it survives your turn ending and workspace sleep/wake \u2014 a service left attached to your shell or backgrounded with \`&\`/\`nohup\` dies when the workspace sleeps, leaving the preview broken for the user.
|
|
9216
9216
|
|
|
9217
|
-
Some potential methods:
|
|
9218
9217
|
\`\`\`bash
|
|
9219
|
-
|
|
9220
|
-
setsid -f bash -lc 'cd /path/to/app && exec yarn dev >> /tmp/app.log 2>&1'
|
|
9221
|
-
|
|
9222
|
-
# For daemons like Docker
|
|
9223
|
-
nohup dockerd > /tmp/dockerd.log 2>&1 &
|
|
9218
|
+
replicas service start web "yarn dev" --cwd /path/to/app
|
|
9224
9219
|
\`\`\`
|
|
9225
9220
|
|
|
9226
9221
|
After starting a service:
|
|
9227
|
-
1.
|
|
9228
|
-
2.
|
|
9229
|
-
3.
|
|
9230
|
-
4. Only create the preview after the service is healthy
|
|
9222
|
+
1. Check logs for readiness: \`replicas service logs web\`
|
|
9223
|
+
2. Confirm it's actually serving: \`curl -s http://localhost:3000\` (or appropriate health check)
|
|
9224
|
+
3. Only create the preview after the service is healthy
|
|
9231
9225
|
|
|
9232
|
-
|
|
9226
|
+
\`replicas service start\` on the same name restarts the service, so you never need to hunt down stale processes on the port.
|
|
9233
9227
|
|
|
9234
9228
|
## Creating Previews
|
|
9235
9229
|
|
|
@@ -9302,7 +9296,8 @@ Use this when:
|
|
|
9302
9296
|
- The user asks you to create, edit, run, or delete an automation
|
|
9303
9297
|
- The user asks you to manage environments, environment variables, or environment files
|
|
9304
9298
|
- The user asks "what envs / repos / automations do I have?"
|
|
9305
|
-
- The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo
|
|
9299
|
+
- The user asks you to scaffold a \`replicas.json\` / \`replicas.yaml\` in a repo
|
|
9300
|
+
- You need to run a long-lived service (dev server, daemon) \u2014 always use \`replicas service start\` so it survives workspace sleep/wake`;
|
|
9306
9301
|
var REFERENCE10 = `# Replicas (in-workspace CLI)
|
|
9307
9302
|
|
|
9308
9303
|
This guide covers how to take action *with* Replicas itself from inside a Replicas workspace \u2014 managing automations, environments (and their variables/files), repos, previews, and the user's \`replicas.json\` config \u2014 using the pre-installed \`replicas\` CLI.
|
|
@@ -9338,6 +9333,7 @@ In agent mode the CLI hides commands that don't make sense for in-workspace agen
|
|
|
9338
9333
|
| \`replicas environment ...\` | Manage environments, env vars, env files |
|
|
9339
9334
|
| \`replicas automation ...\` | Manage automations (cron + GitHub/GitLab event triggers) |
|
|
9340
9335
|
| \`replicas preview ...\` | Register / list preview URLs (covered in \`PREVIEWS.md\`) |
|
|
9336
|
+
| \`replicas service ...\` | Run long-lived services detached so they survive workspace sleep/wake (see below) |
|
|
9341
9337
|
| \`replicas media ...\` | Upload screenshots, videos, audio (covered in \`MEDIA.md\`) |
|
|
9342
9338
|
| \`replicas slack thread ...\` | Attach or switch Slack thread routing (covered in \`SLACK.md\`) |
|
|
9343
9339
|
|
|
@@ -9479,6 +9475,24 @@ replicas automation edit <id> \\
|
|
|
9479
9475
|
|
|
9480
9476
|
\`replicas automation edit <id>\` with no flags drops into interactive mode.
|
|
9481
9477
|
|
|
9478
|
+
## Long-running services
|
|
9479
|
+
|
|
9480
|
+
**Always use \`replicas service start\` to run anything that should keep running after your current command or turn ends** \u2014 dev servers, backend APIs, databases, daemons, watchers. Never leave them attached to your shell, and never rely on plain \`&\`, \`nohup\`, or your own backgrounding: processes started inside your session are torn down when your turn ends and the workspace goes to sleep, so the user finds them dead after waking the workspace. \`replicas service start\` daemonizes the process into its own session, which survives workspace sleep/wake.
|
|
9481
|
+
|
|
9482
|
+
\`\`\`bash
|
|
9483
|
+
replicas service start <name> "<command>" # start (or restart) a named service
|
|
9484
|
+
replicas service start web "bun run dev" --cwd ~/workspaces/app
|
|
9485
|
+
replicas service list # names, pids, running/stopped
|
|
9486
|
+
replicas service logs <name> [-n 100] # tail the service log
|
|
9487
|
+
replicas service stop <name> # stop the whole process group
|
|
9488
|
+
\`\`\`
|
|
9489
|
+
|
|
9490
|
+
Notes:
|
|
9491
|
+
- Quote the command if it contains shell operators: \`replicas service start web "cd app && bun dev"\`.
|
|
9492
|
+
- \`start\` on an existing name restarts it (the old process group is stopped first). It fails fast and prints the log tail if the service dies within the first second.
|
|
9493
|
+
- Logs stream to \`~/.replicas/services/<name>.log\`.
|
|
9494
|
+
- After starting, verify the service is actually healthy (check \`logs\`, then \`curl\` its port) before telling the user it's up or creating a preview for it.
|
|
9495
|
+
|
|
9482
9496
|
## Repositories
|
|
9483
9497
|
|
|
9484
9498
|
Read-only listing of repos connected to the org. Use when the user asks "what repos can I use?", or to validate a \`--repository\` value before passing it to \`environment create\` / \`automation create\`:
|
|
@@ -9736,7 +9750,7 @@ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
|
9736
9750
|
var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
|
|
9737
9751
|
|
|
9738
9752
|
// ../shared/src/cli-version.ts
|
|
9739
|
-
var CLI_VERSION = "0.2.
|
|
9753
|
+
var CLI_VERSION = "0.2.371";
|
|
9740
9754
|
|
|
9741
9755
|
// ../shared/src/version.ts
|
|
9742
9756
|
function compareVersions(v1, v2) {
|
|
@@ -12095,7 +12109,7 @@ function generateState() {
|
|
|
12095
12109
|
}
|
|
12096
12110
|
async function loginCommand() {
|
|
12097
12111
|
const state = generateState();
|
|
12098
|
-
return new Promise((
|
|
12112
|
+
return new Promise((resolve3, reject) => {
|
|
12099
12113
|
let authTimeout;
|
|
12100
12114
|
let hasHandledCallback = false;
|
|
12101
12115
|
let lastRedirectUrl = null;
|
|
@@ -12232,7 +12246,7 @@ async function loginCommand() {
|
|
|
12232
12246
|
setImmediate(() => {
|
|
12233
12247
|
server.closeAllConnections?.();
|
|
12234
12248
|
server.close();
|
|
12235
|
-
|
|
12249
|
+
resolve3();
|
|
12236
12250
|
});
|
|
12237
12251
|
} catch (error2) {
|
|
12238
12252
|
const errorUrl = `${WEB_APP_URL}/cli-login/error?message=${encodeURIComponent("Failed to verify authentication.")}`;
|
|
@@ -12335,13 +12349,13 @@ import chalk5 from "chalk";
|
|
|
12335
12349
|
import { spawn } from "child_process";
|
|
12336
12350
|
var SSH_OPTIONS = ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null"];
|
|
12337
12351
|
async function connectSSH(token, host, proxyCommand) {
|
|
12338
|
-
return new Promise((
|
|
12352
|
+
return new Promise((resolve3, reject) => {
|
|
12339
12353
|
const sshArgs = proxyCommand ? [...SSH_OPTIONS, "-o", `ProxyCommand=${proxyCommand}`, `${token}@${host}`] : [...SSH_OPTIONS, `${token}@${host}`];
|
|
12340
12354
|
const ssh = spawn("ssh", sshArgs, {
|
|
12341
12355
|
stdio: "inherit"
|
|
12342
12356
|
});
|
|
12343
12357
|
ssh.on("close", () => {
|
|
12344
|
-
|
|
12358
|
+
resolve3();
|
|
12345
12359
|
});
|
|
12346
12360
|
ssh.on("error", reject);
|
|
12347
12361
|
});
|
|
@@ -12852,7 +12866,7 @@ async function exchangeCodeForTokens(code, codeVerifier) {
|
|
|
12852
12866
|
};
|
|
12853
12867
|
}
|
|
12854
12868
|
function startCallbackServer(expectedState, codeVerifier) {
|
|
12855
|
-
return new Promise((
|
|
12869
|
+
return new Promise((resolve3, reject) => {
|
|
12856
12870
|
const server = http2.createServer(async (req, res) => {
|
|
12857
12871
|
try {
|
|
12858
12872
|
if (!req.url) {
|
|
@@ -12895,7 +12909,7 @@ function startCallbackServer(expectedState, codeVerifier) {
|
|
|
12895
12909
|
res.writeHead(302, { "Location": `${WEB_APP_URL2}/codex/oauth/success` });
|
|
12896
12910
|
res.end();
|
|
12897
12911
|
server.close();
|
|
12898
|
-
|
|
12912
|
+
resolve3(tokens);
|
|
12899
12913
|
} catch (tokenError) {
|
|
12900
12914
|
const errorMessage = encodeURIComponent(tokenError instanceof Error ? tokenError.message : "Unknown error");
|
|
12901
12915
|
res.writeHead(302, { "Location": `${WEB_APP_URL2}/codex/oauth/error?message=${errorMessage}` });
|
|
@@ -12929,7 +12943,7 @@ async function runCodexOAuthFlow() {
|
|
|
12929
12943
|
const state = generateState2();
|
|
12930
12944
|
const authUrl = buildAuthorizationUrl(pkce.codeChallenge, state);
|
|
12931
12945
|
const tokensPromise = startCallbackServer(state, pkce.codeVerifier);
|
|
12932
|
-
await new Promise((
|
|
12946
|
+
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
12933
12947
|
console.log("If the browser does not open automatically, visit:");
|
|
12934
12948
|
console.log(authUrl);
|
|
12935
12949
|
console.log();
|
|
@@ -13048,10 +13062,10 @@ async function promptForAuthorizationCode(instruction) {
|
|
|
13048
13062
|
input: process.stdin,
|
|
13049
13063
|
output: process.stdout
|
|
13050
13064
|
});
|
|
13051
|
-
return new Promise((
|
|
13065
|
+
return new Promise((resolve3) => {
|
|
13052
13066
|
rl.question(instruction, (answer) => {
|
|
13053
13067
|
rl.close();
|
|
13054
|
-
|
|
13068
|
+
resolve3(answer.trim());
|
|
13055
13069
|
});
|
|
13056
13070
|
});
|
|
13057
13071
|
}
|
|
@@ -14889,6 +14903,169 @@ async function slackThreadSwitchCommand(workspace, options) {
|
|
|
14889
14903
|
});
|
|
14890
14904
|
}
|
|
14891
14905
|
|
|
14906
|
+
// src/commands/service.ts
|
|
14907
|
+
import chalk21 from "chalk";
|
|
14908
|
+
import { spawn as spawn3 } from "child_process";
|
|
14909
|
+
import { closeSync, mkdirSync, openSync, readdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
14910
|
+
import { homedir } from "os";
|
|
14911
|
+
import { join, resolve } from "path";
|
|
14912
|
+
var SERVICES_DIR = join(homedir(), ".replicas", "services");
|
|
14913
|
+
var NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
14914
|
+
function isValidServiceName(name) {
|
|
14915
|
+
return NAME_PATTERN.test(name);
|
|
14916
|
+
}
|
|
14917
|
+
function tailLines(content, lines) {
|
|
14918
|
+
const all = content.split("\n");
|
|
14919
|
+
if (all.length > 0 && all[all.length - 1] === "") all.pop();
|
|
14920
|
+
return all.slice(-lines).join("\n").trim();
|
|
14921
|
+
}
|
|
14922
|
+
function statePath(name) {
|
|
14923
|
+
return join(SERVICES_DIR, `${name}.json`);
|
|
14924
|
+
}
|
|
14925
|
+
function isServiceState(value) {
|
|
14926
|
+
if (typeof value !== "object" || value === null) return false;
|
|
14927
|
+
const record = value;
|
|
14928
|
+
return typeof record.name === "string" && typeof record.command === "string" && typeof record.cwd === "string" && typeof record.pid === "number" && typeof record.logFile === "string" && typeof record.startedAt === "string";
|
|
14929
|
+
}
|
|
14930
|
+
function readState(name) {
|
|
14931
|
+
let parsed;
|
|
14932
|
+
try {
|
|
14933
|
+
parsed = JSON.parse(readFileSync(statePath(name), "utf-8"));
|
|
14934
|
+
} catch {
|
|
14935
|
+
return null;
|
|
14936
|
+
}
|
|
14937
|
+
return isServiceState(parsed) ? parsed : null;
|
|
14938
|
+
}
|
|
14939
|
+
function isRunning(pid) {
|
|
14940
|
+
try {
|
|
14941
|
+
process.kill(-pid, 0);
|
|
14942
|
+
return true;
|
|
14943
|
+
} catch {
|
|
14944
|
+
return false;
|
|
14945
|
+
}
|
|
14946
|
+
}
|
|
14947
|
+
function sleep(ms) {
|
|
14948
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
14949
|
+
}
|
|
14950
|
+
async function killServiceGroup(pid) {
|
|
14951
|
+
try {
|
|
14952
|
+
process.kill(-pid, "SIGTERM");
|
|
14953
|
+
} catch {
|
|
14954
|
+
return;
|
|
14955
|
+
}
|
|
14956
|
+
for (let i = 0; i < 20; i++) {
|
|
14957
|
+
if (!isRunning(pid)) return;
|
|
14958
|
+
await sleep(250);
|
|
14959
|
+
}
|
|
14960
|
+
try {
|
|
14961
|
+
process.kill(-pid, "SIGKILL");
|
|
14962
|
+
} catch {
|
|
14963
|
+
}
|
|
14964
|
+
}
|
|
14965
|
+
function tailLog(logFile, lines) {
|
|
14966
|
+
try {
|
|
14967
|
+
return tailLines(readFileSync(logFile, "utf-8"), lines);
|
|
14968
|
+
} catch {
|
|
14969
|
+
return "";
|
|
14970
|
+
}
|
|
14971
|
+
}
|
|
14972
|
+
async function serviceStartCommand(name, commandParts, options) {
|
|
14973
|
+
if (!isValidServiceName(name)) {
|
|
14974
|
+
throw new Error('Service name must start with a letter or digit and contain only letters, digits, ".", "_", or "-"');
|
|
14975
|
+
}
|
|
14976
|
+
const command = commandParts.join(" ").trim();
|
|
14977
|
+
if (!command) {
|
|
14978
|
+
throw new Error('Provide the command to run, e.g.: replicas service start web "bun run dev"');
|
|
14979
|
+
}
|
|
14980
|
+
const existing = readState(name);
|
|
14981
|
+
if (existing && isRunning(existing.pid)) {
|
|
14982
|
+
console.log(`Stopping existing "${name}" (pid ${existing.pid}) before restart`);
|
|
14983
|
+
await killServiceGroup(existing.pid);
|
|
14984
|
+
}
|
|
14985
|
+
mkdirSync(SERVICES_DIR, { recursive: true });
|
|
14986
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
14987
|
+
const logFile = join(SERVICES_DIR, `${name}.log`);
|
|
14988
|
+
const logFd = openSync(logFile, "a");
|
|
14989
|
+
writeFileSync(logFd, `
|
|
14990
|
+
=== [replicas service] "${name}" started ${(/* @__PURE__ */ new Date()).toISOString()} in ${cwd}: ${command} ===
|
|
14991
|
+
`);
|
|
14992
|
+
const child = spawn3("bash", ["-lc", command], {
|
|
14993
|
+
cwd,
|
|
14994
|
+
detached: true,
|
|
14995
|
+
stdio: ["ignore", logFd, logFd],
|
|
14996
|
+
env: process.env
|
|
14997
|
+
});
|
|
14998
|
+
closeSync(logFd);
|
|
14999
|
+
if (child.pid === void 0) {
|
|
15000
|
+
throw new Error("Failed to spawn service process");
|
|
15001
|
+
}
|
|
15002
|
+
child.unref();
|
|
15003
|
+
const state = {
|
|
15004
|
+
name,
|
|
15005
|
+
command,
|
|
15006
|
+
cwd,
|
|
15007
|
+
pid: child.pid,
|
|
15008
|
+
logFile,
|
|
15009
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15010
|
+
};
|
|
15011
|
+
writeFileSync(statePath(name), JSON.stringify(state, null, 2));
|
|
15012
|
+
await sleep(1e3);
|
|
15013
|
+
if (!isRunning(child.pid)) {
|
|
15014
|
+
const logs = tailLog(logFile, 20);
|
|
15015
|
+
rmSync(statePath(name), { force: true });
|
|
15016
|
+
throw new Error(`Service "${name}" exited immediately.${logs ? `
|
|
15017
|
+
|
|
15018
|
+
Last log output:
|
|
15019
|
+
${logs}` : ""}`);
|
|
15020
|
+
}
|
|
15021
|
+
console.log(`Started "${name}" (pid ${child.pid})`);
|
|
15022
|
+
console.log(`Logs: ${logFile}`);
|
|
15023
|
+
}
|
|
15024
|
+
async function serviceStopCommand(name) {
|
|
15025
|
+
const state = readState(name);
|
|
15026
|
+
if (!state) {
|
|
15027
|
+
throw new Error(`Unknown service "${name}". Run: replicas service list`);
|
|
15028
|
+
}
|
|
15029
|
+
if (isRunning(state.pid)) {
|
|
15030
|
+
await killServiceGroup(state.pid);
|
|
15031
|
+
console.log(`Stopped "${name}" (pid ${state.pid})`);
|
|
15032
|
+
} else {
|
|
15033
|
+
console.log(`Service "${name}" was not running`);
|
|
15034
|
+
}
|
|
15035
|
+
rmSync(statePath(name), { force: true });
|
|
15036
|
+
}
|
|
15037
|
+
async function serviceListCommand() {
|
|
15038
|
+
let entries;
|
|
15039
|
+
try {
|
|
15040
|
+
entries = readdirSync(SERVICES_DIR).filter((f) => f.endsWith(".json"));
|
|
15041
|
+
} catch {
|
|
15042
|
+
entries = [];
|
|
15043
|
+
}
|
|
15044
|
+
const states = entries.map((f) => readState(f.slice(0, -".json".length))).filter((s) => s !== null);
|
|
15045
|
+
if (states.length === 0) {
|
|
15046
|
+
console.log('No services registered. Start one with: replicas service start <name> "<command>"');
|
|
15047
|
+
return;
|
|
15048
|
+
}
|
|
15049
|
+
for (const state of states) {
|
|
15050
|
+
const status = isRunning(state.pid) ? chalk21.green("running") : chalk21.red("stopped");
|
|
15051
|
+
console.log(`${state.name} ${status} pid ${state.pid} started ${state.startedAt}`);
|
|
15052
|
+
console.log(` command: ${state.command} (cwd: ${state.cwd})`);
|
|
15053
|
+
console.log(` logs: ${state.logFile}`);
|
|
15054
|
+
}
|
|
15055
|
+
}
|
|
15056
|
+
async function serviceLogsCommand(name, options) {
|
|
15057
|
+
const state = readState(name);
|
|
15058
|
+
if (!state) {
|
|
15059
|
+
throw new Error(`Unknown service "${name}". Run: replicas service list`);
|
|
15060
|
+
}
|
|
15061
|
+
const lines = options.lines ? Number(options.lines) : 50;
|
|
15062
|
+
if (!Number.isInteger(lines) || lines < 1) {
|
|
15063
|
+
throw new Error("--lines must be a positive integer");
|
|
15064
|
+
}
|
|
15065
|
+
const logs = tailLog(state.logFile, lines);
|
|
15066
|
+
console.log(logs || "(no log output yet)");
|
|
15067
|
+
}
|
|
15068
|
+
|
|
14892
15069
|
// src/commands/learnings.ts
|
|
14893
15070
|
function printBlocks(learnings) {
|
|
14894
15071
|
for (const learning of learnings) {
|
|
@@ -14960,16 +15137,16 @@ async function learningsDeleteCommand(id) {
|
|
|
14960
15137
|
}
|
|
14961
15138
|
|
|
14962
15139
|
// src/commands/computer/index.ts
|
|
14963
|
-
import { spawn as
|
|
15140
|
+
import { spawn as spawn5, spawnSync as spawnSync3 } from "child_process";
|
|
14964
15141
|
import { createHash as createHash2 } from "crypto";
|
|
14965
|
-
import { closeSync, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as
|
|
15142
|
+
import { closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync4, readSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
14966
15143
|
import { dirname as dirname3 } from "path";
|
|
14967
|
-
import
|
|
15144
|
+
import chalk22 from "chalk";
|
|
14968
15145
|
|
|
14969
15146
|
// src/commands/computer/desktop.ts
|
|
14970
15147
|
import { spawnSync } from "child_process";
|
|
14971
|
-
import { existsSync, mkdirSync, readFileSync } from "fs";
|
|
14972
|
-
import { dirname, isAbsolute, resolve } from "path";
|
|
15148
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
15149
|
+
import { dirname, isAbsolute, resolve as resolve2 } from "path";
|
|
14973
15150
|
var STATE_DIR = process.env.REPLICAS_DESKTOP_STATE_DIR || "/tmp/replicas-computer";
|
|
14974
15151
|
var DEFAULT_DISPLAY = process.env.REPLICAS_DESKTOP_DISPLAY || ":99";
|
|
14975
15152
|
var NOVNC_PORT = process.env.REPLICAS_DESKTOP_NOVNC_PORT ? parseInt(process.env.REPLICAS_DESKTOP_NOVNC_PORT, 10) : DESKTOP_NOVNC_PORT;
|
|
@@ -15004,7 +15181,7 @@ function desktopStackHealthy() {
|
|
|
15004
15181
|
const pids = {};
|
|
15005
15182
|
for (const name of ["openbox", "tint2", "x11vnc", "novnc"]) {
|
|
15006
15183
|
try {
|
|
15007
|
-
const pid = Number.parseInt(
|
|
15184
|
+
const pid = Number.parseInt(readFileSync2(`${STATE_DIR}/${name}.pid`, "utf8").trim(), 10);
|
|
15008
15185
|
if (!Number.isFinite(pid)) return false;
|
|
15009
15186
|
process.kill(pid, 0);
|
|
15010
15187
|
pids[name] = pid;
|
|
@@ -15047,7 +15224,7 @@ function runDisplayCmd(bin, args) {
|
|
|
15047
15224
|
return r.stdout?.toString() ?? "";
|
|
15048
15225
|
}
|
|
15049
15226
|
function runDesktopInputCmd(args) {
|
|
15050
|
-
|
|
15227
|
+
mkdirSync2(dirname(INPUT_LOCK_FILE), { recursive: true });
|
|
15051
15228
|
return runDisplayCmd("flock", [
|
|
15052
15229
|
"--exclusive",
|
|
15053
15230
|
"--wait",
|
|
@@ -15106,7 +15283,7 @@ function parseScreenCoord(value, label, size) {
|
|
|
15106
15283
|
return n;
|
|
15107
15284
|
}
|
|
15108
15285
|
function resolvePath(p) {
|
|
15109
|
-
return isAbsolute(p) ? p :
|
|
15286
|
+
return isAbsolute(p) ? p : resolve2(process.cwd(), p);
|
|
15110
15287
|
}
|
|
15111
15288
|
function configuredDesktopDimensions() {
|
|
15112
15289
|
const width = parseInt(process.env.REPLICAS_DESKTOP_WIDTH || String(DESKTOP_VIEWER_WIDTH), 10);
|
|
@@ -15118,16 +15295,16 @@ function configuredDesktopDimensions() {
|
|
|
15118
15295
|
function clamp(n, min, max) {
|
|
15119
15296
|
return Math.min(max, Math.max(min, n));
|
|
15120
15297
|
}
|
|
15121
|
-
var
|
|
15298
|
+
var sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
15122
15299
|
|
|
15123
15300
|
// src/commands/computer/recording.ts
|
|
15124
|
-
import { spawn as
|
|
15125
|
-
import { appendFileSync, existsSync as existsSync2, mkdirSync as
|
|
15301
|
+
import { spawn as spawn4 } from "child_process";
|
|
15302
|
+
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, rmSync as rmSync3, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
15126
15303
|
import { dirname as dirname2 } from "path";
|
|
15127
15304
|
|
|
15128
15305
|
// src/commands/computer/recording/render.ts
|
|
15129
15306
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
15130
|
-
import { copyFileSync, rmSync, writeFileSync } from "fs";
|
|
15307
|
+
import { copyFileSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
15131
15308
|
|
|
15132
15309
|
// src/commands/computer/recording/config.ts
|
|
15133
15310
|
var cameraMotion = {
|
|
@@ -15532,7 +15709,7 @@ function renderRecording(rawPath, target, actions, fps, size) {
|
|
|
15532
15709
|
}
|
|
15533
15710
|
const stamp = `${process.pid}-${Date.now()}`;
|
|
15534
15711
|
const cursor = cursorAssets(stamp);
|
|
15535
|
-
|
|
15712
|
+
writeFileSync2(cursor.path, cursorSvg(cursor.size));
|
|
15536
15713
|
const spans = renderedSegmentSpans(segments);
|
|
15537
15714
|
const renderedDuration = spans.length ? spans[spans.length - 1].outputEnd : duration;
|
|
15538
15715
|
const renderedActions = actionsOnRenderedTimeline(actions, spans);
|
|
@@ -15555,7 +15732,7 @@ function renderRecording(rawPath, target, actions, fps, size) {
|
|
|
15555
15732
|
const concatInputs = segments.map((_, index) => `[v${index}]`).join("");
|
|
15556
15733
|
const filter = `${screenSplitFilter};${filters.join(";")};${concatInputs}concat=n=${segments.length}:v=1:a=0[screen];${cursorFilter}`;
|
|
15557
15734
|
const filterPath = `/tmp/replicas-recording-filter-${stamp}.ffgraph`;
|
|
15558
|
-
|
|
15735
|
+
writeFileSync2(filterPath, filter);
|
|
15559
15736
|
try {
|
|
15560
15737
|
const r = spawnSync2("ffmpeg", [
|
|
15561
15738
|
"-y",
|
|
@@ -15590,8 +15767,8 @@ function renderRecording(rawPath, target, actions, fps, size) {
|
|
|
15590
15767
|
fail(`recording post-processing failed: ${r.error?.message || r.stderr?.toString().trim() || `exit ${r.status}`}`);
|
|
15591
15768
|
}
|
|
15592
15769
|
} finally {
|
|
15593
|
-
|
|
15594
|
-
|
|
15770
|
+
rmSync2(filterPath, { force: true });
|
|
15771
|
+
rmSync2(cursor.path, { force: true });
|
|
15595
15772
|
}
|
|
15596
15773
|
}
|
|
15597
15774
|
|
|
@@ -15613,11 +15790,11 @@ var RECORD_STATE_FILES = [
|
|
|
15613
15790
|
RECORD_ACTIONS_FILE
|
|
15614
15791
|
];
|
|
15615
15792
|
function clearRecordingState() {
|
|
15616
|
-
for (const file of RECORD_STATE_FILES)
|
|
15793
|
+
for (const file of RECORD_STATE_FILES) rmSync3(file, { force: true });
|
|
15617
15794
|
}
|
|
15618
15795
|
function recordingStartedAt() {
|
|
15619
15796
|
if (!existsSync2(RECORD_STARTED_AT_FILE)) return null;
|
|
15620
|
-
const startedAt = Number.parseInt(
|
|
15797
|
+
const startedAt = Number.parseInt(readFileSync3(RECORD_STARTED_AT_FILE, "utf8").trim(), 10);
|
|
15621
15798
|
return Number.isFinite(startedAt) ? startedAt : null;
|
|
15622
15799
|
}
|
|
15623
15800
|
function logRecordingAction(action) {
|
|
@@ -15630,7 +15807,7 @@ function logRecordingAction(action) {
|
|
|
15630
15807
|
function readRecordingDimensions() {
|
|
15631
15808
|
if (!existsSync2(RECORD_DIMENSIONS_FILE)) return configuredDesktopDimensions();
|
|
15632
15809
|
try {
|
|
15633
|
-
const dimensions = JSON.parse(
|
|
15810
|
+
const dimensions = JSON.parse(readFileSync3(RECORD_DIMENSIONS_FILE, "utf8"));
|
|
15634
15811
|
const width = dimensions?.width;
|
|
15635
15812
|
const height = dimensions?.height;
|
|
15636
15813
|
if (typeof width === "number" && Number.isFinite(width) && width > 0 && typeof height === "number" && Number.isFinite(height) && height > 0) {
|
|
@@ -15648,7 +15825,7 @@ function isOptionalNumber(value) {
|
|
|
15648
15825
|
}
|
|
15649
15826
|
function readRecordingActions() {
|
|
15650
15827
|
if (!existsSync2(RECORD_ACTIONS_FILE)) return [];
|
|
15651
|
-
return
|
|
15828
|
+
return readFileSync3(RECORD_ACTIONS_FILE, "utf8").split("\n").filter(Boolean).flatMap((line) => {
|
|
15652
15829
|
try {
|
|
15653
15830
|
const value = JSON.parse(line);
|
|
15654
15831
|
if (typeof value !== "object" || value === null) return [];
|
|
@@ -15670,7 +15847,7 @@ function readRecordingActions() {
|
|
|
15670
15847
|
async function computerRecordStartCommand(path6, options) {
|
|
15671
15848
|
ensureServicesRunning();
|
|
15672
15849
|
if (existsSync2(RECORD_PID_FILE)) {
|
|
15673
|
-
const pid = parseInt(
|
|
15850
|
+
const pid = parseInt(readFileSync3(RECORD_PID_FILE, "utf8").trim(), 10);
|
|
15674
15851
|
if (Number.isFinite(pid)) {
|
|
15675
15852
|
let alive2 = false;
|
|
15676
15853
|
try {
|
|
@@ -15682,13 +15859,13 @@ async function computerRecordStartCommand(path6, options) {
|
|
|
15682
15859
|
}
|
|
15683
15860
|
}
|
|
15684
15861
|
const target = resolvePath(path6);
|
|
15685
|
-
|
|
15862
|
+
mkdirSync3(dirname2(target), { recursive: true });
|
|
15686
15863
|
const fps = options.fps ? parseCoord(options.fps, "--fps") : 60;
|
|
15687
15864
|
const { width, height } = configuredDesktopDimensions();
|
|
15688
|
-
|
|
15865
|
+
mkdirSync3(STATE_DIR, { recursive: true });
|
|
15689
15866
|
const rawTarget = `${target}.raw-${Date.now()}.mp4`;
|
|
15690
|
-
|
|
15691
|
-
const child =
|
|
15867
|
+
rmSync3(RECORD_ACTIONS_FILE, { force: true });
|
|
15868
|
+
const child = spawn4("ffmpeg", [
|
|
15692
15869
|
"-y",
|
|
15693
15870
|
"-hide_banner",
|
|
15694
15871
|
"-loglevel",
|
|
@@ -15719,12 +15896,12 @@ async function computerRecordStartCommand(path6, options) {
|
|
|
15719
15896
|
], { detached: true, stdio: "ignore" });
|
|
15720
15897
|
child.unref();
|
|
15721
15898
|
if (!child.pid) fail("failed to launch ffmpeg");
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15899
|
+
writeFileSync3(RECORD_PID_FILE, String(child.pid));
|
|
15900
|
+
writeFileSync3(RECORD_PATH_FILE, target);
|
|
15901
|
+
writeFileSync3(RECORD_RAW_PATH_FILE, rawTarget);
|
|
15902
|
+
writeFileSync3(RECORD_STARTED_AT_FILE, String(Date.now()));
|
|
15903
|
+
writeFileSync3(RECORD_FPS_FILE, String(fps));
|
|
15904
|
+
writeFileSync3(RECORD_DIMENSIONS_FILE, JSON.stringify({ width, height }));
|
|
15728
15905
|
const startedAt = Date.now();
|
|
15729
15906
|
while (Date.now() - startedAt < 5e3) {
|
|
15730
15907
|
try {
|
|
@@ -15736,7 +15913,7 @@ async function computerRecordStartCommand(path6, options) {
|
|
|
15736
15913
|
} catch {
|
|
15737
15914
|
break;
|
|
15738
15915
|
}
|
|
15739
|
-
await
|
|
15916
|
+
await sleep2(100);
|
|
15740
15917
|
}
|
|
15741
15918
|
let alive = false;
|
|
15742
15919
|
try {
|
|
@@ -15746,13 +15923,13 @@ async function computerRecordStartCommand(path6, options) {
|
|
|
15746
15923
|
}
|
|
15747
15924
|
if (alive) fail("ffmpeg is running but did not produce recording output within 5 seconds; run `replicas computer record stop` to finalize or retry");
|
|
15748
15925
|
clearRecordingState();
|
|
15749
|
-
|
|
15926
|
+
rmSync3(rawTarget, { force: true });
|
|
15750
15927
|
fail("ffmpeg exited before screen recording became ready");
|
|
15751
15928
|
}
|
|
15752
15929
|
async function computerRecordStopCommand() {
|
|
15753
15930
|
if (!existsSync2(RECORD_PID_FILE) && !existsSync2(RECORD_PATH_FILE)) fail("no recording in progress");
|
|
15754
15931
|
if (existsSync2(RECORD_PID_FILE)) {
|
|
15755
|
-
const pid = parseInt(
|
|
15932
|
+
const pid = parseInt(readFileSync3(RECORD_PID_FILE, "utf8").trim(), 10);
|
|
15756
15933
|
if (!Number.isFinite(pid)) fail("invalid recording pidfile");
|
|
15757
15934
|
try {
|
|
15758
15935
|
process.kill(pid, "SIGINT");
|
|
@@ -15766,19 +15943,19 @@ async function computerRecordStopCommand() {
|
|
|
15766
15943
|
alive = false;
|
|
15767
15944
|
break;
|
|
15768
15945
|
}
|
|
15769
|
-
await
|
|
15946
|
+
await sleep2(200);
|
|
15770
15947
|
}
|
|
15771
15948
|
if (alive) fail(`ffmpeg did not finalize recording within 30 seconds (pid ${pid})`);
|
|
15772
15949
|
}
|
|
15773
15950
|
if (existsSync2(RECORD_PATH_FILE)) {
|
|
15774
|
-
const target =
|
|
15775
|
-
const rawPath = existsSync2(RECORD_RAW_PATH_FILE) ?
|
|
15776
|
-
const fps = existsSync2(RECORD_FPS_FILE) ? parseInt(
|
|
15951
|
+
const target = readFileSync3(RECORD_PATH_FILE, "utf8").trim();
|
|
15952
|
+
const rawPath = existsSync2(RECORD_RAW_PATH_FILE) ? readFileSync3(RECORD_RAW_PATH_FILE, "utf8").trim() : target;
|
|
15953
|
+
const fps = existsSync2(RECORD_FPS_FILE) ? parseInt(readFileSync3(RECORD_FPS_FILE, "utf8").trim(), 10) : 60;
|
|
15777
15954
|
const size = readRecordingDimensions();
|
|
15778
15955
|
const actions = readRecordingActions();
|
|
15779
15956
|
if (rawPath !== target) {
|
|
15780
15957
|
renderRecording(rawPath, target, actions, Number.isFinite(fps) ? fps : 60, size);
|
|
15781
|
-
|
|
15958
|
+
rmSync3(rawPath, { force: true });
|
|
15782
15959
|
}
|
|
15783
15960
|
console.log(target);
|
|
15784
15961
|
}
|
|
@@ -15809,7 +15986,7 @@ async function waitForDesktopViewerUrl(timeoutMs) {
|
|
|
15809
15986
|
while (Date.now() < deadline) {
|
|
15810
15987
|
const url = await lookupDesktopViewerUrl();
|
|
15811
15988
|
if (url) return url;
|
|
15812
|
-
await new Promise((
|
|
15989
|
+
await new Promise((resolve3) => setTimeout(resolve3, INFO_WAIT_INTERVAL_MS));
|
|
15813
15990
|
}
|
|
15814
15991
|
return await lookupDesktopViewerUrl();
|
|
15815
15992
|
}
|
|
@@ -15821,7 +15998,7 @@ async function computerInfoCommand() {
|
|
|
15821
15998
|
);
|
|
15822
15999
|
}
|
|
15823
16000
|
console.log(viewerUrl);
|
|
15824
|
-
console.error(
|
|
16001
|
+
console.error(chalk22.dim(`Share this URL with the user to let them watch the desktop live.`));
|
|
15825
16002
|
}
|
|
15826
16003
|
async function computerStatusCommand() {
|
|
15827
16004
|
ensureServicesRunning();
|
|
@@ -15831,18 +16008,18 @@ async function computerStatusCommand() {
|
|
|
15831
16008
|
const r = spawnSync3("pgrep", ["-af", p], { stdio: "pipe" });
|
|
15832
16009
|
const running = r.status === 0 && !!r.stdout?.toString().trim();
|
|
15833
16010
|
const suffix = p === "x11vnc" && bridge ? bridgeStatus(bridge.x11vnc, true) : p === "websockify" && bridge ? bridgeStatus(bridge.websockify, false, true) : "";
|
|
15834
|
-
console.log(` ${running ?
|
|
16011
|
+
console.log(` ${running ? chalk22.green("\u25CF") : chalk22.red("\u25CB")} ${p}${suffix}`);
|
|
15835
16012
|
}
|
|
15836
16013
|
const viewerUrl = await lookupDesktopViewerUrl();
|
|
15837
16014
|
if (viewerUrl) {
|
|
15838
|
-
console.log(` ${
|
|
16015
|
+
console.log(` ${chalk22.cyan("preview")}: ${viewerUrl}`);
|
|
15839
16016
|
} else {
|
|
15840
|
-
console.log(` ${
|
|
16017
|
+
console.log(` ${chalk22.dim("preview: not yet registered (engine registers it at startup)")}`);
|
|
15841
16018
|
}
|
|
15842
16019
|
}
|
|
15843
16020
|
var PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
15844
16021
|
function readPngDimensions(filePath) {
|
|
15845
|
-
const fd =
|
|
16022
|
+
const fd = openSync2(filePath, "r");
|
|
15846
16023
|
try {
|
|
15847
16024
|
const buf = Buffer.alloc(24);
|
|
15848
16025
|
const bytesRead = readSync(fd, buf, 0, 24, 0);
|
|
@@ -15851,7 +16028,7 @@ function readPngDimensions(filePath) {
|
|
|
15851
16028
|
}
|
|
15852
16029
|
return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
|
|
15853
16030
|
} finally {
|
|
15854
|
-
|
|
16031
|
+
closeSync2(fd);
|
|
15855
16032
|
}
|
|
15856
16033
|
}
|
|
15857
16034
|
function brandSvgPath() {
|
|
@@ -15865,7 +16042,7 @@ function loadBrandSvg(canvasW, canvasH) {
|
|
|
15865
16042
|
`Brand wallpaper SVG missing at ${path6}. The workspace image is out of date \u2014 \`desktop/brand-wallpaper.svg\` must be installed at $REPLICAS_DESKTOP_TEMPLATES.`
|
|
15866
16043
|
);
|
|
15867
16044
|
}
|
|
15868
|
-
return
|
|
16045
|
+
return readFileSync4(path6, "utf8").replace(/(<svg[^>]*\s)width="\d+"/, `$1width="${canvasW}"`).replace(/(<svg[^>]*\s)height="\d+"/, `$1height="${canvasH}"`);
|
|
15869
16046
|
}
|
|
15870
16047
|
var BRAND_PAD_FRACTION = 0.06;
|
|
15871
16048
|
var SCREENSHOT_CORNER_FRACTION = 0.022;
|
|
@@ -15900,7 +16077,7 @@ ${labels.join("\n")}
|
|
|
15900
16077
|
</svg>`;
|
|
15901
16078
|
}
|
|
15902
16079
|
function overlayGrid(rawPath, target, width, height, gridSize, gridPath) {
|
|
15903
|
-
|
|
16080
|
+
writeFileSync4(gridPath, buildGridSvg(width, height, gridSize));
|
|
15904
16081
|
const r = spawnSync3(
|
|
15905
16082
|
"ffmpeg",
|
|
15906
16083
|
[
|
|
@@ -15928,7 +16105,7 @@ function overlayGrid(rawPath, target, width, height, gridSize, gridPath) {
|
|
|
15928
16105
|
}
|
|
15929
16106
|
async function computerScreenshotCommand(path6, options = {}) {
|
|
15930
16107
|
const target = resolvePath(path6);
|
|
15931
|
-
|
|
16108
|
+
mkdirSync4(dirname3(target), { recursive: true });
|
|
15932
16109
|
const stamp = `${process.pid}-${Date.now()}`;
|
|
15933
16110
|
const rawPath = `/tmp/replicas-screenshot-${stamp}.raw.png`;
|
|
15934
16111
|
const svgPath = `/tmp/replicas-screenshot-${stamp}.brand.svg`;
|
|
@@ -15960,12 +16137,12 @@ async function computerScreenshotCommand(path6, options = {}) {
|
|
|
15960
16137
|
const shadowMargin = shadowSigma * 3;
|
|
15961
16138
|
const shadowW = width + shadowMargin * 2;
|
|
15962
16139
|
const shadowH = height + shadowMargin * 2;
|
|
15963
|
-
|
|
15964
|
-
|
|
16140
|
+
writeFileSync4(svgPath, loadBrandSvg(canvasW, canvasH));
|
|
16141
|
+
writeFileSync4(
|
|
15965
16142
|
maskPath,
|
|
15966
16143
|
SCREENSHOT_MASK_TEMPLATE.replace(/__W__/g, String(width)).replace(/__H__/g, String(height)).replace(/__R__/g, String(cornerR))
|
|
15967
16144
|
);
|
|
15968
|
-
|
|
16145
|
+
writeFileSync4(
|
|
15969
16146
|
shadowPath,
|
|
15970
16147
|
SHADOW_MASK_TEMPLATE.replace(/__SW__/g, String(shadowW)).replace(/__SH__/g, String(shadowH)).replace(/__M__/g, String(shadowMargin)).replace(/__W__/g, String(width)).replace(/__H__/g, String(height)).replace(/__R__/g, String(cornerR))
|
|
15971
16148
|
);
|
|
@@ -15998,16 +16175,16 @@ async function computerScreenshotCommand(path6, options = {}) {
|
|
|
15998
16175
|
fail(`ffmpeg branding failed: ${r.stderr?.toString().trim() || `exit ${r.status}`}`);
|
|
15999
16176
|
}
|
|
16000
16177
|
} finally {
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
|
|
16005
|
-
|
|
16178
|
+
rmSync4(rawPath, { force: true });
|
|
16179
|
+
rmSync4(svgPath, { force: true });
|
|
16180
|
+
rmSync4(maskPath, { force: true });
|
|
16181
|
+
rmSync4(shadowPath, { force: true });
|
|
16182
|
+
rmSync4(gridPath, { force: true });
|
|
16006
16183
|
}
|
|
16007
16184
|
console.log(target);
|
|
16008
16185
|
}
|
|
16009
16186
|
function hashFile(path6) {
|
|
16010
|
-
return createHash2("sha256").update(
|
|
16187
|
+
return createHash2("sha256").update(readFileSync4(path6)).digest("hex");
|
|
16011
16188
|
}
|
|
16012
16189
|
async function captureStableRawScreenshot(target, options) {
|
|
16013
16190
|
const start = Date.now();
|
|
@@ -16038,11 +16215,11 @@ async function captureStableRawScreenshot(target, options) {
|
|
|
16038
16215
|
if (frames > 1 && now - lastChangeAt >= options.stableMs) {
|
|
16039
16216
|
return { width, height, stable: true, elapsedMs: now - start, frames, changes };
|
|
16040
16217
|
}
|
|
16041
|
-
await
|
|
16218
|
+
await sleep2(options.pollMs);
|
|
16042
16219
|
}
|
|
16043
16220
|
return { width, height, stable: false, elapsedMs: Date.now() - start, frames, changes };
|
|
16044
16221
|
} finally {
|
|
16045
|
-
|
|
16222
|
+
rmSync4(framePath, { force: true });
|
|
16046
16223
|
}
|
|
16047
16224
|
}
|
|
16048
16225
|
function getActiveWindowTitle() {
|
|
@@ -16058,7 +16235,7 @@ function recordingMousePosition() {
|
|
|
16058
16235
|
}
|
|
16059
16236
|
async function computerObserveCommand(path6, options = {}) {
|
|
16060
16237
|
const target = resolvePath(path6);
|
|
16061
|
-
|
|
16238
|
+
mkdirSync4(dirname3(target), { recursive: true });
|
|
16062
16239
|
const timeoutMs = options.timeout ? parseCoord(options.timeout, "--timeout") : 3e3;
|
|
16063
16240
|
const stableMs = options.stableMs ? parseCoord(options.stableMs, "--stable-ms") : 600;
|
|
16064
16241
|
const pollMs = options.pollMs ? parseCoord(options.pollMs, "--poll-ms") : 200;
|
|
@@ -16092,8 +16269,8 @@ async function computerObserveCommand(path6, options = {}) {
|
|
|
16092
16269
|
gridSize
|
|
16093
16270
|
}, null, 2));
|
|
16094
16271
|
} finally {
|
|
16095
|
-
|
|
16096
|
-
|
|
16272
|
+
rmSync4(rawPath, { force: true });
|
|
16273
|
+
rmSync4(gridPath, { force: true });
|
|
16097
16274
|
}
|
|
16098
16275
|
}
|
|
16099
16276
|
async function fetchChromeJson(path6) {
|
|
@@ -16154,7 +16331,7 @@ async function sendChromeSessionCommand(session, method, params) {
|
|
|
16154
16331
|
return chromeResult(await session.send({ method, params }), method);
|
|
16155
16332
|
}
|
|
16156
16333
|
async function withChromeSession(webSocketDebuggerUrl, callback) {
|
|
16157
|
-
return await new Promise((
|
|
16334
|
+
return await new Promise((resolve3, reject) => {
|
|
16158
16335
|
const ws = new WebSocket(webSocketDebuggerUrl);
|
|
16159
16336
|
const pending = /* @__PURE__ */ new Map();
|
|
16160
16337
|
let nextId = 1;
|
|
@@ -16176,7 +16353,7 @@ async function withChromeSession(webSocketDebuggerUrl, callback) {
|
|
|
16176
16353
|
for (const request of pending.values()) clearTimeout(request.timeout);
|
|
16177
16354
|
pending.clear();
|
|
16178
16355
|
ws.close();
|
|
16179
|
-
|
|
16356
|
+
resolve3(value);
|
|
16180
16357
|
};
|
|
16181
16358
|
const session = {
|
|
16182
16359
|
send: ({ method, params }) => new Promise((resolveCommand, rejectCommand) => {
|
|
@@ -16293,7 +16470,7 @@ function browserStateProperties(node) {
|
|
|
16293
16470
|
function readBrowserStateCache(path6) {
|
|
16294
16471
|
let value;
|
|
16295
16472
|
try {
|
|
16296
|
-
value = JSON.parse(
|
|
16473
|
+
value = JSON.parse(readFileSync4(path6, "utf8"));
|
|
16297
16474
|
} catch {
|
|
16298
16475
|
return null;
|
|
16299
16476
|
}
|
|
@@ -16773,7 +16950,7 @@ async function waitForBrowserStability(page, options) {
|
|
|
16773
16950
|
}
|
|
16774
16951
|
} catch {
|
|
16775
16952
|
}
|
|
16776
|
-
await
|
|
16953
|
+
await sleep2(options.pollMs);
|
|
16777
16954
|
}
|
|
16778
16955
|
return { stable: false, elapsedMs: Date.now() - startedAt, samples, changes, state };
|
|
16779
16956
|
}
|
|
@@ -16819,7 +16996,7 @@ async function computerBrowserStateCommand(path6, options = {}) {
|
|
|
16819
16996
|
const page = await selectChromePage(options);
|
|
16820
16997
|
const stability = await waitForBrowserStability(page, { timeoutMs, stableMs, pollMs });
|
|
16821
16998
|
const target = resolvePath(path6);
|
|
16822
|
-
|
|
16999
|
+
mkdirSync4(dirname3(target), { recursive: true });
|
|
16823
17000
|
const [{ snapshot, entries }, screenshotResult] = await Promise.all([
|
|
16824
17001
|
captureBrowserSnapshot(page, { textLimit, elementLimit }),
|
|
16825
17002
|
sendChromeCommand(page.webSocketDebuggerUrl, "Page.captureScreenshot", {
|
|
@@ -16830,7 +17007,7 @@ async function computerBrowserStateCommand(path6, options = {}) {
|
|
|
16830
17007
|
]);
|
|
16831
17008
|
const data = screenshotResult.data;
|
|
16832
17009
|
if (typeof data !== "string") fail("Chrome did not return screenshot data");
|
|
16833
|
-
|
|
17010
|
+
writeFileSync4(target, Buffer.from(data, "base64"));
|
|
16834
17011
|
const screenshot = readPngDimensions(target);
|
|
16835
17012
|
const targetId = page.id ?? "unknown";
|
|
16836
17013
|
const cachePath = browserStateCachePath(targetId);
|
|
@@ -16846,8 +17023,8 @@ async function computerBrowserStateCommand(path6, options = {}) {
|
|
|
16846
17023
|
changes = { added: diff.added, changed: diff.changed, removed: diff.removed };
|
|
16847
17024
|
}
|
|
16848
17025
|
}
|
|
16849
|
-
|
|
16850
|
-
|
|
17026
|
+
mkdirSync4(STATE_DIR, { recursive: true });
|
|
17027
|
+
writeFileSync4(cachePath, JSON.stringify({ url: snapshot.url, documentId: snapshot.documentId, entries }));
|
|
16851
17028
|
const stableState = isRecord(stability.state) ? stability.state : {};
|
|
16852
17029
|
const state = {
|
|
16853
17030
|
title: snapshot.title,
|
|
@@ -17408,7 +17585,7 @@ async function computerBrowserWaitCommand(query, options = {}) {
|
|
|
17408
17585
|
console.log(JSON.stringify({ ok: true, elapsedMs: Date.now() - start, attempts, result: lastResult }, null, 2));
|
|
17409
17586
|
return;
|
|
17410
17587
|
}
|
|
17411
|
-
await
|
|
17588
|
+
await sleep2(pollMs);
|
|
17412
17589
|
}
|
|
17413
17590
|
console.log(JSON.stringify({ ok: false, elapsedMs: Date.now() - start, attempts, result: lastResult }, null, 2));
|
|
17414
17591
|
process.exitCode = 1;
|
|
@@ -17634,7 +17811,7 @@ async function computerBrowserBatchCommand(actionsJson, options = {}) {
|
|
|
17634
17811
|
attempts++;
|
|
17635
17812
|
result = await evaluateChromeSession(session, expression);
|
|
17636
17813
|
if (isRecord(result) && result.matched === true) break;
|
|
17637
|
-
await
|
|
17814
|
+
await sleep2(action.pollMs);
|
|
17638
17815
|
}
|
|
17639
17816
|
if (!isRecord(result) || result.matched !== true) fail(`Batch wait ${index} timed out after ${Date.now() - actionStartedAt}ms`);
|
|
17640
17817
|
completed.push({ index, action: action.action, attempts, elapsedMs: Date.now() - actionStartedAt });
|
|
@@ -17780,7 +17957,7 @@ async function computerLaunchCommand(app, args) {
|
|
|
17780
17957
|
} catch {
|
|
17781
17958
|
}
|
|
17782
17959
|
}
|
|
17783
|
-
const child =
|
|
17960
|
+
const child = spawn5(bin, fullArgs, {
|
|
17784
17961
|
env: withDisplay(),
|
|
17785
17962
|
detached: true,
|
|
17786
17963
|
stdio: "ignore"
|
|
@@ -17812,7 +17989,7 @@ async function computerLaunchCommand(app, args) {
|
|
|
17812
17989
|
} catch {
|
|
17813
17990
|
fail(`Chrome exited before its desktop control channel became ready.`);
|
|
17814
17991
|
}
|
|
17815
|
-
await
|
|
17992
|
+
await sleep2(100);
|
|
17816
17993
|
}
|
|
17817
17994
|
if (!readyPage?.webSocketDebuggerUrl) fail(`Chrome launched but its requested page was not controllable after 15 seconds.`);
|
|
17818
17995
|
await sendChromeCommand(readyPage.webSocketDebuggerUrl, "Page.bringToFront", {});
|
|
@@ -17823,7 +18000,7 @@ async function computerLaunchCommand(app, args) {
|
|
|
17823
18000
|
}
|
|
17824
18001
|
|
|
17825
18002
|
// src/commands/interactive.ts
|
|
17826
|
-
import
|
|
18003
|
+
import chalk23 from "chalk";
|
|
17827
18004
|
|
|
17828
18005
|
// src/interactive/index.tsx
|
|
17829
18006
|
import { createCliRenderer } from "@opentui/core";
|
|
@@ -17897,7 +18074,7 @@ function useReconnectingSseStream(options) {
|
|
|
17897
18074
|
while (!cancelled) {
|
|
17898
18075
|
const stop = await connect();
|
|
17899
18076
|
if (cancelled || stop) break;
|
|
17900
|
-
await new Promise((
|
|
18077
|
+
await new Promise((resolve3) => setTimeout(resolve3, reconnectDelayMs));
|
|
17901
18078
|
}
|
|
17902
18079
|
};
|
|
17903
18080
|
run().catch(() => setConnected(false));
|
|
@@ -21004,13 +21181,13 @@ async function interactiveCommand() {
|
|
|
21004
21181
|
'No organization selected. Please run "replicas org switch" to select an organization.'
|
|
21005
21182
|
);
|
|
21006
21183
|
}
|
|
21007
|
-
console.log(
|
|
21184
|
+
console.log(chalk23.gray("Starting interactive mode..."));
|
|
21008
21185
|
await launchInteractive();
|
|
21009
21186
|
}
|
|
21010
21187
|
|
|
21011
21188
|
// src/commands/environment.ts
|
|
21012
21189
|
import fs5 from "fs";
|
|
21013
|
-
import
|
|
21190
|
+
import chalk24 from "chalk";
|
|
21014
21191
|
import prompts5 from "prompts";
|
|
21015
21192
|
var UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
21016
21193
|
function maskValue(value) {
|
|
@@ -21023,38 +21200,38 @@ async function resolveEnvironmentId(input) {
|
|
|
21023
21200
|
const response = await orgAuthenticatedFetch("/v1/environments");
|
|
21024
21201
|
const resolved = resolveByNameOrId(input, response.environments);
|
|
21025
21202
|
if (!resolved) {
|
|
21026
|
-
console.log(
|
|
21203
|
+
console.log(chalk24.red(`Environment not found: ${input}`));
|
|
21027
21204
|
const available = response.environments.map((e) => e.name).join(", ");
|
|
21028
|
-
console.log(
|
|
21205
|
+
console.log(chalk24.gray(`Available: ${available || "(none)"}`));
|
|
21029
21206
|
process.exit(1);
|
|
21030
21207
|
}
|
|
21031
21208
|
return resolved.id;
|
|
21032
21209
|
}
|
|
21033
21210
|
function printEnvironment(env) {
|
|
21034
|
-
console.log(
|
|
21035
|
-
console.log(
|
|
21211
|
+
console.log(chalk24.white(` ${env.name}${env.is_global ? chalk24.gray(" (global)") : ""}`));
|
|
21212
|
+
console.log(chalk24.gray(` ID: ${env.id}`));
|
|
21036
21213
|
if (env.description) {
|
|
21037
|
-
console.log(
|
|
21214
|
+
console.log(chalk24.gray(` Description: ${env.description}`));
|
|
21038
21215
|
}
|
|
21039
21216
|
if (env.repository_id) {
|
|
21040
|
-
console.log(
|
|
21217
|
+
console.log(chalk24.gray(` Repository: ${env.repository_id}`));
|
|
21041
21218
|
} else if (env.repository_set_id) {
|
|
21042
|
-
console.log(
|
|
21219
|
+
console.log(chalk24.gray(` Repository Set: ${env.repository_set_id}`));
|
|
21043
21220
|
}
|
|
21044
21221
|
if (env.variable_count !== void 0) {
|
|
21045
|
-
console.log(
|
|
21222
|
+
console.log(chalk24.gray(` Variables: ${env.variable_count}, Files: ${env.file_count ?? 0}, Skills: ${env.skill_count ?? 0}, MCPs: ${env.mcp_count ?? 0}`));
|
|
21046
21223
|
}
|
|
21047
|
-
console.log(
|
|
21224
|
+
console.log(chalk24.gray(` Updated: ${formatDate2(env.updated_at)}`));
|
|
21048
21225
|
console.log();
|
|
21049
21226
|
}
|
|
21050
21227
|
async function environmentListCommand() {
|
|
21051
21228
|
ensureOrgApiAuthenticated();
|
|
21052
21229
|
const response = await orgAuthenticatedFetch("/v1/environments");
|
|
21053
21230
|
if (response.environments.length === 0) {
|
|
21054
|
-
console.log(
|
|
21231
|
+
console.log(chalk24.yellow("\nNo environments found.\n"));
|
|
21055
21232
|
return;
|
|
21056
21233
|
}
|
|
21057
|
-
console.log(
|
|
21234
|
+
console.log(chalk24.green(`
|
|
21058
21235
|
Environments (${response.environments.length}):
|
|
21059
21236
|
`));
|
|
21060
21237
|
for (const env of response.environments) {
|
|
@@ -21065,7 +21242,7 @@ async function environmentGetCommand(idOrName) {
|
|
|
21065
21242
|
ensureOrgApiAuthenticated();
|
|
21066
21243
|
const id = await resolveEnvironmentId(idOrName);
|
|
21067
21244
|
const response = await orgAuthenticatedFetch(`/v1/environments/${id}`);
|
|
21068
|
-
console.log(
|
|
21245
|
+
console.log(chalk24.green(`
|
|
21069
21246
|
Environment: ${response.environment.name}
|
|
21070
21247
|
`));
|
|
21071
21248
|
printEnvironment(response.environment);
|
|
@@ -21081,7 +21258,7 @@ async function environmentCreateCommand(name, options) {
|
|
|
21081
21258
|
validate: (v) => v.trim() ? true : "Name is required"
|
|
21082
21259
|
});
|
|
21083
21260
|
if (!r.name) {
|
|
21084
|
-
console.log(
|
|
21261
|
+
console.log(chalk24.yellow("\nCancelled."));
|
|
21085
21262
|
return;
|
|
21086
21263
|
}
|
|
21087
21264
|
envName = r.name;
|
|
@@ -21094,8 +21271,8 @@ async function environmentCreateCommand(name, options) {
|
|
|
21094
21271
|
const repos2 = await orgAuthenticatedFetch("/v1/repositories");
|
|
21095
21272
|
const repo = repos2.repositories.find((r) => r.name === options.repository);
|
|
21096
21273
|
if (!repo) {
|
|
21097
|
-
console.log(
|
|
21098
|
-
console.log(
|
|
21274
|
+
console.log(chalk24.red(`Repository not found: ${options.repository}`));
|
|
21275
|
+
console.log(chalk24.gray(`Available: ${repos2.repositories.map((r) => r.name).join(", ")}`));
|
|
21099
21276
|
process.exit(1);
|
|
21100
21277
|
}
|
|
21101
21278
|
repositoryId = repo.id;
|
|
@@ -21125,9 +21302,9 @@ async function environmentCreateCommand(name, options) {
|
|
|
21125
21302
|
method: "POST",
|
|
21126
21303
|
body
|
|
21127
21304
|
});
|
|
21128
|
-
console.log(
|
|
21305
|
+
console.log(chalk24.green(`
|
|
21129
21306
|
Created environment: ${response.environment.name}`));
|
|
21130
|
-
console.log(
|
|
21307
|
+
console.log(chalk24.gray(` ID: ${response.environment.id}
|
|
21131
21308
|
`));
|
|
21132
21309
|
}
|
|
21133
21310
|
async function environmentEditCommand(idOrName, options) {
|
|
@@ -21146,21 +21323,21 @@ async function environmentEditCommand(idOrName, options) {
|
|
|
21146
21323
|
const repos2 = await orgAuthenticatedFetch("/v1/repositories");
|
|
21147
21324
|
const repo = repos2.repositories.find((r) => r.name === options.repository);
|
|
21148
21325
|
if (!repo) {
|
|
21149
|
-
console.log(
|
|
21326
|
+
console.log(chalk24.red(`Repository not found: ${options.repository}`));
|
|
21150
21327
|
process.exit(1);
|
|
21151
21328
|
}
|
|
21152
21329
|
body.repository_id = repo.id;
|
|
21153
21330
|
}
|
|
21154
21331
|
}
|
|
21155
21332
|
if (Object.keys(body).length === 0) {
|
|
21156
|
-
console.log(
|
|
21333
|
+
console.log(chalk24.yellow("\nNo changes specified. Pass --name, --description, --repository, or --system-prompt."));
|
|
21157
21334
|
return;
|
|
21158
21335
|
}
|
|
21159
21336
|
const response = await orgAuthenticatedFetch(`/v1/environments/${id}`, {
|
|
21160
21337
|
method: "PATCH",
|
|
21161
21338
|
body
|
|
21162
21339
|
});
|
|
21163
|
-
console.log(
|
|
21340
|
+
console.log(chalk24.green(`
|
|
21164
21341
|
Updated environment: ${response.environment.name}
|
|
21165
21342
|
`));
|
|
21166
21343
|
}
|
|
@@ -21175,20 +21352,20 @@ async function environmentDeleteCommand(idOrName, options) {
|
|
|
21175
21352
|
initial: false
|
|
21176
21353
|
});
|
|
21177
21354
|
if (!r.confirm) {
|
|
21178
|
-
console.log(
|
|
21355
|
+
console.log(chalk24.yellow("\nCancelled."));
|
|
21179
21356
|
return;
|
|
21180
21357
|
}
|
|
21181
21358
|
}
|
|
21182
21359
|
await orgAuthenticatedFetch(`/v1/environments/${id}`, { method: "DELETE" });
|
|
21183
|
-
console.log(
|
|
21360
|
+
console.log(chalk24.green(`
|
|
21184
21361
|
Deleted environment ${idOrName}.
|
|
21185
21362
|
`));
|
|
21186
21363
|
}
|
|
21187
21364
|
function printVariable(v, reveal) {
|
|
21188
|
-
console.log(
|
|
21189
|
-
console.log(
|
|
21190
|
-
console.log(
|
|
21191
|
-
console.log(
|
|
21365
|
+
console.log(chalk24.white(` ${v.key}`));
|
|
21366
|
+
console.log(chalk24.gray(` ID: ${v.id}`));
|
|
21367
|
+
console.log(chalk24.gray(` Value: ${reveal ? v.value : maskValue(v.value)}`));
|
|
21368
|
+
console.log(chalk24.gray(` Updated: ${formatDate2(v.updated_at)}`));
|
|
21192
21369
|
console.log();
|
|
21193
21370
|
}
|
|
21194
21371
|
async function envVarsListCommand(envIdOrName, options) {
|
|
@@ -21198,14 +21375,14 @@ async function envVarsListCommand(envIdOrName, options) {
|
|
|
21198
21375
|
`/v1/environments/${id}/variables`
|
|
21199
21376
|
);
|
|
21200
21377
|
if (response.environment_variables.length === 0) {
|
|
21201
|
-
console.log(
|
|
21378
|
+
console.log(chalk24.yellow("\nNo variables.\n"));
|
|
21202
21379
|
return;
|
|
21203
21380
|
}
|
|
21204
|
-
console.log(
|
|
21381
|
+
console.log(chalk24.green(`
|
|
21205
21382
|
Variables (${response.environment_variables.length}):
|
|
21206
21383
|
`));
|
|
21207
21384
|
if (!options.reveal) {
|
|
21208
|
-
console.log(
|
|
21385
|
+
console.log(chalk24.gray(" Values are masked. Pass --reveal to show full values.\n"));
|
|
21209
21386
|
}
|
|
21210
21387
|
for (const v of response.environment_variables) printVariable(v, !!options.reveal);
|
|
21211
21388
|
}
|
|
@@ -21222,7 +21399,7 @@ async function envVarsSetCommand(envIdOrName, key, value) {
|
|
|
21222
21399
|
`/v1/environments/${id}/variables/${match.id}`,
|
|
21223
21400
|
{ method: "PATCH", body: body2 }
|
|
21224
21401
|
);
|
|
21225
|
-
console.log(
|
|
21402
|
+
console.log(chalk24.green(`
|
|
21226
21403
|
Updated variable ${response2.environment_variable.key}.
|
|
21227
21404
|
`));
|
|
21228
21405
|
return;
|
|
@@ -21236,7 +21413,7 @@ Updated variable ${response2.environment_variable.key}.
|
|
|
21236
21413
|
`/v1/environments/${id}/variables`,
|
|
21237
21414
|
{ method: "POST", body }
|
|
21238
21415
|
);
|
|
21239
|
-
console.log(
|
|
21416
|
+
console.log(chalk24.green(`
|
|
21240
21417
|
Created variable ${response.environment_variable.key}.
|
|
21241
21418
|
`));
|
|
21242
21419
|
}
|
|
@@ -21250,7 +21427,7 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
|
|
|
21250
21427
|
);
|
|
21251
21428
|
const match = existing.environment_variables.find((v) => v.key === keyOrId);
|
|
21252
21429
|
if (!match) {
|
|
21253
|
-
console.log(
|
|
21430
|
+
console.log(chalk24.red(`Variable not found: ${keyOrId}`));
|
|
21254
21431
|
process.exit(1);
|
|
21255
21432
|
}
|
|
21256
21433
|
variableId = match.id;
|
|
@@ -21263,23 +21440,23 @@ async function envVarsDeleteCommand(envIdOrName, keyOrId, options) {
|
|
|
21263
21440
|
initial: false
|
|
21264
21441
|
});
|
|
21265
21442
|
if (!r.confirm) {
|
|
21266
|
-
console.log(
|
|
21443
|
+
console.log(chalk24.yellow("\nCancelled."));
|
|
21267
21444
|
return;
|
|
21268
21445
|
}
|
|
21269
21446
|
}
|
|
21270
21447
|
await orgAuthenticatedFetch(`/v1/environments/${id}/variables/${variableId}`, {
|
|
21271
21448
|
method: "DELETE"
|
|
21272
21449
|
});
|
|
21273
|
-
console.log(
|
|
21450
|
+
console.log(chalk24.green(`
|
|
21274
21451
|
Deleted variable ${keyOrId}.
|
|
21275
21452
|
`));
|
|
21276
21453
|
}
|
|
21277
21454
|
function printFile(f) {
|
|
21278
|
-
console.log(
|
|
21279
|
-
console.log(
|
|
21280
|
-
console.log(
|
|
21281
|
-
console.log(
|
|
21282
|
-
console.log(
|
|
21455
|
+
console.log(chalk24.white(` ${f.path}`));
|
|
21456
|
+
console.log(chalk24.gray(` ID: ${f.id}`));
|
|
21457
|
+
console.log(chalk24.gray(` Name: ${f.name}`));
|
|
21458
|
+
console.log(chalk24.gray(` Size: ${f.content.length} bytes`));
|
|
21459
|
+
console.log(chalk24.gray(` Updated: ${formatDate2(f.updated_at)}`));
|
|
21283
21460
|
console.log();
|
|
21284
21461
|
}
|
|
21285
21462
|
async function envFilesListCommand(envIdOrName) {
|
|
@@ -21289,10 +21466,10 @@ async function envFilesListCommand(envIdOrName) {
|
|
|
21289
21466
|
`/v1/environments/${id}/files`
|
|
21290
21467
|
);
|
|
21291
21468
|
if (response.environment_files.length === 0) {
|
|
21292
|
-
console.log(
|
|
21469
|
+
console.log(chalk24.yellow("\nNo files.\n"));
|
|
21293
21470
|
return;
|
|
21294
21471
|
}
|
|
21295
|
-
console.log(
|
|
21472
|
+
console.log(chalk24.green(`
|
|
21296
21473
|
Files (${response.environment_files.length}):
|
|
21297
21474
|
`));
|
|
21298
21475
|
for (const f of response.environment_files) printFile(f);
|
|
@@ -21323,7 +21500,7 @@ async function envFilesSetCommand(envIdOrName, destinationPath, options) {
|
|
|
21323
21500
|
`/v1/environments/${id}/files/${match.id}`,
|
|
21324
21501
|
{ method: "PATCH", body: body2 }
|
|
21325
21502
|
);
|
|
21326
|
-
console.log(
|
|
21503
|
+
console.log(chalk24.green(`
|
|
21327
21504
|
Updated file ${response2.environment_file.path}.
|
|
21328
21505
|
`));
|
|
21329
21506
|
return;
|
|
@@ -21338,7 +21515,7 @@ Updated file ${response2.environment_file.path}.
|
|
|
21338
21515
|
`/v1/environments/${id}/files`,
|
|
21339
21516
|
{ method: "POST", body }
|
|
21340
21517
|
);
|
|
21341
|
-
console.log(
|
|
21518
|
+
console.log(chalk24.green(`
|
|
21342
21519
|
Created file ${response.environment_file.path}.
|
|
21343
21520
|
`));
|
|
21344
21521
|
}
|
|
@@ -21352,7 +21529,7 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
|
|
|
21352
21529
|
);
|
|
21353
21530
|
const match = existing.environment_files.find((f) => f.path === pathOrId);
|
|
21354
21531
|
if (!match) {
|
|
21355
|
-
console.log(
|
|
21532
|
+
console.log(chalk24.red(`File not found: ${pathOrId}`));
|
|
21356
21533
|
process.exit(1);
|
|
21357
21534
|
}
|
|
21358
21535
|
fileId = match.id;
|
|
@@ -21365,14 +21542,14 @@ async function envFilesDeleteCommand(envIdOrName, pathOrId, options) {
|
|
|
21365
21542
|
initial: false
|
|
21366
21543
|
});
|
|
21367
21544
|
if (!r.confirm) {
|
|
21368
|
-
console.log(
|
|
21545
|
+
console.log(chalk24.yellow("\nCancelled."));
|
|
21369
21546
|
return;
|
|
21370
21547
|
}
|
|
21371
21548
|
}
|
|
21372
21549
|
await orgAuthenticatedFetch(`/v1/environments/${id}/files/${fileId}`, {
|
|
21373
21550
|
method: "DELETE"
|
|
21374
21551
|
});
|
|
21375
|
-
console.log(
|
|
21552
|
+
console.log(chalk24.green(`
|
|
21376
21553
|
Deleted file ${pathOrId}.
|
|
21377
21554
|
`));
|
|
21378
21555
|
}
|
|
@@ -21383,15 +21560,15 @@ async function envStartHookGetCommand(envIdOrName) {
|
|
|
21383
21560
|
`/v1/environments/${id}/start-hooks`
|
|
21384
21561
|
);
|
|
21385
21562
|
if (!response.start_hook) {
|
|
21386
|
-
console.log(
|
|
21563
|
+
console.log(chalk24.yellow("\nNo start hook configured.\n"));
|
|
21387
21564
|
return;
|
|
21388
21565
|
}
|
|
21389
21566
|
const hook = response.start_hook;
|
|
21390
|
-
console.log(
|
|
21567
|
+
console.log(chalk24.green(`
|
|
21391
21568
|
Start hook (v${hook.version}, ${hook.is_active ? "active" : "inactive"}):
|
|
21392
21569
|
`));
|
|
21393
|
-
console.log(
|
|
21394
|
-
console.log(
|
|
21570
|
+
console.log(chalk24.gray(` ID: ${hook.id}`));
|
|
21571
|
+
console.log(chalk24.gray(` Created: ${formatDate2(hook.created_at)}
|
|
21395
21572
|
`));
|
|
21396
21573
|
console.log(hook.content);
|
|
21397
21574
|
console.log();
|
|
@@ -21406,10 +21583,10 @@ async function envStartHookSaveCommand(envIdOrName, options) {
|
|
|
21406
21583
|
{ method: "POST", body }
|
|
21407
21584
|
);
|
|
21408
21585
|
if (!response.start_hook) {
|
|
21409
|
-
console.log(
|
|
21586
|
+
console.log(chalk24.green("\nCleared start hook.\n"));
|
|
21410
21587
|
return;
|
|
21411
21588
|
}
|
|
21412
|
-
console.log(
|
|
21589
|
+
console.log(chalk24.green(`
|
|
21413
21590
|
Saved start hook v${response.start_hook.version}.
|
|
21414
21591
|
`));
|
|
21415
21592
|
}
|
|
@@ -21426,7 +21603,7 @@ async function envStartHookTestCommand(envIdOrName, options) {
|
|
|
21426
21603
|
body: { content },
|
|
21427
21604
|
onEvent: (event) => {
|
|
21428
21605
|
if (event.type === "progress" && event.message) {
|
|
21429
|
-
console.log(
|
|
21606
|
+
console.log(chalk24.gray(event.message));
|
|
21430
21607
|
} else if (event.type === "output" && event.output) {
|
|
21431
21608
|
process.stdout.write(event.output);
|
|
21432
21609
|
} else if (event.type === "complete") {
|
|
@@ -21439,21 +21616,21 @@ async function envStartHookTestCommand(envIdOrName, options) {
|
|
|
21439
21616
|
}
|
|
21440
21617
|
);
|
|
21441
21618
|
if (errorMessage) {
|
|
21442
|
-
console.log(
|
|
21619
|
+
console.log(chalk24.red(`
|
|
21443
21620
|
${errorMessage}
|
|
21444
21621
|
`));
|
|
21445
21622
|
process.exit(1);
|
|
21446
21623
|
}
|
|
21447
21624
|
if (timedOut) {
|
|
21448
|
-
console.log(
|
|
21625
|
+
console.log(chalk24.yellow("\nStart hook timed out.\n"));
|
|
21449
21626
|
process.exit(1);
|
|
21450
21627
|
}
|
|
21451
21628
|
if (exitCode === 0) {
|
|
21452
|
-
console.log(
|
|
21629
|
+
console.log(chalk24.green(`
|
|
21453
21630
|
Start hook passed (exit code ${exitCode}).
|
|
21454
21631
|
`));
|
|
21455
21632
|
} else {
|
|
21456
|
-
console.log(
|
|
21633
|
+
console.log(chalk24.red(`
|
|
21457
21634
|
Start hook failed (exit code ${exitCode ?? "unknown"}).
|
|
21458
21635
|
`));
|
|
21459
21636
|
process.exit(1);
|
|
@@ -21466,24 +21643,24 @@ async function envStartHookRepositoryHooksCommand(envIdOrName) {
|
|
|
21466
21643
|
`/v1/environments/${id}/start-hooks/repository-hooks`
|
|
21467
21644
|
);
|
|
21468
21645
|
if (response.repositories.length === 0) {
|
|
21469
|
-
console.log(
|
|
21646
|
+
console.log(chalk24.yellow("\nNo repositories bound to this environment.\n"));
|
|
21470
21647
|
return;
|
|
21471
21648
|
}
|
|
21472
|
-
console.log(
|
|
21649
|
+
console.log(chalk24.green(`
|
|
21473
21650
|
Repository start hooks (${response.repositories.length}):
|
|
21474
21651
|
`));
|
|
21475
21652
|
for (const repo of response.repositories) {
|
|
21476
|
-
console.log(
|
|
21653
|
+
console.log(chalk24.white(` ${repo.repository_name} @${repo.default_branch}`));
|
|
21477
21654
|
if (repo.error) {
|
|
21478
|
-
console.log(
|
|
21655
|
+
console.log(chalk24.red(` Error: ${repo.error}`));
|
|
21479
21656
|
} else if (repo.start_hook) {
|
|
21480
|
-
console.log(
|
|
21481
|
-
console.log(
|
|
21657
|
+
console.log(chalk24.gray(` Source: ${repo.filename ?? "(unknown)"}`));
|
|
21658
|
+
console.log(chalk24.gray(` Commands (${repo.start_hook.commands.length}):`));
|
|
21482
21659
|
for (const cmd of repo.start_hook.commands) {
|
|
21483
|
-
console.log(
|
|
21660
|
+
console.log(chalk24.gray(` ${cmd}`));
|
|
21484
21661
|
}
|
|
21485
21662
|
} else {
|
|
21486
|
-
console.log(
|
|
21663
|
+
console.log(chalk24.gray(` No startHook defined.`));
|
|
21487
21664
|
}
|
|
21488
21665
|
console.log();
|
|
21489
21666
|
}
|
|
@@ -21505,7 +21682,7 @@ function registerSlackCommands(parent) {
|
|
|
21505
21682
|
await slackThreadAttachCommand(options);
|
|
21506
21683
|
} catch (error) {
|
|
21507
21684
|
if (error instanceof Error) {
|
|
21508
|
-
console.error(
|
|
21685
|
+
console.error(chalk25.red(`
|
|
21509
21686
|
\u2717 ${error.message}
|
|
21510
21687
|
`));
|
|
21511
21688
|
}
|
|
@@ -21517,7 +21694,7 @@ function registerSlackCommands(parent) {
|
|
|
21517
21694
|
await slackThreadSwitchCommand(workspace, options);
|
|
21518
21695
|
} catch (error) {
|
|
21519
21696
|
if (error instanceof Error) {
|
|
21520
|
-
console.error(
|
|
21697
|
+
console.error(chalk25.red(`
|
|
21521
21698
|
\u2717 ${error.message}
|
|
21522
21699
|
`));
|
|
21523
21700
|
}
|
|
@@ -21531,7 +21708,7 @@ program.command("login").description("Authenticate with your Replicas account").
|
|
|
21531
21708
|
await loginCommand();
|
|
21532
21709
|
} catch (error) {
|
|
21533
21710
|
if (error instanceof Error) {
|
|
21534
|
-
console.error(
|
|
21711
|
+
console.error(chalk25.red(`
|
|
21535
21712
|
\u2717 ${error.message}
|
|
21536
21713
|
`));
|
|
21537
21714
|
}
|
|
@@ -21543,7 +21720,7 @@ program.command("init").description("Create a replicas.json or replicas.yaml con
|
|
|
21543
21720
|
initCommand(options);
|
|
21544
21721
|
} catch (error) {
|
|
21545
21722
|
if (error instanceof Error) {
|
|
21546
|
-
console.error(
|
|
21723
|
+
console.error(chalk25.red(`
|
|
21547
21724
|
\u2717 ${error.message}
|
|
21548
21725
|
`));
|
|
21549
21726
|
}
|
|
@@ -21555,7 +21732,7 @@ program.command("logout").description("Clear stored credentials").action(() => {
|
|
|
21555
21732
|
logoutCommand();
|
|
21556
21733
|
} catch (error) {
|
|
21557
21734
|
if (error instanceof Error) {
|
|
21558
|
-
console.error(
|
|
21735
|
+
console.error(chalk25.red(`
|
|
21559
21736
|
\u2717 ${error.message}
|
|
21560
21737
|
`));
|
|
21561
21738
|
}
|
|
@@ -21567,7 +21744,7 @@ program.command("whoami").description("Display current authenticated user").acti
|
|
|
21567
21744
|
await whoamiCommand();
|
|
21568
21745
|
} catch (error) {
|
|
21569
21746
|
if (error instanceof Error) {
|
|
21570
|
-
console.error(
|
|
21747
|
+
console.error(chalk25.red(`
|
|
21571
21748
|
\u2717 ${error.message}
|
|
21572
21749
|
`));
|
|
21573
21750
|
}
|
|
@@ -21579,7 +21756,7 @@ program.command("codex-auth").description("Authenticate Replicas with your Codex
|
|
|
21579
21756
|
await codexAuthCommand(options);
|
|
21580
21757
|
} catch (error) {
|
|
21581
21758
|
if (error instanceof Error) {
|
|
21582
|
-
console.error(
|
|
21759
|
+
console.error(chalk25.red(`
|
|
21583
21760
|
\u2717 ${error.message}
|
|
21584
21761
|
`));
|
|
21585
21762
|
}
|
|
@@ -21591,7 +21768,7 @@ program.command("claude-auth").description("Authenticate Replicas with your Clau
|
|
|
21591
21768
|
await claudeAuthCommand(options);
|
|
21592
21769
|
} catch (error) {
|
|
21593
21770
|
if (error instanceof Error) {
|
|
21594
|
-
console.error(
|
|
21771
|
+
console.error(chalk25.red(`
|
|
21595
21772
|
\u2717 ${error.message}
|
|
21596
21773
|
`));
|
|
21597
21774
|
}
|
|
@@ -21604,7 +21781,7 @@ org.command("switch").description("Switch to a different organization").action(a
|
|
|
21604
21781
|
await orgSwitchCommand();
|
|
21605
21782
|
} catch (error) {
|
|
21606
21783
|
if (error instanceof Error) {
|
|
21607
|
-
console.error(
|
|
21784
|
+
console.error(chalk25.red(`
|
|
21608
21785
|
\u2717 ${error.message}
|
|
21609
21786
|
`));
|
|
21610
21787
|
}
|
|
@@ -21616,7 +21793,7 @@ org.action(async () => {
|
|
|
21616
21793
|
await orgCommand();
|
|
21617
21794
|
} catch (error) {
|
|
21618
21795
|
if (error instanceof Error) {
|
|
21619
|
-
console.error(
|
|
21796
|
+
console.error(chalk25.red(`
|
|
21620
21797
|
\u2717 ${error.message}
|
|
21621
21798
|
`));
|
|
21622
21799
|
}
|
|
@@ -21628,7 +21805,7 @@ program.command("connect <workspace-name>").description("Connect to a workspace
|
|
|
21628
21805
|
await connectCommand(workspaceName);
|
|
21629
21806
|
} catch (error) {
|
|
21630
21807
|
if (error instanceof Error) {
|
|
21631
|
-
console.error(
|
|
21808
|
+
console.error(chalk25.red(`
|
|
21632
21809
|
\u2717 ${error.message}
|
|
21633
21810
|
`));
|
|
21634
21811
|
}
|
|
@@ -21640,7 +21817,7 @@ program.command("code <workspace-name>").description("Open a workspace in VSCode
|
|
|
21640
21817
|
await codeCommand(workspaceName);
|
|
21641
21818
|
} catch (error) {
|
|
21642
21819
|
if (error instanceof Error) {
|
|
21643
|
-
console.error(
|
|
21820
|
+
console.error(chalk25.red(`
|
|
21644
21821
|
\u2717 ${error.message}
|
|
21645
21822
|
`));
|
|
21646
21823
|
}
|
|
@@ -21653,7 +21830,7 @@ config.command("get <key>").description("Get a configuration value").action(asyn
|
|
|
21653
21830
|
await configGetCommand(key);
|
|
21654
21831
|
} catch (error) {
|
|
21655
21832
|
if (error instanceof Error) {
|
|
21656
|
-
console.error(
|
|
21833
|
+
console.error(chalk25.red(`
|
|
21657
21834
|
\u2717 ${error.message}
|
|
21658
21835
|
`));
|
|
21659
21836
|
}
|
|
@@ -21665,7 +21842,7 @@ config.command("set <key> <value>").description("Set a configuration value").act
|
|
|
21665
21842
|
await configSetCommand(key, value);
|
|
21666
21843
|
} catch (error) {
|
|
21667
21844
|
if (error instanceof Error) {
|
|
21668
|
-
console.error(
|
|
21845
|
+
console.error(chalk25.red(`
|
|
21669
21846
|
\u2717 ${error.message}
|
|
21670
21847
|
`));
|
|
21671
21848
|
}
|
|
@@ -21677,7 +21854,7 @@ config.command("list").description("List all configuration values").action(async
|
|
|
21677
21854
|
await configListCommand();
|
|
21678
21855
|
} catch (error) {
|
|
21679
21856
|
if (error instanceof Error) {
|
|
21680
|
-
console.error(
|
|
21857
|
+
console.error(chalk25.red(`
|
|
21681
21858
|
\u2717 ${error.message}
|
|
21682
21859
|
`));
|
|
21683
21860
|
}
|
|
@@ -21689,7 +21866,7 @@ program.command("list").description("List all replicas").option("-p, --page <pag
|
|
|
21689
21866
|
await replicaListCommand(options);
|
|
21690
21867
|
} catch (error) {
|
|
21691
21868
|
if (error instanceof Error) {
|
|
21692
|
-
console.error(
|
|
21869
|
+
console.error(chalk25.red(`
|
|
21693
21870
|
\u2717 ${error.message}
|
|
21694
21871
|
`));
|
|
21695
21872
|
}
|
|
@@ -21701,7 +21878,7 @@ program.command("get <id>").description("Get replica details by ID").action(asyn
|
|
|
21701
21878
|
await replicaGetCommand(id);
|
|
21702
21879
|
} catch (error) {
|
|
21703
21880
|
if (error instanceof Error) {
|
|
21704
|
-
console.error(
|
|
21881
|
+
console.error(chalk25.red(`
|
|
21705
21882
|
\u2717 ${error.message}
|
|
21706
21883
|
`));
|
|
21707
21884
|
}
|
|
@@ -21713,7 +21890,7 @@ program.command("create [name]").description("Create a new replica").option("-m,
|
|
|
21713
21890
|
await replicaCreateCommand(name, options);
|
|
21714
21891
|
} catch (error) {
|
|
21715
21892
|
if (error instanceof Error) {
|
|
21716
|
-
console.error(
|
|
21893
|
+
console.error(chalk25.red(`
|
|
21717
21894
|
\u2717 ${error.message}
|
|
21718
21895
|
`));
|
|
21719
21896
|
}
|
|
@@ -21725,7 +21902,7 @@ program.command("send <id>").description("Send a message to a replica").option("
|
|
|
21725
21902
|
await replicaSendCommand(id, options);
|
|
21726
21903
|
} catch (error) {
|
|
21727
21904
|
if (error instanceof Error) {
|
|
21728
|
-
console.error(
|
|
21905
|
+
console.error(chalk25.red(`
|
|
21729
21906
|
\u2717 ${error.message}
|
|
21730
21907
|
`));
|
|
21731
21908
|
}
|
|
@@ -21737,7 +21914,7 @@ program.command("delete <id>").description("Delete a replica").option("-f, --for
|
|
|
21737
21914
|
await replicaDeleteCommand(id, options);
|
|
21738
21915
|
} catch (error) {
|
|
21739
21916
|
if (error instanceof Error) {
|
|
21740
|
-
console.error(
|
|
21917
|
+
console.error(chalk25.red(`
|
|
21741
21918
|
\u2717 ${error.message}
|
|
21742
21919
|
`));
|
|
21743
21920
|
}
|
|
@@ -21749,7 +21926,7 @@ program.command("read <id>").description("Read conversation history of a replica
|
|
|
21749
21926
|
await replicaReadCommand(id, options);
|
|
21750
21927
|
} catch (error) {
|
|
21751
21928
|
if (error instanceof Error) {
|
|
21752
|
-
console.error(
|
|
21929
|
+
console.error(chalk25.red(`
|
|
21753
21930
|
\u2717 ${error.message}
|
|
21754
21931
|
`));
|
|
21755
21932
|
}
|
|
@@ -21762,7 +21939,7 @@ automation.command("list").description("List all automations").option("-p, --pag
|
|
|
21762
21939
|
await automationListCommand(options);
|
|
21763
21940
|
} catch (error) {
|
|
21764
21941
|
if (error instanceof Error) {
|
|
21765
|
-
console.error(
|
|
21942
|
+
console.error(chalk25.red(`
|
|
21766
21943
|
\u2717 ${error.message}
|
|
21767
21944
|
`));
|
|
21768
21945
|
}
|
|
@@ -21774,7 +21951,7 @@ automation.command("get <id>").description("Get automation details by ID").actio
|
|
|
21774
21951
|
await automationGetCommand(id);
|
|
21775
21952
|
} catch (error) {
|
|
21776
21953
|
if (error instanceof Error) {
|
|
21777
|
-
console.error(
|
|
21954
|
+
console.error(chalk25.red(`
|
|
21778
21955
|
\u2717 ${error.message}
|
|
21779
21956
|
`));
|
|
21780
21957
|
}
|
|
@@ -21789,7 +21966,7 @@ automation.command("create [name]").description("Create a new automation").optio
|
|
|
21789
21966
|
});
|
|
21790
21967
|
} catch (error) {
|
|
21791
21968
|
if (error instanceof Error) {
|
|
21792
|
-
console.error(
|
|
21969
|
+
console.error(chalk25.red(`
|
|
21793
21970
|
\u2717 ${error.message}
|
|
21794
21971
|
`));
|
|
21795
21972
|
}
|
|
@@ -21801,7 +21978,7 @@ automation.command("edit <id>").description("Edit an existing automation").optio
|
|
|
21801
21978
|
await automationEditCommand(id, options);
|
|
21802
21979
|
} catch (error) {
|
|
21803
21980
|
if (error instanceof Error) {
|
|
21804
|
-
console.error(
|
|
21981
|
+
console.error(chalk25.red(`
|
|
21805
21982
|
\u2717 ${error.message}
|
|
21806
21983
|
`));
|
|
21807
21984
|
}
|
|
@@ -21813,7 +21990,7 @@ automation.command("run <id>").description("Manually trigger an automation (cron
|
|
|
21813
21990
|
await automationRunCommand(id);
|
|
21814
21991
|
} catch (error) {
|
|
21815
21992
|
if (error instanceof Error) {
|
|
21816
|
-
console.error(
|
|
21993
|
+
console.error(chalk25.red(`
|
|
21817
21994
|
\u2717 ${error.message}
|
|
21818
21995
|
`));
|
|
21819
21996
|
}
|
|
@@ -21825,7 +22002,7 @@ automation.command("delete <id>").description("Delete an automation").option("-f
|
|
|
21825
22002
|
await automationDeleteCommand(id, options);
|
|
21826
22003
|
} catch (error) {
|
|
21827
22004
|
if (error instanceof Error) {
|
|
21828
|
-
console.error(
|
|
22005
|
+
console.error(chalk25.red(`
|
|
21829
22006
|
\u2717 ${error.message}
|
|
21830
22007
|
`));
|
|
21831
22008
|
}
|
|
@@ -21837,7 +22014,7 @@ automation.action(async () => {
|
|
|
21837
22014
|
await automationListCommand({});
|
|
21838
22015
|
} catch (error) {
|
|
21839
22016
|
if (error instanceof Error) {
|
|
21840
|
-
console.error(
|
|
22017
|
+
console.error(chalk25.red(`
|
|
21841
22018
|
\u2717 ${error.message}
|
|
21842
22019
|
`));
|
|
21843
22020
|
}
|
|
@@ -21850,7 +22027,7 @@ repos.command("list").description("List all repositories").action(async () => {
|
|
|
21850
22027
|
await repositoriesListCommand();
|
|
21851
22028
|
} catch (error) {
|
|
21852
22029
|
if (error instanceof Error) {
|
|
21853
|
-
console.error(
|
|
22030
|
+
console.error(chalk25.red(`
|
|
21854
22031
|
\u2717 ${error.message}
|
|
21855
22032
|
`));
|
|
21856
22033
|
}
|
|
@@ -21862,7 +22039,7 @@ repos.action(async () => {
|
|
|
21862
22039
|
await repositoriesListCommand();
|
|
21863
22040
|
} catch (error) {
|
|
21864
22041
|
if (error instanceof Error) {
|
|
21865
|
-
console.error(
|
|
22042
|
+
console.error(chalk25.red(`
|
|
21866
22043
|
\u2717 ${error.message}
|
|
21867
22044
|
`));
|
|
21868
22045
|
}
|
|
@@ -21875,7 +22052,7 @@ environment.command("list").description("List all environments").action(async ()
|
|
|
21875
22052
|
await environmentListCommand();
|
|
21876
22053
|
} catch (error) {
|
|
21877
22054
|
if (error instanceof Error) {
|
|
21878
|
-
console.error(
|
|
22055
|
+
console.error(chalk25.red(`
|
|
21879
22056
|
\u2717 ${error.message}
|
|
21880
22057
|
`));
|
|
21881
22058
|
}
|
|
@@ -21887,7 +22064,7 @@ environment.command("get <id-or-name>").description('Get an environment by ID or
|
|
|
21887
22064
|
await environmentGetCommand(idOrName);
|
|
21888
22065
|
} catch (error) {
|
|
21889
22066
|
if (error instanceof Error) {
|
|
21890
|
-
console.error(
|
|
22067
|
+
console.error(chalk25.red(`
|
|
21891
22068
|
\u2717 ${error.message}
|
|
21892
22069
|
`));
|
|
21893
22070
|
}
|
|
@@ -21899,7 +22076,7 @@ environment.command("create [name]").description("Create a new environment").opt
|
|
|
21899
22076
|
await environmentCreateCommand(name, options);
|
|
21900
22077
|
} catch (error) {
|
|
21901
22078
|
if (error instanceof Error) {
|
|
21902
|
-
console.error(
|
|
22079
|
+
console.error(chalk25.red(`
|
|
21903
22080
|
\u2717 ${error.message}
|
|
21904
22081
|
`));
|
|
21905
22082
|
}
|
|
@@ -21911,7 +22088,7 @@ environment.command("edit <id-or-name>").description("Edit an environment").opti
|
|
|
21911
22088
|
await environmentEditCommand(idOrName, options);
|
|
21912
22089
|
} catch (error) {
|
|
21913
22090
|
if (error instanceof Error) {
|
|
21914
|
-
console.error(
|
|
22091
|
+
console.error(chalk25.red(`
|
|
21915
22092
|
\u2717 ${error.message}
|
|
21916
22093
|
`));
|
|
21917
22094
|
}
|
|
@@ -21923,7 +22100,7 @@ environment.command("delete <id-or-name>").description("Delete an environment").
|
|
|
21923
22100
|
await environmentDeleteCommand(idOrName, options);
|
|
21924
22101
|
} catch (error) {
|
|
21925
22102
|
if (error instanceof Error) {
|
|
21926
|
-
console.error(
|
|
22103
|
+
console.error(chalk25.red(`
|
|
21927
22104
|
\u2717 ${error.message}
|
|
21928
22105
|
`));
|
|
21929
22106
|
}
|
|
@@ -21936,7 +22113,7 @@ envVars.command("list <env>").description("List variables in an environment (val
|
|
|
21936
22113
|
await envVarsListCommand(env, options);
|
|
21937
22114
|
} catch (error) {
|
|
21938
22115
|
if (error instanceof Error) {
|
|
21939
|
-
console.error(
|
|
22116
|
+
console.error(chalk25.red(`
|
|
21940
22117
|
\u2717 ${error.message}
|
|
21941
22118
|
`));
|
|
21942
22119
|
}
|
|
@@ -21948,7 +22125,7 @@ envVars.command("set <env> <key> <value>").description("Create or update a varia
|
|
|
21948
22125
|
await envVarsSetCommand(env, key, value);
|
|
21949
22126
|
} catch (error) {
|
|
21950
22127
|
if (error instanceof Error) {
|
|
21951
|
-
console.error(
|
|
22128
|
+
console.error(chalk25.red(`
|
|
21952
22129
|
\u2717 ${error.message}
|
|
21953
22130
|
`));
|
|
21954
22131
|
}
|
|
@@ -21960,7 +22137,7 @@ envVars.command("delete <env> <key-or-id>").description("Delete a variable by ke
|
|
|
21960
22137
|
await envVarsDeleteCommand(env, keyOrId, options);
|
|
21961
22138
|
} catch (error) {
|
|
21962
22139
|
if (error instanceof Error) {
|
|
21963
|
-
console.error(
|
|
22140
|
+
console.error(chalk25.red(`
|
|
21964
22141
|
\u2717 ${error.message}
|
|
21965
22142
|
`));
|
|
21966
22143
|
}
|
|
@@ -21973,7 +22150,7 @@ envFiles.command("list <env>").description("List files in an environment").actio
|
|
|
21973
22150
|
await envFilesListCommand(env);
|
|
21974
22151
|
} catch (error) {
|
|
21975
22152
|
if (error instanceof Error) {
|
|
21976
|
-
console.error(
|
|
22153
|
+
console.error(chalk25.red(`
|
|
21977
22154
|
\u2717 ${error.message}
|
|
21978
22155
|
`));
|
|
21979
22156
|
}
|
|
@@ -21985,7 +22162,7 @@ envFiles.command("set <env> <destination-path>").description("Create or update a
|
|
|
21985
22162
|
await envFilesSetCommand(env, destinationPath, options);
|
|
21986
22163
|
} catch (error) {
|
|
21987
22164
|
if (error instanceof Error) {
|
|
21988
|
-
console.error(
|
|
22165
|
+
console.error(chalk25.red(`
|
|
21989
22166
|
\u2717 ${error.message}
|
|
21990
22167
|
`));
|
|
21991
22168
|
}
|
|
@@ -21997,7 +22174,7 @@ envFiles.command("delete <env> <path-or-id>").description("Delete a file by dest
|
|
|
21997
22174
|
await envFilesDeleteCommand(env, pathOrId, options);
|
|
21998
22175
|
} catch (error) {
|
|
21999
22176
|
if (error instanceof Error) {
|
|
22000
|
-
console.error(
|
|
22177
|
+
console.error(chalk25.red(`
|
|
22001
22178
|
\u2717 ${error.message}
|
|
22002
22179
|
`));
|
|
22003
22180
|
}
|
|
@@ -22010,7 +22187,7 @@ envStartHooks.command("get <env>").description("Show the active start hook for a
|
|
|
22010
22187
|
await envStartHookGetCommand(env);
|
|
22011
22188
|
} catch (error) {
|
|
22012
22189
|
if (error instanceof Error) {
|
|
22013
|
-
console.error(
|
|
22190
|
+
console.error(chalk25.red(`
|
|
22014
22191
|
\u2717 ${error.message}
|
|
22015
22192
|
`));
|
|
22016
22193
|
}
|
|
@@ -22022,7 +22199,7 @@ envStartHooks.command("save <env>").description("Save and activate a start hook
|
|
|
22022
22199
|
await envStartHookSaveCommand(env, options);
|
|
22023
22200
|
} catch (error) {
|
|
22024
22201
|
if (error instanceof Error) {
|
|
22025
|
-
console.error(
|
|
22202
|
+
console.error(chalk25.red(`
|
|
22026
22203
|
\u2717 ${error.message}
|
|
22027
22204
|
`));
|
|
22028
22205
|
}
|
|
@@ -22034,7 +22211,7 @@ envStartHooks.command("test <env>").description("Run a start hook in an isolated
|
|
|
22034
22211
|
await envStartHookTestCommand(env, options);
|
|
22035
22212
|
} catch (error) {
|
|
22036
22213
|
if (error instanceof Error) {
|
|
22037
|
-
console.error(
|
|
22214
|
+
console.error(chalk25.red(`
|
|
22038
22215
|
\u2717 ${error.message}
|
|
22039
22216
|
`));
|
|
22040
22217
|
}
|
|
@@ -22046,7 +22223,7 @@ envStartHooks.command("repository-hooks <env>").description("List per-repo start
|
|
|
22046
22223
|
await envStartHookRepositoryHooksCommand(env);
|
|
22047
22224
|
} catch (error) {
|
|
22048
22225
|
if (error instanceof Error) {
|
|
22049
|
-
console.error(
|
|
22226
|
+
console.error(chalk25.red(`
|
|
22050
22227
|
\u2717 ${error.message}
|
|
22051
22228
|
`));
|
|
22052
22229
|
}
|
|
@@ -22058,7 +22235,7 @@ environment.action(async () => {
|
|
|
22058
22235
|
await environmentListCommand();
|
|
22059
22236
|
} catch (error) {
|
|
22060
22237
|
if (error instanceof Error) {
|
|
22061
|
-
console.error(
|
|
22238
|
+
console.error(chalk25.red(`
|
|
22062
22239
|
\u2717 ${error.message}
|
|
22063
22240
|
`));
|
|
22064
22241
|
}
|
|
@@ -22070,7 +22247,7 @@ program.command("interact").alias("i").description("Launch the interactive termi
|
|
|
22070
22247
|
await interactiveCommand();
|
|
22071
22248
|
} catch (error) {
|
|
22072
22249
|
if (error instanceof Error) {
|
|
22073
|
-
console.error(
|
|
22250
|
+
console.error(chalk25.red(`
|
|
22074
22251
|
\u2717 ${error.message}
|
|
22075
22252
|
`));
|
|
22076
22253
|
}
|
|
@@ -22121,7 +22298,7 @@ if (isAgentMode()) {
|
|
|
22121
22298
|
await previewAddCommand(workspaceId, options);
|
|
22122
22299
|
} catch (error) {
|
|
22123
22300
|
if (error instanceof Error) {
|
|
22124
|
-
console.error(
|
|
22301
|
+
console.error(chalk25.red(`
|
|
22125
22302
|
\u2717 ${error.message}
|
|
22126
22303
|
`));
|
|
22127
22304
|
}
|
|
@@ -22133,7 +22310,7 @@ if (isAgentMode()) {
|
|
|
22133
22310
|
await previewListCommand(workspaceId);
|
|
22134
22311
|
} catch (error) {
|
|
22135
22312
|
if (error instanceof Error) {
|
|
22136
|
-
console.error(
|
|
22313
|
+
console.error(chalk25.red(`
|
|
22137
22314
|
\u2717 ${error.message}
|
|
22138
22315
|
`));
|
|
22139
22316
|
}
|
|
@@ -22145,7 +22322,7 @@ if (isAgentMode()) {
|
|
|
22145
22322
|
await previewRemoveCommand(workspaceId, options);
|
|
22146
22323
|
} catch (error) {
|
|
22147
22324
|
if (error instanceof Error) {
|
|
22148
|
-
console.error(
|
|
22325
|
+
console.error(chalk25.red(`
|
|
22149
22326
|
\u2717 ${error.message}
|
|
22150
22327
|
`));
|
|
22151
22328
|
}
|
|
@@ -22154,13 +22331,54 @@ if (isAgentMode()) {
|
|
|
22154
22331
|
});
|
|
22155
22332
|
}
|
|
22156
22333
|
if (isAgentMode()) {
|
|
22334
|
+
const service = program.command("service").description("Run long-lived services (dev servers, daemons) detached from the agent session so they survive workspace sleep/wake");
|
|
22335
|
+
service.command("start <name> [command...]").description('Start (or restart) a named service as a detached daemon. Quote shell operators: replicas service start web "cd app && bun dev"').option("-d, --cwd <dir>", "Working directory for the service (defaults to the current directory)").action(async (name, commandParts, options) => {
|
|
22336
|
+
try {
|
|
22337
|
+
await serviceStartCommand(name, commandParts, options);
|
|
22338
|
+
} catch (error) {
|
|
22339
|
+
if (error instanceof Error) {
|
|
22340
|
+
console.error(`Error: ${error.message}`);
|
|
22341
|
+
}
|
|
22342
|
+
process.exit(1);
|
|
22343
|
+
}
|
|
22344
|
+
});
|
|
22345
|
+
service.command("stop <name>").description("Stop a service and its whole process group").action(async (name) => {
|
|
22346
|
+
try {
|
|
22347
|
+
await serviceStopCommand(name);
|
|
22348
|
+
} catch (error) {
|
|
22349
|
+
if (error instanceof Error) {
|
|
22350
|
+
console.error(`Error: ${error.message}`);
|
|
22351
|
+
}
|
|
22352
|
+
process.exit(1);
|
|
22353
|
+
}
|
|
22354
|
+
});
|
|
22355
|
+
service.command("list").description("List registered services and whether they are running").action(async () => {
|
|
22356
|
+
try {
|
|
22357
|
+
await serviceListCommand();
|
|
22358
|
+
} catch (error) {
|
|
22359
|
+
if (error instanceof Error) {
|
|
22360
|
+
console.error(`Error: ${error.message}`);
|
|
22361
|
+
}
|
|
22362
|
+
process.exit(1);
|
|
22363
|
+
}
|
|
22364
|
+
});
|
|
22365
|
+
service.command("logs <name>").description("Print the last lines of a service log").option("-n, --lines <n>", "Number of lines to print (default 50)").action(async (name, options) => {
|
|
22366
|
+
try {
|
|
22367
|
+
await serviceLogsCommand(name, options);
|
|
22368
|
+
} catch (error) {
|
|
22369
|
+
if (error instanceof Error) {
|
|
22370
|
+
console.error(`Error: ${error.message}`);
|
|
22371
|
+
}
|
|
22372
|
+
process.exit(1);
|
|
22373
|
+
}
|
|
22374
|
+
});
|
|
22157
22375
|
const media = program.command("media").description("Share workspace media (screenshots, videos, audio) inline in chat");
|
|
22158
22376
|
media.command("upload <files...>").description("Upload one or more screenshot, video, or audio files. Multiple files are uploaded concurrently. Prints a markdown embed per file for the assistant reply.").option("-k, --kind <kind>", "Media kind: image, video, or audio (inferred from extension if omitted)").option("-s, --session-id <id>", "Session ID to associate the asset with").option("--share", "Create an opt-in public forge embed URL for each asset").action(async (files, options) => {
|
|
22159
22377
|
try {
|
|
22160
22378
|
await mediaUploadCommand(files, options);
|
|
22161
22379
|
} catch (error) {
|
|
22162
22380
|
if (error instanceof Error) {
|
|
22163
|
-
console.error(
|
|
22381
|
+
console.error(chalk25.red(`
|
|
22164
22382
|
\u2717 ${error.message}
|
|
22165
22383
|
`));
|
|
22166
22384
|
}
|
|
@@ -22171,7 +22389,7 @@ if (isAgentMode()) {
|
|
|
22171
22389
|
try {
|
|
22172
22390
|
await mediaShareCommand(mediaId);
|
|
22173
22391
|
} catch (error) {
|
|
22174
|
-
if (error instanceof Error) console.error(
|
|
22392
|
+
if (error instanceof Error) console.error(chalk25.red(`
|
|
22175
22393
|
\u2717 ${error.message}
|
|
22176
22394
|
`));
|
|
22177
22395
|
process.exit(1);
|
|
@@ -22181,7 +22399,7 @@ if (isAgentMode()) {
|
|
|
22181
22399
|
try {
|
|
22182
22400
|
await mediaRevokeCommand(mediaId);
|
|
22183
22401
|
} catch (error) {
|
|
22184
|
-
if (error instanceof Error) console.error(
|
|
22402
|
+
if (error instanceof Error) console.error(chalk25.red(`
|
|
22185
22403
|
\u2717 ${error.message}
|
|
22186
22404
|
`));
|
|
22187
22405
|
process.exit(1);
|
|
@@ -22192,7 +22410,7 @@ if (isAgentMode()) {
|
|
|
22192
22410
|
await mediaListCommand(options);
|
|
22193
22411
|
} catch (error) {
|
|
22194
22412
|
if (error instanceof Error) {
|
|
22195
|
-
console.error(
|
|
22413
|
+
console.error(chalk25.red(`
|
|
22196
22414
|
\u2717 ${error.message}
|
|
22197
22415
|
`));
|
|
22198
22416
|
}
|
|
@@ -22205,7 +22423,7 @@ if (isAgentMode()) {
|
|
|
22205
22423
|
await learningsReadCommand(options);
|
|
22206
22424
|
} catch (error) {
|
|
22207
22425
|
if (error instanceof Error) {
|
|
22208
|
-
console.error(
|
|
22426
|
+
console.error(chalk25.red(`
|
|
22209
22427
|
\u2717 ${error.message}
|
|
22210
22428
|
`));
|
|
22211
22429
|
}
|
|
@@ -22217,7 +22435,7 @@ if (isAgentMode()) {
|
|
|
22217
22435
|
await learningsAddCommand(options);
|
|
22218
22436
|
} catch (error) {
|
|
22219
22437
|
if (error instanceof Error) {
|
|
22220
|
-
console.error(
|
|
22438
|
+
console.error(chalk25.red(`
|
|
22221
22439
|
\u2717 ${error.message}
|
|
22222
22440
|
`));
|
|
22223
22441
|
}
|
|
@@ -22229,7 +22447,7 @@ if (isAgentMode()) {
|
|
|
22229
22447
|
await learningsUpdateCommand(id, options);
|
|
22230
22448
|
} catch (error) {
|
|
22231
22449
|
if (error instanceof Error) {
|
|
22232
|
-
console.error(
|
|
22450
|
+
console.error(chalk25.red(`
|
|
22233
22451
|
\u2717 ${error.message}
|
|
22234
22452
|
`));
|
|
22235
22453
|
}
|
|
@@ -22241,7 +22459,7 @@ if (isAgentMode()) {
|
|
|
22241
22459
|
await learningsDeleteCommand(id);
|
|
22242
22460
|
} catch (error) {
|
|
22243
22461
|
if (error instanceof Error) {
|
|
22244
|
-
console.error(
|
|
22462
|
+
console.error(chalk25.red(`
|
|
22245
22463
|
\u2717 ${error.message}
|
|
22246
22464
|
`));
|
|
22247
22465
|
}
|
|
@@ -22254,7 +22472,7 @@ if (isAgentMode()) {
|
|
|
22254
22472
|
await fn(...args);
|
|
22255
22473
|
} catch (error) {
|
|
22256
22474
|
if (error instanceof Error) {
|
|
22257
|
-
console.error(
|
|
22475
|
+
console.error(chalk25.red(`
|
|
22258
22476
|
\u2717 ${error.message}
|
|
22259
22477
|
`));
|
|
22260
22478
|
}
|
|
@@ -22295,6 +22513,7 @@ if (isAgentMode()) {
|
|
|
22295
22513
|
"list",
|
|
22296
22514
|
"connect",
|
|
22297
22515
|
"preview",
|
|
22516
|
+
"service",
|
|
22298
22517
|
"media",
|
|
22299
22518
|
"slack",
|
|
22300
22519
|
"computer",
|