agent-yes 1.101.0 → 1.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/SUPPORTED_CLIS-Bfvn4t4T.js +8 -0
- package/dist/{SUPPORTED_CLIS-CXsHRSdB.js → SUPPORTED_CLIS-DLa81elJ.js} +2 -2
- package/dist/cli.js +3 -3
- package/dist/index.js +2 -2
- package/dist/{serve-Bbl4BGZs.js → serve-_SDEh-NR.js} +6 -5
- package/dist/{subcommands-Dt9kMsEQ.js → subcommands-DDbKmEBG.js} +1 -1
- package/dist/{subcommands-wyGQaaaK.js → subcommands-DZRLQ15r.js} +2 -2
- package/dist/{ts-mo_bB4au.js → ts-CFWQFwe3.js} +2 -2
- package/dist/{versionChecker-BhU9-zSi.js → versionChecker-IfF6V9MT.js} +2 -2
- package/lab/ui/console-logic.js +79 -0
- package/lab/ui/index.html +61 -75
- package/package.json +4 -2
- package/ts/serve.ts +2 -0
- package/ts/workspaceConfig.spec.ts +71 -0
- package/ts/workspaceConfig.ts +70 -0
- package/dist/SUPPORTED_CLIS-DGQZ0sRr.js +0 -8
package/README.md
CHANGED
|
@@ -4,6 +4,28 @@ A wrapper tool that automates interactions with various AI CLI tools by automati
|
|
|
4
4
|
|
|
5
5
|
⚠️ **Important Security Warning**: Only run this on trusted repositories. This tool automatically responds to prompts and can execute commands without user confirmation. Be aware of potential prompt injection attacks where malicious code or instructions could be embedded in files or user inputs to manipulate the automated responses.
|
|
6
6
|
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
One-liner (installs Bun if needed, then the `ay` / `cy` / `claude-yes` … CLIs):
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# macOS / Linux
|
|
13
|
+
curl -fsSL https://agent-yes.com/setup.sh | sh
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```powershell
|
|
17
|
+
# Windows (PowerShell)
|
|
18
|
+
irm https://agent-yes.com/setup.ps1 | iex
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or with a package manager you already have:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bun add -g agent-yes # or: npm install -g agent-yes
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then: `ay claude` (run an agent with auto-yes) · `ay serve share` (web console + shareable link) · live console at https://agent-yes.com
|
|
28
|
+
|
|
7
29
|
## Features
|
|
8
30
|
|
|
9
31
|
- **Multi-CLI Support**: Works with Claude, Gemini, Codex, Copilot, and Cursor CLI tools
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "./ts-CFWQFwe3.js";
|
|
2
|
+
import "./logger-B9h0djqx.js";
|
|
3
|
+
import "./versionChecker-IfF6V9MT.js";
|
|
4
|
+
import "./pidStore-DBjlqzo8.js";
|
|
5
|
+
import "./globalPidIndex-yVd3mbsV.js";
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DLa81elJ.js";
|
|
7
|
+
|
|
8
|
+
export { SUPPORTED_CLIS };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-CFWQFwe3.js";
|
|
2
2
|
|
|
3
3
|
//#region ts/SUPPORTED_CLIS.ts
|
|
4
4
|
const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
|
|
5
5
|
|
|
6
6
|
//#endregion
|
|
7
7
|
export { SUPPORTED_CLIS as t };
|
|
8
|
-
//# sourceMappingURL=SUPPORTED_CLIS-
|
|
8
|
+
//# sourceMappingURL=SUPPORTED_CLIS-DLa81elJ.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { n as logger } from "./logger-B9h0djqx.js";
|
|
3
|
-
import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-
|
|
3
|
+
import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-IfF6V9MT.js";
|
|
4
4
|
import { argv } from "process";
|
|
5
5
|
import { execFileSync, spawn } from "child_process";
|
|
6
6
|
import ms from "ms";
|
|
@@ -482,7 +482,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
482
482
|
{
|
|
483
483
|
const rawArg = process.argv[2];
|
|
484
484
|
const isHelpFlag = rawArg === "-h" || rawArg === "--help";
|
|
485
|
-
const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-
|
|
485
|
+
const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-DDbKmEBG.js");
|
|
486
486
|
if (isHelpFlag && process.argv.length === 3) {
|
|
487
487
|
cmdHelp();
|
|
488
488
|
process.exit(0);
|
|
@@ -515,7 +515,7 @@ if (config.useRust) {
|
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
if (rustBinary) {
|
|
518
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
518
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-Bfvn4t4T.js");
|
|
519
519
|
const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
|
|
520
520
|
if (config.verbose) {
|
|
521
521
|
console.log(`[rust] Using binary: ${rustBinary}`);
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-CFWQFwe3.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-
|
|
3
|
+
import "./versionChecker-IfF6V9MT.js";
|
|
4
4
|
import "./pidStore-DBjlqzo8.js";
|
|
5
5
|
import "./globalPidIndex-yVd3mbsV.js";
|
|
6
6
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import "./ts-
|
|
1
|
+
import "./ts-CFWQFwe3.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-
|
|
3
|
+
import "./versionChecker-IfF6V9MT.js";
|
|
4
4
|
import "./pidStore-DBjlqzo8.js";
|
|
5
5
|
import "./globalPidIndex-yVd3mbsV.js";
|
|
6
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DLa81elJ.js";
|
|
7
7
|
import "./remotes-C3xPRtfg.js";
|
|
8
|
-
import { c as readNotes, f as snapshotStatus, l as renderRawLog, m as writeToIpc, o as listRecords, r as controlCodeFromName, u as resolveOne } from "./subcommands-
|
|
8
|
+
import { c as readNotes, f as snapshotStatus, l as renderRawLog, m as writeToIpc, o as listRecords, r as controlCodeFromName, u as resolveOne } from "./subcommands-DZRLQ15r.js";
|
|
9
9
|
import yargs from "yargs";
|
|
10
10
|
import { mkdir, open, readFile, writeFile } from "fs/promises";
|
|
11
11
|
import { homedir } from "os";
|
|
@@ -482,6 +482,7 @@ Options:
|
|
|
482
482
|
const p = new URL(req.url).pathname;
|
|
483
483
|
if (req.method === "GET" && (p === "/" || p === "/index.html")) return serveUiFile("index.html", "text/html; charset=utf-8");
|
|
484
484
|
if (req.method === "GET" && p === "/room-client.js") return serveUiFile("room-client.js", "text/javascript; charset=utf-8");
|
|
485
|
+
if (req.method === "GET" && p === "/console-logic.js") return serveUiFile("console-logic.js", "text/javascript; charset=utf-8");
|
|
485
486
|
if (req.method === "GET" && p === "/favicon.ico") return new Response(null, { status: 204 });
|
|
486
487
|
return apiFetch(req);
|
|
487
488
|
};
|
|
@@ -551,4 +552,4 @@ Options:
|
|
|
551
552
|
|
|
552
553
|
//#endregion
|
|
553
554
|
export { cmdServe };
|
|
554
|
-
//# sourceMappingURL=serve-
|
|
555
|
+
//# sourceMappingURL=serve-_SDEh-NR.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-B9h0djqx.js";
|
|
2
2
|
import "./globalPidIndex-yVd3mbsV.js";
|
|
3
3
|
import "./remotes-C3xPRtfg.js";
|
|
4
|
-
import { a as isSubcommand, c as readNotes, d as runSubcommand, f as snapshotStatus, i as isPidAlive, l as renderRawLog, m as writeToIpc, n as cmdHelp, o as listRecords, p as stopTipForCli, r as controlCodeFromName, s as matchKeyword, t as GRACEFUL_EXIT_COMMANDS, u as resolveOne } from "./subcommands-
|
|
4
|
+
import { a as isSubcommand, c as readNotes, d as runSubcommand, f as snapshotStatus, i as isPidAlive, l as renderRawLog, m as writeToIpc, n as cmdHelp, o as listRecords, p as stopTipForCli, r as controlCodeFromName, s as matchKeyword, t as GRACEFUL_EXIT_COMMANDS, u as resolveOne } from "./subcommands-DZRLQ15r.js";
|
|
5
5
|
|
|
6
6
|
export { cmdHelp, isSubcommand, runSubcommand };
|
|
@@ -163,7 +163,7 @@ async function runSubcommand(argv) {
|
|
|
163
163
|
case "restart": return await cmdRestart(rest);
|
|
164
164
|
case "note": return await cmdNote(rest);
|
|
165
165
|
case "serve": {
|
|
166
|
-
const { cmdServe } = await import("./serve-
|
|
166
|
+
const { cmdServe } = await import("./serve-_SDEh-NR.js");
|
|
167
167
|
return cmdServe(rest);
|
|
168
168
|
}
|
|
169
169
|
case "setup": {
|
|
@@ -1452,4 +1452,4 @@ async function cmdStatus(rest) {
|
|
|
1452
1452
|
|
|
1453
1453
|
//#endregion
|
|
1454
1454
|
export { isSubcommand as a, readNotes as c, runSubcommand as d, snapshotStatus as f, isPidAlive as i, renderRawLog as l, writeToIpc as m, cmdHelp as n, listRecords as o, stopTipForCli as p, controlCodeFromName as r, matchKeyword as s, GRACEFUL_EXIT_COMMANDS as t, resolveOne as u };
|
|
1455
|
-
//# sourceMappingURL=subcommands-
|
|
1455
|
+
//# sourceMappingURL=subcommands-DZRLQ15r.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-B9h0djqx.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-IfF6V9MT.js";
|
|
3
3
|
import { n as agentYesHome, t as PidStore } from "./pidStore-DBjlqzo8.js";
|
|
4
4
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CJxsoGdb.js";
|
|
5
5
|
import { i as readGlobalPids } from "./globalPidIndex-yVd3mbsV.js";
|
|
@@ -1714,4 +1714,4 @@ function sleep(ms) {
|
|
|
1714
1714
|
|
|
1715
1715
|
//#endregion
|
|
1716
1716
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1717
|
-
//# sourceMappingURL=ts-
|
|
1717
|
+
//# sourceMappingURL=ts-CFWQFwe3.js.map
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
|
|
8
8
|
//#region package.json
|
|
9
9
|
var name = "agent-yes";
|
|
10
|
-
var version = "1.
|
|
10
|
+
var version = "1.103.0";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -221,4 +221,4 @@ async function displayVersion() {
|
|
|
221
221
|
|
|
222
222
|
//#endregion
|
|
223
223
|
export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
|
|
224
|
-
//# sourceMappingURL=versionChecker-
|
|
224
|
+
//# sourceMappingURL=versionChecker-IfF6V9MT.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Pure, DOM-free logic for the agent-yes console (lab/ui/index.html).
|
|
2
|
+
//
|
|
3
|
+
// Extracted into its own ES module so it can be unit-tested in vitest
|
|
4
|
+
// (tests/ui-logic/console-logic.spec.ts) while the browser imports it directly
|
|
5
|
+
// — no build step. Everything here is a pure function of its arguments: no
|
|
6
|
+
// document/window/localStorage access, no Date.now() except via an injected
|
|
7
|
+
// `now` so age() is deterministic under test.
|
|
8
|
+
|
|
9
|
+
// An agent entry as surfaced by /api/ls (the fields this module reads):
|
|
10
|
+
// { cli, cwd, title, prompt, status, started_at, pid, _host }
|
|
11
|
+
|
|
12
|
+
// claude is the default CLI — show the cli name only when it differs, so the
|
|
13
|
+
// common case stays uncluttered and the identity (repo/branch) leads instead.
|
|
14
|
+
export const cliLabel = (e) => (e.cli && e.cli !== "claude" ? e.cli : "");
|
|
15
|
+
|
|
16
|
+
// Parse owner/repo/branch from a cwd like .../ws/<owner>/<repo>/tree/<branch>.
|
|
17
|
+
export function repoBranch(e) {
|
|
18
|
+
const m = /\/([^/]+)\/([^/]+)\/tree\/([^/]+)/.exec(e.cwd || "");
|
|
19
|
+
return m ? { owner: m[1], repo: m[2], branch: m[3] } : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Identity string for the left panel. cap=true → repo/branch each clipped to
|
|
23
|
+
// 3 chars for the compact one-line view (e.g. "age/mai").
|
|
24
|
+
export function ident(e, cap) {
|
|
25
|
+
const rb = repoBranch(e);
|
|
26
|
+
if (!rb) return "";
|
|
27
|
+
const c = (s) => (cap && s.length > 3 ? s.slice(0, 3) : s);
|
|
28
|
+
return `${c(rb.repo)}/${c(rb.branch)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Derive codehost-style mnemonic tags from a cwd like .../ws/<owner>/<repo>/tree/<wt>.
|
|
32
|
+
export function tagsFor(e) {
|
|
33
|
+
const t = [];
|
|
34
|
+
const rb = repoBranch(e);
|
|
35
|
+
if (rb) {
|
|
36
|
+
t.push(["repo", `${rb.owner}/${rb.repo}`], ["wt", rb.branch]);
|
|
37
|
+
}
|
|
38
|
+
const cli = cliLabel(e);
|
|
39
|
+
if (cli) t.push(["cli", cli]);
|
|
40
|
+
if (e._host) t.push(["host", e._host]); // codehost rooms: which machine
|
|
41
|
+
return t;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Human age of an agent ("12s" / "5m" / "3h"). `now` is injectable so tests
|
|
45
|
+
// don't depend on the wall clock; the browser calls age(e) and gets Date.now().
|
|
46
|
+
export function age(e, now = Date.now()) {
|
|
47
|
+
if (!e.started_at) return "";
|
|
48
|
+
const s = Math.max(0, (now - e.started_at) / 1000);
|
|
49
|
+
if (s < 60) return Math.floor(s) + "s";
|
|
50
|
+
if (s < 3600) return Math.floor(s / 60) + "m";
|
|
51
|
+
return Math.floor(s / 3600) + "h";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Filter predicate: every space-separated token must match. A `key:value` token
|
|
55
|
+
// matches against the mnemonic tags (repo/wt/cli/host); a bare token is a
|
|
56
|
+
// case-insensitive substring search over title/prompt/cli/cwd/status.
|
|
57
|
+
export function matches(e, toks) {
|
|
58
|
+
const hay =
|
|
59
|
+
(e.title || "") + " " + (e.prompt || "") + " " + e.cli + " " + (e.cwd || "") + " " + e.status;
|
|
60
|
+
return toks.every((tok) => {
|
|
61
|
+
tok = tok.toLowerCase();
|
|
62
|
+
const ci = tok.indexOf(":");
|
|
63
|
+
if (ci > 0) {
|
|
64
|
+
const k = tok.slice(0, ci),
|
|
65
|
+
v = tok.slice(ci + 1);
|
|
66
|
+
return tagsFor(e).some(([tk, tv]) => tk === k && tv.toLowerCase().includes(v));
|
|
67
|
+
}
|
|
68
|
+
return hay.toLowerCase().includes(tok);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Next selection index when stepping the list by `dir` (+1 down / -1 up).
|
|
73
|
+
// No current selection (i<0) lands on the first (down) or last (up) row;
|
|
74
|
+
// otherwise clamps at the ends. Returns -1 for an empty list.
|
|
75
|
+
export function nextIndex(len, i, dir) {
|
|
76
|
+
if (len <= 0) return -1;
|
|
77
|
+
if (i < 0) return dir > 0 ? 0 : len - 1;
|
|
78
|
+
return Math.max(0, Math.min(len - 1, i + dir));
|
|
79
|
+
}
|
package/lab/ui/index.html
CHANGED
|
@@ -101,6 +101,23 @@
|
|
|
101
101
|
color: var(--muted);
|
|
102
102
|
font-size: 12.5px;
|
|
103
103
|
}
|
|
104
|
+
.install {
|
|
105
|
+
margin-top: 8px;
|
|
106
|
+
color: var(--muted);
|
|
107
|
+
font-size: 11.5px;
|
|
108
|
+
}
|
|
109
|
+
.install code {
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
color: var(--green);
|
|
112
|
+
}
|
|
113
|
+
.install code:hover {
|
|
114
|
+
filter: brightness(1.25);
|
|
115
|
+
}
|
|
116
|
+
@media (max-width: 720px) {
|
|
117
|
+
.install .winhint {
|
|
118
|
+
display: none;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
104
121
|
.ibox {
|
|
105
122
|
display: flex;
|
|
106
123
|
align-items: center;
|
|
@@ -604,6 +621,14 @@
|
|
|
604
621
|
<div class="sub">
|
|
605
622
|
Live <code>ay ls</code> + per-agent tail & send. Backed by <code>ay serve</code>.
|
|
606
623
|
</div>
|
|
624
|
+
<div class="install" title="click to copy">
|
|
625
|
+
install:
|
|
626
|
+
<code class="copy">curl -fsSL https://agent-yes.com/setup.sh | sh</code>
|
|
627
|
+
<span class="winhint"
|
|
628
|
+
>· Windows:
|
|
629
|
+
<code class="copy">irm https://agent-yes.com/setup.ps1 | iex</code></span
|
|
630
|
+
>
|
|
631
|
+
</div>
|
|
607
632
|
<div class="ibox">
|
|
608
633
|
<span class="mag">⌕</span>
|
|
609
634
|
<input
|
|
@@ -650,7 +675,21 @@
|
|
|
650
675
|
<div class="launchoverlay" id="launch" style="display: none"></div>
|
|
651
676
|
<div class="launchoverlay" id="newform" style="display: none"></div>
|
|
652
677
|
|
|
653
|
-
<script>
|
|
678
|
+
<script type="module">
|
|
679
|
+
// Pure list/identity/filter helpers live in a sibling module so they can be
|
|
680
|
+
// unit-tested (tests/ui-logic/console-logic.spec.ts) without a DOM. This
|
|
681
|
+
// script is a module (deferred, runs after the codehost shim above sets
|
|
682
|
+
// window.__codehost), so a static import is safe.
|
|
683
|
+
import {
|
|
684
|
+
cliLabel,
|
|
685
|
+
repoBranch,
|
|
686
|
+
ident,
|
|
687
|
+
tagsFor,
|
|
688
|
+
age,
|
|
689
|
+
matches,
|
|
690
|
+
nextIndex,
|
|
691
|
+
} from "./console-logic.js";
|
|
692
|
+
|
|
654
693
|
let entries = [];
|
|
655
694
|
let sel = null; // selected keyword (pid as string)
|
|
656
695
|
let es = null; // live-tail subscription closer
|
|
@@ -984,66 +1023,6 @@
|
|
|
984
1023
|
},
|
|
985
1024
|
};
|
|
986
1025
|
|
|
987
|
-
// claude is the default CLI — show the cli name only when it differs, so the
|
|
988
|
-
// common case stays uncluttered and the identity (repo/branch) leads instead.
|
|
989
|
-
const cliLabel = (e) => (e.cli && e.cli !== "claude" ? e.cli : "");
|
|
990
|
-
// Parse owner/repo/branch from a cwd like .../ws/<owner>/<repo>/tree/<branch>.
|
|
991
|
-
function repoBranch(e) {
|
|
992
|
-
const m = /\/([^/]+)\/([^/]+)\/tree\/([^/]+)/.exec(e.cwd || "");
|
|
993
|
-
return m ? { owner: m[1], repo: m[2], branch: m[3] } : null;
|
|
994
|
-
}
|
|
995
|
-
// Identity string for the left panel. cap=true → repo/branch each clipped to
|
|
996
|
-
// 3 chars for the compact one-line view (e.g. "age/mai").
|
|
997
|
-
function ident(e, cap) {
|
|
998
|
-
const rb = repoBranch(e);
|
|
999
|
-
if (!rb) return "";
|
|
1000
|
-
const c = (s) => (cap && s.length > 3 ? s.slice(0, 3) : s);
|
|
1001
|
-
return `${c(rb.repo)}/${c(rb.branch)}`;
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
// Derive codehost-style mnemonic tags from a cwd like .../ws/<owner>/<repo>/tree/<wt>
|
|
1005
|
-
function tagsFor(e) {
|
|
1006
|
-
const t = [];
|
|
1007
|
-
const rb = repoBranch(e);
|
|
1008
|
-
if (rb) {
|
|
1009
|
-
t.push(["repo", `${rb.owner}/${rb.repo}`], ["wt", rb.branch]);
|
|
1010
|
-
}
|
|
1011
|
-
const cli = cliLabel(e);
|
|
1012
|
-
if (cli) t.push(["cli", cli]);
|
|
1013
|
-
if (e._host) t.push(["host", e._host]); // codehost rooms: which machine
|
|
1014
|
-
return t;
|
|
1015
|
-
}
|
|
1016
|
-
function age(e) {
|
|
1017
|
-
if (!e.started_at) return "";
|
|
1018
|
-
const s = Math.max(0, (Date.now() - e.started_at) / 1000);
|
|
1019
|
-
if (s < 60) return Math.floor(s) + "s";
|
|
1020
|
-
if (s < 3600) return Math.floor(s / 60) + "m";
|
|
1021
|
-
return Math.floor(s / 3600) + "h";
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
function matches(e, toks) {
|
|
1025
|
-
const hay =
|
|
1026
|
-
(e.title || "") +
|
|
1027
|
-
" " +
|
|
1028
|
-
(e.prompt || "") +
|
|
1029
|
-
" " +
|
|
1030
|
-
e.cli +
|
|
1031
|
-
" " +
|
|
1032
|
-
(e.cwd || "") +
|
|
1033
|
-
" " +
|
|
1034
|
-
e.status;
|
|
1035
|
-
return toks.every((tok) => {
|
|
1036
|
-
tok = tok.toLowerCase();
|
|
1037
|
-
const ci = tok.indexOf(":");
|
|
1038
|
-
if (ci > 0) {
|
|
1039
|
-
const k = tok.slice(0, ci),
|
|
1040
|
-
v = tok.slice(ci + 1);
|
|
1041
|
-
return tagsFor(e).some(([tk, tv]) => tk === k && tv.toLowerCase().includes(v));
|
|
1042
|
-
}
|
|
1043
|
-
return hay.toLowerCase().includes(tok);
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
1026
|
// Compact list: one line per agent (dot + cli + title), persisted per device.
|
|
1048
1027
|
let compactList = localStorage.getItem("ay.compactList") === "1";
|
|
1049
1028
|
|
|
@@ -1244,10 +1223,8 @@
|
|
|
1244
1223
|
const toks = $("q").value.trim().split(/\s+/).filter(Boolean);
|
|
1245
1224
|
const shown = entries.filter((e) => matches(e, toks));
|
|
1246
1225
|
if (!shown.length) return;
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
else i = Math.max(0, Math.min(shown.length - 1, i + dir));
|
|
1250
|
-
const next = shown[i];
|
|
1226
|
+
const cur = shown.findIndex((e) => String(e.pid) === sel);
|
|
1227
|
+
const next = shown[nextIndex(shown.length, cur, dir)];
|
|
1251
1228
|
select(String(next.pid));
|
|
1252
1229
|
const row = $("list").querySelector('.row[data-pid="' + next.pid + '"]');
|
|
1253
1230
|
if (row) row.scrollIntoView({ block: "nearest" });
|
|
@@ -1384,8 +1361,12 @@
|
|
|
1384
1361
|
: `<div class="empty2">no saved rooms — paste a share link below</div>`;
|
|
1385
1362
|
$("rooms").innerHTML = `<div class="rtitle">rooms · stored on this device</div>${items}
|
|
1386
1363
|
<div class="radd"><input id="roomin" placeholder="room:token or https://…/#room:token" /><button id="roomadd">add</button></div>
|
|
1364
|
+
<div class="rconnect">new here? install agent-yes (bun or npm, auto):
|
|
1365
|
+
<code id="cmdinstall" class="copy" title="click to copy">curl -fsSL https://agent-yes.com/setup.sh | sh</code>
|
|
1366
|
+
<span style="opacity:.6">Windows:</span>
|
|
1367
|
+
<code id="cmdinstallwin" class="copy" title="click to copy">irm https://agent-yes.com/setup.ps1 | iex</code></div>
|
|
1387
1368
|
<div class="rconnect">share your own fleet — run this, then open the printed link:
|
|
1388
|
-
<code id="cmd" title="click to copy">
|
|
1369
|
+
<code id="cmd" class="copy" title="click to copy">ay serve share</code></div>
|
|
1389
1370
|
<div class="rconnect">or view a <b>codehost</b> room — paste <code>ch:<room-token></code> (or a
|
|
1390
1371
|
codehost.dev share link) above; every machine in the room shows its agents here.</div>`;
|
|
1391
1372
|
}
|
|
@@ -1421,15 +1402,20 @@
|
|
|
1421
1402
|
$("rooms").style.display = "none";
|
|
1422
1403
|
} else alert("expected room:token or a share link");
|
|
1423
1404
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
// Click-to-copy for any <code class="copy"> (install one-liners, share cmd…),
|
|
1408
|
+
// wherever it lives — header or the rooms panel.
|
|
1409
|
+
document.addEventListener("click", (ev) => {
|
|
1410
|
+
const c = ev.target.closest && ev.target.closest("code.copy");
|
|
1411
|
+
if (!c) return;
|
|
1412
|
+
navigator.clipboard?.writeText(c.textContent).then(() => {
|
|
1413
|
+
const o = c.textContent;
|
|
1414
|
+
c.textContent = "copied ✓";
|
|
1415
|
+
setTimeout(() => {
|
|
1416
|
+
c.textContent = o;
|
|
1417
|
+
}, 1000);
|
|
1418
|
+
});
|
|
1433
1419
|
});
|
|
1434
1420
|
|
|
1435
1421
|
// ---- launch: command-only URLs (#launch=<json>, NO token) ----
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.103.0",
|
|
4
4
|
"description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"ts/*.ts",
|
|
56
56
|
"!dist/**/*.map",
|
|
57
57
|
"dist/**/*.js",
|
|
58
|
+
"lab/ui/console-logic.js",
|
|
58
59
|
"lab/ui/index.html",
|
|
59
60
|
"lab/ui/room-client.js"
|
|
60
61
|
],
|
|
@@ -86,7 +87,8 @@
|
|
|
86
87
|
"release:beta": "standard-version && npm publish --tag beta",
|
|
87
88
|
"test": "vitest run",
|
|
88
89
|
"test:coverage": "vitest run --coverage",
|
|
89
|
-
"test:ui": "vitest run --config tests/ui-test/vitest.config.ts"
|
|
90
|
+
"test:ui": "vitest run --config tests/ui-test/vitest.config.ts",
|
|
91
|
+
"test:ui-dom": "vitest run --config tests/ui-dom/vitest.config.ts"
|
|
90
92
|
},
|
|
91
93
|
"dependencies": {
|
|
92
94
|
"@snomiao/bun-pty": "^0.3.4",
|
package/ts/serve.ts
CHANGED
|
@@ -620,6 +620,8 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
620
620
|
return serveUiFile("index.html", "text/html; charset=utf-8");
|
|
621
621
|
if (req.method === "GET" && p === "/room-client.js")
|
|
622
622
|
return serveUiFile("room-client.js", "text/javascript; charset=utf-8");
|
|
623
|
+
if (req.method === "GET" && p === "/console-logic.js")
|
|
624
|
+
return serveUiFile("console-logic.js", "text/javascript; charset=utf-8");
|
|
623
625
|
if (req.method === "GET" && p === "/favicon.ico") return new Response(null, { status: 204 });
|
|
624
626
|
return apiFetch(req);
|
|
625
627
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
3
|
+
import { homedir, tmpdir } from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import {
|
|
6
|
+
expandTilde,
|
|
7
|
+
getWorkspaceRoot,
|
|
8
|
+
resolveSpawnCwd,
|
|
9
|
+
setWorkspaceRoot,
|
|
10
|
+
} from "./workspaceConfig.ts";
|
|
11
|
+
|
|
12
|
+
describe("workspaceConfig", () => {
|
|
13
|
+
let original: string | undefined;
|
|
14
|
+
let tmp: string;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
original = process.env.AGENT_YES_HOME;
|
|
17
|
+
tmp = mkdtempSync(path.join(tmpdir(), "ay-cfg-"));
|
|
18
|
+
process.env.AGENT_YES_HOME = tmp;
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
if (original === undefined) delete process.env.AGENT_YES_HOME;
|
|
22
|
+
else process.env.AGENT_YES_HOME = original;
|
|
23
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("defaults the workspace root to the home dir when unset", () => {
|
|
27
|
+
expect(getWorkspaceRoot()).toBe(homedir());
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("round-trips set/get and resolves to an absolute path", () => {
|
|
31
|
+
const saved = setWorkspaceRoot(path.join(tmp, "ws"));
|
|
32
|
+
expect(saved).toBe(path.join(tmp, "ws"));
|
|
33
|
+
expect(getWorkspaceRoot()).toBe(path.join(tmp, "ws"));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("expands a leading ~", () => {
|
|
37
|
+
expect(expandTilde("~")).toBe(homedir());
|
|
38
|
+
expect(expandTilde("~/projects")).toBe(path.join(homedir(), "projects"));
|
|
39
|
+
expect(expandTilde("/abs/path")).toBe("/abs/path");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("stores a tilde path as home-based absolute", () => {
|
|
43
|
+
const saved = setWorkspaceRoot("~/myws");
|
|
44
|
+
expect(saved).toBe(path.join(homedir(), "myws"));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("resolveSpawnCwd", () => {
|
|
48
|
+
beforeEach(() => setWorkspaceRoot(path.join(tmp, "ws")));
|
|
49
|
+
|
|
50
|
+
it("empty input → workspace root", () => {
|
|
51
|
+
expect(resolveSpawnCwd("")).toBe(path.join(tmp, "ws"));
|
|
52
|
+
expect(resolveSpawnCwd(undefined)).toBe(path.join(tmp, "ws"));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("bare name → <workspace>/<name>", () => {
|
|
56
|
+
expect(resolveSpawnCwd("myproject")).toBe(path.join(tmp, "ws", "myproject"));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("absolute path → used as-is", () => {
|
|
60
|
+
expect(resolveSpawnCwd("/tmp/elsewhere")).toBe("/tmp/elsewhere");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("tilde path → home-based", () => {
|
|
64
|
+
expect(resolveSpawnCwd("~/docs")).toBe(path.join(homedir(), "docs"));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("a relative path with a separator is resolved, not joined to the workspace", () => {
|
|
68
|
+
expect(resolveSpawnCwd("a/b")).toBe(path.resolve("a/b"));
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { agentYesHome } from "./agentYesHome.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Machine-global agent-yes config (workspace root, etc.), stored alongside the
|
|
8
|
+
* pid index and serve token under `agentYesHome()`. Kept tiny and synchronous —
|
|
9
|
+
* it's read on the spawn hot path and written once during `ay setup`.
|
|
10
|
+
*
|
|
11
|
+
* The *workspace root* is the default directory new agents are spawned into when
|
|
12
|
+
* the console doesn't pass an explicit cwd. It defaults to the user's home dir so
|
|
13
|
+
* a non-engineer can just run agents in their files without knowing about paths.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface Config {
|
|
17
|
+
workspace?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function configPath(): string {
|
|
21
|
+
return path.join(agentYesHome(), "config.json");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readConfig(): Config {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(readFileSync(configPath(), "utf-8")) as Config;
|
|
27
|
+
} catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Expand a leading `~` (`~` or `~/x`) to an absolute home-based path. */
|
|
33
|
+
export function expandTilde(p: string): string {
|
|
34
|
+
const s = p.trim();
|
|
35
|
+
if (s === "~") return homedir();
|
|
36
|
+
if (s.startsWith("~/") || s.startsWith("~\\")) return path.join(homedir(), s.slice(2));
|
|
37
|
+
return s;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The configured workspace root (absolute), or the home dir if unset. */
|
|
41
|
+
export function getWorkspaceRoot(): string {
|
|
42
|
+
const w = readConfig().workspace;
|
|
43
|
+
return w && w.trim() ? w : homedir();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Persist the workspace root, tilde-expanded and resolved to an absolute path. */
|
|
47
|
+
export function setWorkspaceRoot(dir: string): string {
|
|
48
|
+
const abs = path.resolve(expandTilde(dir));
|
|
49
|
+
const cfg = readConfig();
|
|
50
|
+
cfg.workspace = abs;
|
|
51
|
+
mkdirSync(agentYesHome(), { recursive: true });
|
|
52
|
+
writeFileSync(configPath(), JSON.stringify(cfg, null, 2));
|
|
53
|
+
return abs;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a user-supplied spawn location to an absolute cwd:
|
|
58
|
+
* - empty → the workspace root
|
|
59
|
+
* - a bare name → `<workspace>/<name>` (so "myproject" lands under the root)
|
|
60
|
+
* - `~`-prefixed → home-based absolute
|
|
61
|
+
* - anything with a path separator → resolved as-is
|
|
62
|
+
*/
|
|
63
|
+
export function resolveSpawnCwd(input?: string): string {
|
|
64
|
+
const root = getWorkspaceRoot();
|
|
65
|
+
const v = (input ?? "").trim();
|
|
66
|
+
if (!v) return root;
|
|
67
|
+
if (v.startsWith("~")) return path.resolve(expandTilde(v));
|
|
68
|
+
if (v.includes("/") || v.includes("\\") || path.isAbsolute(v)) return path.resolve(v);
|
|
69
|
+
return path.join(root, v);
|
|
70
|
+
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import "./ts-mo_bB4au.js";
|
|
2
|
-
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-BhU9-zSi.js";
|
|
4
|
-
import "./pidStore-DBjlqzo8.js";
|
|
5
|
-
import "./globalPidIndex-yVd3mbsV.js";
|
|
6
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CXsHRSdB.js";
|
|
7
|
-
|
|
8
|
-
export { SUPPORTED_CLIS };
|