agent-yes 1.262.0 → 1.263.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/dist/{SUPPORTED_CLIS-BFLGbQmm.js → SUPPORTED_CLIS--5E9wO4L.js} +3 -3
- package/dist/{SUPPORTED_CLIS-CjKxvhlh.js → SUPPORTED_CLIS-DjFlWHpg.js} +2 -2
- package/dist/{agentShare-LEETLOm1.js → agentShare-BP6wiu_5.js} +2 -2
- package/dist/{callback-lqCCgSy1.js → callback-B0PQUZcK.js} +2 -2
- package/dist/{callback-CB3UjryF.js → callback-DFUFLIZQ.js} +3 -3
- package/dist/cli.js +5 -5
- package/dist/index.js +2 -2
- package/dist/{notifyDaemon-P6Q7Eo_B.js → notifyDaemon-BskLhHdg.js} +2 -2
- package/dist/{rustBinary-_qRGhAa5.js → rustBinary-Borvwmya.js} +2 -2
- package/dist/{schedule-ChAdx2h6.js → schedule-BSEIVKQ0.js} +4 -4
- package/dist/{serve-DhtgWGZB.js → serve-BEdLsSpv.js} +159 -17
- package/dist/{setup-BlJRaODn.js → setup-DFRvZ_ku.js} +2 -2
- package/dist/subcommands-B1YlmRaZ.js +10 -0
- package/dist/{subcommands-Zk3brdKt.js → subcommands-Bo1MSwuC.js} +78 -17
- package/dist/{terminal-BVWhnQUf.js → terminal-BMQWojIp.js} +2 -2
- package/dist/{trayApp-DtThjl0_.js → trayApp-CjB5QhdV.js} +2 -2
- package/dist/trayApp-DrdktFnW.js +5 -0
- package/dist/{ts-BqaOPFCQ.js → ts-BSHR_dga.js} +2 -2
- package/dist/{versionChecker-D-WLKAN6.js → versionChecker-BTLZ3PAb.js} +2 -2
- package/dist/{widget-CJyd9t8k.js → widget-BVss0Z9Y.js} +3 -3
- package/dist/{ws-mG4yeZu8.js → ws-DMudFezi.js} +2 -2
- package/dist/{ws-Vy3mBjNm.js → ws-DxNNwnrc.js} +2 -2
- package/lab/ui/index.html +101 -36
- package/package.json +2 -1
- package/scripts/deepseek-codex.ts +580 -0
- package/ts/serve.spec.ts +36 -0
- package/ts/serve.ts +144 -1
- package/ts/subcommands.ts +109 -1
- package/dist/subcommands-D6O9uRvN.js +0 -10
- package/dist/trayApp-C6U7Hghi.js +0 -5
package/ts/serve.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
appendFile,
|
|
3
|
+
mkdir,
|
|
4
|
+
open,
|
|
5
|
+
readdir,
|
|
6
|
+
readFile,
|
|
7
|
+
rename,
|
|
8
|
+
rm,
|
|
9
|
+
stat,
|
|
10
|
+
unlink,
|
|
11
|
+
writeFile,
|
|
12
|
+
} from "fs/promises";
|
|
2
13
|
import { existsSync, renameSync, watch, writeFileSync } from "node:fs";
|
|
3
14
|
import { execFileSync } from "node:child_process";
|
|
4
15
|
import { fileURLToPath } from "node:url";
|
|
@@ -566,6 +577,38 @@ async function runCapture(
|
|
|
566
577
|
}
|
|
567
578
|
}
|
|
568
579
|
|
|
580
|
+
// A non-GitHub git source (gitlab, self-hosted, …) for /api/spawn's raw-clone
|
|
581
|
+
// path. github.com inputs return null — those go through the provision module
|
|
582
|
+
// (gh auth, setup-repo.sh). Accepts scp-style git@host:path, ssh://, git://,
|
|
583
|
+
// http(s):// — bare owner/repo is github-first and never lands here.
|
|
584
|
+
export function parseGitUrl(s: string): { url: string; owner: string; repo: string } | null {
|
|
585
|
+
let host = "";
|
|
586
|
+
let pathPart = "";
|
|
587
|
+
const scp = /^git@([^:/\s]+):([^\s]+?)(?:\.git)?\/?$/.exec(s);
|
|
588
|
+
if (scp) {
|
|
589
|
+
host = scp[1]!;
|
|
590
|
+
pathPart = scp[2]!;
|
|
591
|
+
} else {
|
|
592
|
+
let u: URL;
|
|
593
|
+
try {
|
|
594
|
+
u = new URL(s);
|
|
595
|
+
} catch {
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
if (!/^(https?|ssh|git)$/.test(u.protocol.replace(":", ""))) return null;
|
|
599
|
+
host = u.hostname;
|
|
600
|
+
pathPart = u.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
|
|
601
|
+
}
|
|
602
|
+
if (/(^|\.)github\.com$/i.test(host)) return null;
|
|
603
|
+
const segs = pathPart.split("/").filter(Boolean);
|
|
604
|
+
if (segs.length < 2) return null;
|
|
605
|
+
const owner = segs[segs.length - 2]!;
|
|
606
|
+
const repo = segs[segs.length - 1]!.replace(/\.git$/, "");
|
|
607
|
+
if (!owner || !repo || owner === "." || owner === ".." || repo === "." || repo === "..")
|
|
608
|
+
return null;
|
|
609
|
+
return { url: s.replace(/\/+$/, ""), owner, repo };
|
|
610
|
+
}
|
|
611
|
+
|
|
569
612
|
// 60s memo for /api/ws/repos' gh side (see the endpoint for why).
|
|
570
613
|
let ghRepoListMemo: { t: number; ok: boolean; repos: string[]; error?: string } | null = null;
|
|
571
614
|
|
|
@@ -4024,6 +4067,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
4024
4067
|
prompt?: string;
|
|
4025
4068
|
yes?: boolean;
|
|
4026
4069
|
create?: boolean;
|
|
4070
|
+
branch?: string; // raw-clone path only (github specs embed the branch in `from`)
|
|
4027
4071
|
fork?: { fromCwd?: string; branch?: string };
|
|
4028
4072
|
};
|
|
4029
4073
|
try {
|
|
@@ -4161,6 +4205,105 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
4161
4205
|
);
|
|
4162
4206
|
cwd = result.folder;
|
|
4163
4207
|
provisioned = { action: result.action, folder: result.folder };
|
|
4208
|
+
} else if (from && parseGitUrl(from)) {
|
|
4209
|
+
// Non-GitHub git URL (gitlab, self-hosted, …): raw `git clone` into the
|
|
4210
|
+
// standard layout <wsRoot>/<owner>/<repo>/tree/<branch> — no provision
|
|
4211
|
+
// module, no setup-repo.sh. Same admission gates as the github path:
|
|
4212
|
+
// provision hook first (it may select credentials), else the allowlist.
|
|
4213
|
+
const gitSrc = parseGitUrl(from)!;
|
|
4214
|
+
const branch = typeof body.branch === "string" ? body.branch.trim() : "";
|
|
4215
|
+
// the branch lands in a filesystem path (tree/<branch>) — no empty/./..
|
|
4216
|
+
// segments, no option-looking names
|
|
4217
|
+
const badBranch = (b: string) =>
|
|
4218
|
+
b.startsWith("-") || b.split("/").some((s) => !s || s === "." || s === "..");
|
|
4219
|
+
if (branch && badBranch(branch))
|
|
4220
|
+
return new Response(`invalid branch name: ${branch}`, { status: 400 });
|
|
4221
|
+
const gitHook = await runProvisionHook(getProvisionRoot() ?? homedir(), {
|
|
4222
|
+
KOHO_ACTION: "from",
|
|
4223
|
+
KOHO_SOURCE: from,
|
|
4224
|
+
KOHO_OWNER: gitSrc.owner,
|
|
4225
|
+
KOHO_REPO: gitSrc.repo,
|
|
4226
|
+
KOHO_BRANCH: branch,
|
|
4227
|
+
KOHO_WS_ROOT: getProvisionRoot() ?? "",
|
|
4228
|
+
});
|
|
4229
|
+
if (gitHook.ran) {
|
|
4230
|
+
if (!gitHook.ok)
|
|
4231
|
+
return new Response(
|
|
4232
|
+
`provision hook denied '${gitSrc.owner}/${gitSrc.repo}' (exit ${gitHook.code})` +
|
|
4233
|
+
(gitHook.detail ? `:\n${gitHook.detail}` : ""),
|
|
4234
|
+
{ status: 403 },
|
|
4235
|
+
);
|
|
4236
|
+
} else if (!isProvisionAllowed(gitSrc.owner, gitSrc.repo)) {
|
|
4237
|
+
return new Response(
|
|
4238
|
+
`provisioning '${gitSrc.owner}/${gitSrc.repo}' is not allowed — add the owner to ` +
|
|
4239
|
+
`provisionAllowlist in ~/.agent-yes/config.json (or "*" to allow all), ` +
|
|
4240
|
+
`or set a provisionHook to gate it yourself`,
|
|
4241
|
+
{ status: 403 },
|
|
4242
|
+
);
|
|
4243
|
+
}
|
|
4244
|
+
const wsRootDir = getProvisionRoot() ?? path.join(homedir(), "ws");
|
|
4245
|
+
const base = path.join(wsRootDir, gitSrc.owner, gitSrc.repo, "tree");
|
|
4246
|
+
const destFor = (b: string) => path.join(base, b);
|
|
4247
|
+
if (branch && existsSync(path.join(destFor(branch), ".git"))) {
|
|
4248
|
+
// already provisioned — reuse; a fetch/pull is the agent's business
|
|
4249
|
+
cwd = destFor(branch);
|
|
4250
|
+
provisioned = { action: "existing", folder: cwd };
|
|
4251
|
+
} else {
|
|
4252
|
+
const tmp = path.join(base, `.clone-${process.pid}-${Date.now().toString(36)}`);
|
|
4253
|
+
try {
|
|
4254
|
+
await mkdir(base, { recursive: true });
|
|
4255
|
+
} catch (e) {
|
|
4256
|
+
return new Response(`cannot create ${base}: ${(e as Error).message}`, { status: 500 });
|
|
4257
|
+
}
|
|
4258
|
+
const cloneMs = 300_000;
|
|
4259
|
+
let created = false;
|
|
4260
|
+
let r = await runCapture(
|
|
4261
|
+
branch
|
|
4262
|
+
? ["git", "clone", "--branch", branch, "--", gitSrc.url, tmp]
|
|
4263
|
+
: ["git", "clone", "--", gitSrc.url, tmp],
|
|
4264
|
+
{ timeoutMs: cloneMs },
|
|
4265
|
+
);
|
|
4266
|
+
if (!r.ok && branch && body.create === true) {
|
|
4267
|
+
// branch may not exist yet — clone the default and branch off it
|
|
4268
|
+
await rm(tmp, { recursive: true, force: true }).catch(() => {});
|
|
4269
|
+
r = await runCapture(["git", "clone", "--", gitSrc.url, tmp], { timeoutMs: cloneMs });
|
|
4270
|
+
if (r.ok) {
|
|
4271
|
+
const co = await runCapture(["git", "-C", tmp, "checkout", "-b", branch]);
|
|
4272
|
+
if (!co.ok) r = co;
|
|
4273
|
+
else created = true;
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4276
|
+
if (!r.ok) {
|
|
4277
|
+
await rm(tmp, { recursive: true, force: true }).catch(() => {});
|
|
4278
|
+
return new Response(
|
|
4279
|
+
`git clone failed: ${(r.stderr.trim() || "unknown").slice(0, 500)}` +
|
|
4280
|
+
(branch && body.create !== true
|
|
4281
|
+
? "\n(if the branch doesn't exist yet, retry with create:true)"
|
|
4282
|
+
: ""),
|
|
4283
|
+
{ status: 502 },
|
|
4284
|
+
);
|
|
4285
|
+
}
|
|
4286
|
+
const head = await runCapture(["git", "-C", tmp, "rev-parse", "--abbrev-ref", "HEAD"]);
|
|
4287
|
+
let actual = branch || (head.ok ? head.stdout.trim() : "") || "main";
|
|
4288
|
+
if (badBranch(actual)) actual = "main";
|
|
4289
|
+
const dest = destFor(actual);
|
|
4290
|
+
if (existsSync(dest)) {
|
|
4291
|
+
// raced/already there — keep the existing checkout, drop ours
|
|
4292
|
+
await rm(tmp, { recursive: true, force: true }).catch(() => {});
|
|
4293
|
+
} else {
|
|
4294
|
+
try {
|
|
4295
|
+
await mkdir(path.dirname(dest), { recursive: true });
|
|
4296
|
+
await rename(tmp, dest);
|
|
4297
|
+
} catch (e) {
|
|
4298
|
+
await rm(tmp, { recursive: true, force: true }).catch(() => {});
|
|
4299
|
+
return new Response(`cannot place checkout at ${dest}: ${(e as Error).message}`, {
|
|
4300
|
+
status: 500,
|
|
4301
|
+
});
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
cwd = dest;
|
|
4305
|
+
provisioned = { action: created ? "cloned+new-branch" : "cloned", folder: dest };
|
|
4306
|
+
}
|
|
4164
4307
|
} else if (from) {
|
|
4165
4308
|
type Spec = { owner: string; repo: string; branch: string };
|
|
4166
4309
|
let prov: {
|
package/ts/subcommands.ts
CHANGED
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { randomBytes } from "crypto";
|
|
15
|
+
import { spawn } from "child_process";
|
|
15
16
|
import { appendFile, mkdir, open, readFile, stat, writeFile } from "fs/promises";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
16
18
|
import ms from "ms";
|
|
17
19
|
import { homedir } from "os";
|
|
18
20
|
import path from "path";
|
|
@@ -442,6 +444,8 @@ const SUBCOMMANDS = new Set([
|
|
|
442
444
|
"expose",
|
|
443
445
|
"callback",
|
|
444
446
|
"reap",
|
|
447
|
+
"deepseek",
|
|
448
|
+
"ds",
|
|
445
449
|
"help",
|
|
446
450
|
]);
|
|
447
451
|
|
|
@@ -512,6 +516,42 @@ export function isUnknownManagerToken(
|
|
|
512
516
|
return !supportedClis.includes(rawArg);
|
|
513
517
|
}
|
|
514
518
|
|
|
519
|
+
/**
|
|
520
|
+
* Write to stdout and wait until it has actually been handed off.
|
|
521
|
+
*
|
|
522
|
+
* The CLI ends with `process.exit()`, which DISCARDS bytes still sitting in the
|
|
523
|
+
* pipe buffer. Writing to a file completes synchronously so this never showed
|
|
524
|
+
* there, but any consumer that PIPES us silently lost everything past 64KiB.
|
|
525
|
+
* Measured on `ay ls --json` with a large fleet (symval CTO, 2026-08-05):
|
|
526
|
+
*
|
|
527
|
+
* ay ls --json > file 118055 bytes, valid JSON
|
|
528
|
+
* ay ls --json | consumer 65536 bytes, cut mid-multibyte — will not parse
|
|
529
|
+
*
|
|
530
|
+
* The truncation is invisible to the caller: it looks exactly like a small
|
|
531
|
+
* fleet, and an orchestrator that parses this reported 27 of 71 agents.
|
|
532
|
+
*
|
|
533
|
+
* Only capturing the REAL write's completion works. Probing afterwards with an
|
|
534
|
+
* empty `write("")` — by return value, by drain event, or by callback — reports
|
|
535
|
+
* ready while the big write is still queued (all three verified failing), so do
|
|
536
|
+
* not "simplify" this into a flush helper at the exit site.
|
|
537
|
+
*/
|
|
538
|
+
async function writeStdoutFlushed(text: string): Promise<void> {
|
|
539
|
+
// Use the WRITE'S OWN RETURN VALUE, not a probe afterwards. `false` means the
|
|
540
|
+
// pipe buffer is full and bytes are still queued; only then do we wait.
|
|
541
|
+
//
|
|
542
|
+
// Deliberately `=== false`: a stubbed/mocked stdout (tests, embedders) returns
|
|
543
|
+
// undefined, and treating that as backpressure made this await forever — it
|
|
544
|
+
// broke 5 specs before the strict compare went in. The timeout is a second
|
|
545
|
+
// guarantee that a stuck consumer can never hang the CLI.
|
|
546
|
+
const flushed = process.stdout.write(text);
|
|
547
|
+
if (flushed === false) {
|
|
548
|
+
await Promise.race([
|
|
549
|
+
new Promise<void>((resolve) => process.stdout.once("drain", () => resolve())),
|
|
550
|
+
new Promise<void>((resolve) => setTimeout(resolve, 2000)),
|
|
551
|
+
]);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
515
555
|
/**
|
|
516
556
|
* Top-level entry. Returns the desired process exit code, or null if argv
|
|
517
557
|
* is not a subcommand invocation.
|
|
@@ -629,6 +669,9 @@ export async function runSubcommand(argv: string[]): Promise<number | null> {
|
|
|
629
669
|
await reaper.sweep();
|
|
630
670
|
return 0;
|
|
631
671
|
}
|
|
672
|
+
case "deepseek":
|
|
673
|
+
case "ds":
|
|
674
|
+
return cmdDeepseek(rest);
|
|
632
675
|
case "help":
|
|
633
676
|
return cmdHelp(managerCommands);
|
|
634
677
|
default:
|
|
@@ -641,6 +684,47 @@ export async function runSubcommand(argv: string[]): Promise<number | null> {
|
|
|
641
684
|
}
|
|
642
685
|
}
|
|
643
686
|
|
|
687
|
+
// ---------------------------------------------------------------------------
|
|
688
|
+
// ay deepseek / ay ds
|
|
689
|
+
// ---------------------------------------------------------------------------
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* `ay deepseek [-- <args>…]` / `ay ds …`: run the local DeepSeek adapter that
|
|
693
|
+
* bridges Codex's Responses API to DeepSeek's chat completions, then spawn
|
|
694
|
+
* `codex` pointed at it. The adapter script lives in this package's
|
|
695
|
+
* `scripts/deepseek-codex.ts` and is Bun-only (Bun.serve / Bun.spawn), so it is
|
|
696
|
+
* re-exec'd via the same bun runtime that's running us — never imported into
|
|
697
|
+
* this process. Extra args are forwarded verbatim to `codex`.
|
|
698
|
+
*/
|
|
699
|
+
export function cmdDeepseek(rest: string[]): Promise<number> {
|
|
700
|
+
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
701
|
+
const script = path.join(root, "scripts", "deepseek-codex.ts");
|
|
702
|
+
const bunBin = process.execPath.split(/[/\\]/).at(-1)?.startsWith("bun")
|
|
703
|
+
? process.execPath
|
|
704
|
+
: "bun";
|
|
705
|
+
const child = spawn(bunBin, [script, ...rest], {
|
|
706
|
+
cwd: process.cwd(),
|
|
707
|
+
env: { ...process.env, AGENT_YES_BIN: process.argv[1] },
|
|
708
|
+
stdio: "inherit",
|
|
709
|
+
});
|
|
710
|
+
return new Promise((resolve) => {
|
|
711
|
+
child.on("error", (err) => {
|
|
712
|
+
process.stderr.write(`ay deepseek: failed to start: ${err.message}\n`);
|
|
713
|
+
resolve(1);
|
|
714
|
+
});
|
|
715
|
+
child.on("exit", (code, signal) => {
|
|
716
|
+
if (signal) {
|
|
717
|
+
resolve(128 + (signal === "SIGINT" ? 2 : signal === "SIGTERM" ? 15 : 1));
|
|
718
|
+
} else {
|
|
719
|
+
resolve(code ?? 1);
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
for (const signal of ["SIGINT", "SIGTERM"] as const) {
|
|
723
|
+
process.on(signal, () => child.kill(signal));
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
|
|
644
728
|
// ---------------------------------------------------------------------------
|
|
645
729
|
// ay help
|
|
646
730
|
// ---------------------------------------------------------------------------
|
|
@@ -747,6 +831,7 @@ export async function cmdHelp(managerCommands = true): Promise<number> {
|
|
|
747
831
|
` ay result <keyword> [--wait] pull an agent's structured result envelope\n` +
|
|
748
832
|
` ay result set '<json>' (inside an agent) deposit your result envelope\n` +
|
|
749
833
|
` ay reap kill process groups leaked by dead agents\n` +
|
|
834
|
+
` ay deepseek|ds [-- <codex args>] run codex via the local DeepSeek adapter (DEEPSEEK_API_KEY)\n` +
|
|
750
835
|
wsLines +
|
|
751
836
|
`\n` +
|
|
752
837
|
`Remote:\n` +
|
|
@@ -1849,7 +1934,7 @@ async function cmdLs(rest: string[]): Promise<number> {
|
|
|
1849
1934
|
const enriched = await Promise.all(
|
|
1850
1935
|
records.map(async (r) => ({ ...r, ...(await deriveLiveState(r)) })),
|
|
1851
1936
|
);
|
|
1852
|
-
|
|
1937
|
+
await writeStdoutFlushed(JSON.stringify(enriched, null, 2) + "\n");
|
|
1853
1938
|
return 0;
|
|
1854
1939
|
}
|
|
1855
1940
|
|
|
@@ -3222,6 +3307,15 @@ async function cmdSend(rest: string[]): Promise<number> {
|
|
|
3222
3307
|
})
|
|
3223
3308
|
.help(false)
|
|
3224
3309
|
.version(false)
|
|
3310
|
+
// An UNKNOWN flag must be an error, never a silent reinterpretation of the
|
|
3311
|
+
// message. yargs otherwise swallows `--body-file /tmp/x` as an ad-hoc option
|
|
3312
|
+
// whose VALUE is the next token — which removes the positional entirely and
|
|
3313
|
+
// sends an EMPTY body. That failure is invisible from both ends: the sender
|
|
3314
|
+
// sees a normal exit, the recipient sees a blank message and reads it as an
|
|
3315
|
+
// idle lane. Observed 2026-07-30: four consecutive replies vanished this way,
|
|
3316
|
+
// and the receiving lane concluded the sender had stopped working and began
|
|
3317
|
+
// taking over the work.
|
|
3318
|
+
.strictOptions()
|
|
3225
3319
|
.exitProcess(false);
|
|
3226
3320
|
|
|
3227
3321
|
const argv = await y.parseAsync();
|
|
@@ -3238,6 +3332,17 @@ async function cmdSend(rest: string[]): Promise<number> {
|
|
|
3238
3332
|
if (!keyword)
|
|
3239
3333
|
throw new Error("usage: ay send <keyword> <msg|-> [--code=enter|esc|ctrl-c|ctrl-y|tab|none]");
|
|
3240
3334
|
|
|
3335
|
+
// Second line of defence, independent of how the message went missing: never
|
|
3336
|
+
// deliver nothing. Sending an empty body is never what anyone meant, and its
|
|
3337
|
+
// whole cost is paid by the RECIPIENT, who cannot tell "no message" from
|
|
3338
|
+
// "nothing to say". `-` is exempt here and validated after stdin is read.
|
|
3339
|
+
if (rawMessage !== "-" && rawMessage.trim() === "") {
|
|
3340
|
+
throw new Error(
|
|
3341
|
+
"ay send: refusing to send an empty message. Pass the text as a single argument, " +
|
|
3342
|
+
"or use `-` to read the body from stdin (e.g. `ay send <keyword> - < file.txt`).",
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3241
3346
|
const codeName = argv.code.toLowerCase();
|
|
3242
3347
|
{
|
|
3243
3348
|
const remote = await resolveRemoteSpec(keyword);
|
|
@@ -3271,6 +3376,9 @@ async function cmdSend(rest: string[]): Promise<number> {
|
|
|
3271
3376
|
const chunks: Buffer[] = [];
|
|
3272
3377
|
for await (const chunk of process.stdin) chunks.push(chunk as Buffer);
|
|
3273
3378
|
body = Buffer.concat(chunks).toString("utf-8").trimEnd();
|
|
3379
|
+
if (body.trim() === "") {
|
|
3380
|
+
throw new Error("ay send: refusing to send an empty message (stdin was empty).");
|
|
3381
|
+
}
|
|
3274
3382
|
} else {
|
|
3275
3383
|
body = rawMessage;
|
|
3276
3384
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./globalPidIndex-pwp7Vb7o.js";
|
|
3
|
-
import "./messageLog-BYFwioFY.js";
|
|
4
|
-
import "./e2e-CUMZC53I.js";
|
|
5
|
-
import "./configShared-DtHMBCl7.js";
|
|
6
|
-
import { A as readPtysize, B as runSubcommand, C as lastStdinAt, D as readAgentPtysize, E as menuSelectKeys, F as renderRawLogLines, G as waitForLogQuiet, H as stdinActivityPath, I as resolveOne, K as writeKeysPaced, L as resolveReadWindow, M as recentReadEdges, N as renderLogTailLines, O as readLogForRender, P as renderRawLog, R as resolveResumeArgs, S as isUserTyping, T as matchKeyword, U as stopTipForCli, V as snapshotStatus, W as submitAndConfirm, _ as isExitRequest, a as backoffWhileTyping, b as isSubcommand, c as cursorAbs, d as extractBadges, f as extractMenu, g as isAgentStuck, h as finalizedLines, i as TYPING_WINDOW_MS, j as recentMessageEdges, k as readNotes, l as deriveLiveState, m as extractTaskCounts, n as MAX_RENDER_BYTES, o as cmdHelp, p as extractNeedsInput, q as writeToIpc, r as READ_PAGE_DEFAULT, s as controlCodeFromName, t as GRACEFUL_EXIT_COMMANDS, u as deriveLiveStatus, v as isPidAlive, w as listRecords, x as isUnknownManagerToken, y as isSlashCommand, z as restartHintLines } from "./subcommands-Zk3brdKt.js";
|
|
7
|
-
import "./webrtcLink-CS4D-3G1.js";
|
|
8
|
-
import "./remotes-Cn-wszbK.js";
|
|
9
|
-
|
|
10
|
-
export { cmdHelp, isSubcommand, isUnknownManagerToken, runSubcommand };
|
package/dist/trayApp-C6U7Hghi.js
DELETED