claude-yes 1.80.0 → 1.82.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-ujFlzMra.js → SUPPORTED_CLIS-WKiG4dyQ.js} +3 -3
- package/dist/cli.js +3 -3
- package/dist/index.js +2 -2
- package/dist/{subcommands-BVcxPfly.js → subcommands-eMrWDGMq.js} +86 -10
- package/dist/{ts-DJTdHpX6.js → ts-WV8trEPX.js} +2 -2
- package/dist/{versionChecker-iWnXmXoS.js → versionChecker-BVt2a2mL.js} +2 -2
- package/package.json +1 -1
- package/ts/subcommands.spec.ts +1 -1
- package/ts/subcommands.ts +115 -9
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-WV8trEPX.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-
|
|
3
|
+
import "./versionChecker-BVt2a2mL.js";
|
|
4
4
|
import "./pidStore-C1JXxoPi.js";
|
|
5
5
|
import "./globalPidIndex-Cr-g75QF.js";
|
|
6
6
|
|
|
@@ -9,4 +9,4 @@ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
|
|
|
9
9
|
|
|
10
10
|
//#endregion
|
|
11
11
|
export { SUPPORTED_CLIS };
|
|
12
|
-
//# sourceMappingURL=SUPPORTED_CLIS-
|
|
12
|
+
//# sourceMappingURL=SUPPORTED_CLIS-WKiG4dyQ.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-BVt2a2mL.js";
|
|
4
4
|
import { argv } from "process";
|
|
5
5
|
import { execFileSync, spawn } from "child_process";
|
|
6
6
|
import ms from "ms";
|
|
@@ -475,7 +475,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
475
475
|
}
|
|
476
476
|
}
|
|
477
477
|
{
|
|
478
|
-
const { isSubcommand, runSubcommand } = await import("./subcommands-
|
|
478
|
+
const { isSubcommand, runSubcommand } = await import("./subcommands-eMrWDGMq.js");
|
|
479
479
|
if (isSubcommand(process.argv[2])) {
|
|
480
480
|
const code = await runSubcommand(process.argv);
|
|
481
481
|
process.exit(code ?? 0);
|
|
@@ -504,7 +504,7 @@ if (config.useRust) {
|
|
|
504
504
|
}
|
|
505
505
|
}
|
|
506
506
|
if (rustBinary) {
|
|
507
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
507
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-WKiG4dyQ.js");
|
|
508
508
|
const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
|
|
509
509
|
if (config.verbose) {
|
|
510
510
|
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-WV8trEPX.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-
|
|
3
|
+
import "./versionChecker-BVt2a2mL.js";
|
|
4
4
|
import "./pidStore-C1JXxoPi.js";
|
|
5
5
|
import "./globalPidIndex-Cr-g75QF.js";
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-B9h0djqx.js";
|
|
2
2
|
import { r as readGlobalPids } from "./globalPidIndex-Cr-g75QF.js";
|
|
3
|
-
import { readFile, stat } from "fs/promises";
|
|
3
|
+
import { appendFile, mkdir, readFile, stat, writeFile } from "fs/promises";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import path from "path";
|
|
6
6
|
|
|
@@ -17,6 +17,47 @@ import path from "path";
|
|
|
17
17
|
* Returns null when argv[2] is not a known subcommand so cli.ts falls through
|
|
18
18
|
* to the normal agent-spawning flow.
|
|
19
19
|
*/
|
|
20
|
+
function notesPath() {
|
|
21
|
+
const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
22
|
+
return path.join(dir, "notes.jsonl");
|
|
23
|
+
}
|
|
24
|
+
async function readNotes() {
|
|
25
|
+
let raw;
|
|
26
|
+
try {
|
|
27
|
+
raw = await readFile(notesPath(), "utf-8");
|
|
28
|
+
} catch {
|
|
29
|
+
return /* @__PURE__ */ new Map();
|
|
30
|
+
}
|
|
31
|
+
const map = /* @__PURE__ */ new Map();
|
|
32
|
+
for (const line of raw.split("\n")) {
|
|
33
|
+
const t = line.trim();
|
|
34
|
+
if (!t) continue;
|
|
35
|
+
try {
|
|
36
|
+
const { pid, note } = JSON.parse(t);
|
|
37
|
+
if (typeof pid === "number") if (note) map.set(pid, note);
|
|
38
|
+
else map.delete(pid);
|
|
39
|
+
} catch {}
|
|
40
|
+
}
|
|
41
|
+
return map;
|
|
42
|
+
}
|
|
43
|
+
async function writeNote(pid, note) {
|
|
44
|
+
const p = notesPath();
|
|
45
|
+
await mkdir(path.dirname(p), { recursive: true });
|
|
46
|
+
await appendFile(p, JSON.stringify({
|
|
47
|
+
pid,
|
|
48
|
+
note,
|
|
49
|
+
updated_at: Date.now()
|
|
50
|
+
}) + "\n");
|
|
51
|
+
}
|
|
52
|
+
async function compactNotes() {
|
|
53
|
+
const map = await readNotes();
|
|
54
|
+
const lines = Array.from(map.entries()).map(([pid, note]) => JSON.stringify({
|
|
55
|
+
pid,
|
|
56
|
+
note,
|
|
57
|
+
updated_at: Date.now()
|
|
58
|
+
})).join("\n");
|
|
59
|
+
await writeFile(notesPath(), lines ? lines + "\n" : "");
|
|
60
|
+
}
|
|
20
61
|
/**
|
|
21
62
|
* Read the per-cwd TS PidStore JSONL and convert to the global record shape,
|
|
22
63
|
* so pre-existing TS agents that were spawned before the global-index mirror
|
|
@@ -82,7 +123,8 @@ const SUBCOMMANDS = new Set([
|
|
|
82
123
|
"tail",
|
|
83
124
|
"head",
|
|
84
125
|
"send",
|
|
85
|
-
"restart"
|
|
126
|
+
"restart",
|
|
127
|
+
"note"
|
|
86
128
|
]);
|
|
87
129
|
function isSubcommand(name) {
|
|
88
130
|
return !!name && SUBCOMMANDS.has(name);
|
|
@@ -106,6 +148,7 @@ async function runSubcommand(argv) {
|
|
|
106
148
|
case "head": return await cmdRead(rest, { mode: "head" });
|
|
107
149
|
case "send": return await cmdSend(rest);
|
|
108
150
|
case "restart": return await cmdRestart(rest);
|
|
151
|
+
case "note": return await cmdNote(rest);
|
|
109
152
|
default: return null;
|
|
110
153
|
}
|
|
111
154
|
} catch (err) {
|
|
@@ -220,6 +263,7 @@ async function cmdLs(rest) {
|
|
|
220
263
|
const fixedWidth = widths.pid + widths.cli + widths.status + widths.age + widths.cwd + 10;
|
|
221
264
|
const promptBudget = Math.max(20, termWidth - fixedWidth - 1);
|
|
222
265
|
const IDLE_THRESHOLD_MS = 60 * 1e3;
|
|
266
|
+
const notes = await readNotes();
|
|
223
267
|
const rows = await Promise.all(records.map(async (r) => {
|
|
224
268
|
let displayStatus;
|
|
225
269
|
if (!isPidAlive(r.pid)) displayStatus = "stopped";
|
|
@@ -227,13 +271,16 @@ async function cmdLs(rest) {
|
|
|
227
271
|
const mtime = await stat(r.log_file).then((s) => s.mtimeMs).catch(() => null);
|
|
228
272
|
displayStatus = mtime !== null && Date.now() - mtime > IDLE_THRESHOLD_MS ? "idle" : "active";
|
|
229
273
|
} else displayStatus = "active";
|
|
274
|
+
const label = truncate(notes.get(r.pid) ?? r.prompt ?? "", promptBudget);
|
|
275
|
+
const hasNote = notes.has(r.pid);
|
|
230
276
|
return {
|
|
231
277
|
pid: String(r.pid),
|
|
232
278
|
cli: r.cli,
|
|
233
279
|
status: displayStatus,
|
|
234
280
|
age: humanizeAge(Date.now() - r.started_at),
|
|
235
281
|
cwd: shortenPath(r.cwd),
|
|
236
|
-
|
|
282
|
+
label,
|
|
283
|
+
hasNote,
|
|
237
284
|
_alive: displayStatus !== "stopped"
|
|
238
285
|
};
|
|
239
286
|
}));
|
|
@@ -243,7 +290,7 @@ async function cmdLs(rest) {
|
|
|
243
290
|
"STATUS".padEnd(widths.status),
|
|
244
291
|
"AGE".padEnd(widths.age),
|
|
245
292
|
"CWD".padEnd(widths.cwd),
|
|
246
|
-
"PROMPT"
|
|
293
|
+
"NOTE/PROMPT"
|
|
247
294
|
].join(" ") + "\n";
|
|
248
295
|
process.stdout.write(header);
|
|
249
296
|
for (const r of rows) process.stdout.write([
|
|
@@ -252,7 +299,7 @@ async function cmdLs(rest) {
|
|
|
252
299
|
r.status.padEnd(widths.status),
|
|
253
300
|
r.age.padEnd(widths.age),
|
|
254
301
|
r.cwd.padEnd(widths.cwd),
|
|
255
|
-
r.
|
|
302
|
+
r.hasNote ? `* ${r.label}` : r.label
|
|
256
303
|
].join(" ") + "\n");
|
|
257
304
|
if (!opts.json && rows.length > 0) {
|
|
258
305
|
const alive = rows.find((r) => r._alive);
|
|
@@ -263,6 +310,7 @@ async function cmdLs(rest) {
|
|
|
263
310
|
hints.push(` cy tail -f ${alive.pid} # follow live output\n`);
|
|
264
311
|
hints.push(` cy send ${alive.pid} "next: ..." # send a prompt\n`);
|
|
265
312
|
hints.push(` cy send ${alive.pid} "" --code=ctrl-c # interrupt\n`);
|
|
313
|
+
hints.push(` cy note ${alive.pid} "what it's doing" # set a note\n`);
|
|
266
314
|
}
|
|
267
315
|
if (stopped) hints.push(` cy restart ${stopped.pid} # restart stopped agent\n`);
|
|
268
316
|
if (!alive && !stopped) hints.push(` cy ls --all # show exited agents\n`);
|
|
@@ -310,7 +358,9 @@ async function cmdRead(rest, { mode }) {
|
|
|
310
358
|
mode,
|
|
311
359
|
n
|
|
312
360
|
});
|
|
313
|
-
|
|
361
|
+
const noteLabel = (await readNotes()).get(record.pid);
|
|
362
|
+
const header = noteLabel ? `[pid ${record.pid} ${shortenPath(record.cwd)} * ${noteLabel}]` : `[pid ${record.pid} ${shortenPath(record.cwd)}]`;
|
|
363
|
+
process.stderr.write(header + "\n");
|
|
314
364
|
process.stdout.write(rendered);
|
|
315
365
|
if (!rendered.endsWith("\n")) process.stdout.write("\n");
|
|
316
366
|
if (follow) {
|
|
@@ -380,13 +430,18 @@ async function cmdSend(rest) {
|
|
|
380
430
|
const { flags, positional } = parseArgs(rest);
|
|
381
431
|
const opts = commonOpts(flags);
|
|
382
432
|
const keyword = positional[0];
|
|
383
|
-
const
|
|
384
|
-
if (!keyword) throw new Error("usage: cy send <keyword> <msg
|
|
433
|
+
const rawMessage = positional.slice(1).join(" ");
|
|
434
|
+
if (!keyword) throw new Error("usage: cy send <keyword> <msg|-> [--code=enter|esc|ctrl-c|ctrl-y|tab|none]");
|
|
385
435
|
const trailing = controlCodeFromName(typeof flags.code === "string" ? flags.code.toLowerCase() : "enter");
|
|
386
436
|
const record = await resolveOne(keyword, opts);
|
|
387
437
|
const fifoPath = record.fifo_file;
|
|
388
438
|
if (!fifoPath) throw new Error(`pid ${record.pid}: no fifo_file recorded — agent was not started with --stdpush (or was spawned by Rust which doesn't yet support FIFO IPC; see ROADMAP item 10)`);
|
|
389
|
-
|
|
439
|
+
let body;
|
|
440
|
+
if (rawMessage === "-") {
|
|
441
|
+
const chunks = [];
|
|
442
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
443
|
+
body = Buffer.concat(chunks).toString("utf-8").trimEnd();
|
|
444
|
+
} else body = rawMessage;
|
|
390
445
|
if (body && trailing) {
|
|
391
446
|
await writeToIpc(fifoPath, body);
|
|
392
447
|
await new Promise((r) => setTimeout(r, 200));
|
|
@@ -476,7 +531,28 @@ async function cmdRestart(rest) {
|
|
|
476
531
|
process.stderr.write(`\n cy tail ${proc.pid} # watch output\n cy ls # list all agents\n`);
|
|
477
532
|
return 0;
|
|
478
533
|
}
|
|
534
|
+
async function cmdNote(rest) {
|
|
535
|
+
const { flags, positional } = parseArgs(rest);
|
|
536
|
+
const opts = commonOpts(flags);
|
|
537
|
+
const keyword = positional[0];
|
|
538
|
+
const note = positional.slice(1).join(" ");
|
|
539
|
+
if (!keyword) throw new Error("usage: cy note <keyword> [\"note text\"] (omit text to clear)");
|
|
540
|
+
const record = await resolveOne(keyword, {
|
|
541
|
+
...opts,
|
|
542
|
+
all: true
|
|
543
|
+
});
|
|
544
|
+
if (!note) {
|
|
545
|
+
await writeNote(record.pid, "");
|
|
546
|
+
await compactNotes();
|
|
547
|
+
process.stdout.write(`cleared note for pid ${record.pid}\n`);
|
|
548
|
+
return 0;
|
|
549
|
+
}
|
|
550
|
+
await writeNote(record.pid, note);
|
|
551
|
+
process.stdout.write(`note set for pid ${record.pid}: ${note}\n`);
|
|
552
|
+
process.stderr.write(`\n cy ls # see updated note in list\n`);
|
|
553
|
+
return 0;
|
|
554
|
+
}
|
|
479
555
|
|
|
480
556
|
//#endregion
|
|
481
557
|
export { isSubcommand, runSubcommand };
|
|
482
|
-
//# sourceMappingURL=subcommands-
|
|
558
|
+
//# sourceMappingURL=subcommands-eMrWDGMq.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-BVt2a2mL.js";
|
|
3
3
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-C22d9SRJ.js";
|
|
4
4
|
import { t as PidStore } from "./pidStore-C1JXxoPi.js";
|
|
5
5
|
import { arch, platform } from "process";
|
|
@@ -1679,4 +1679,4 @@ function sleep(ms) {
|
|
|
1679
1679
|
|
|
1680
1680
|
//#endregion
|
|
1681
1681
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1682
|
-
//# sourceMappingURL=ts-
|
|
1682
|
+
//# sourceMappingURL=ts-WV8trEPX.js.map
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
|
|
8
8
|
//#region package.json
|
|
9
9
|
var name = "claude-yes";
|
|
10
|
-
var version = "1.
|
|
10
|
+
var version = "1.82.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-BVt2a2mL.js.map
|
package/package.json
CHANGED
package/ts/subcommands.spec.ts
CHANGED
|
@@ -307,7 +307,7 @@ describe("subcommands.cmdLs human table", () => {
|
|
|
307
307
|
} finally {
|
|
308
308
|
cap.restore();
|
|
309
309
|
}
|
|
310
|
-
expect(cap.text).toMatch(/PID\s+CLI\s+STATUS\s+AGE\s+CWD\s+PROMPT/);
|
|
310
|
+
expect(cap.text).toMatch(/PID\s+CLI\s+STATUS\s+AGE\s+CWD\s+NOTE\/PROMPT/);
|
|
311
311
|
expect(cap.text).toMatch(new RegExp(`${process.pid}\\s`));
|
|
312
312
|
expect(cap.text).toMatch(/claude/);
|
|
313
313
|
expect(cap.text).toMatch(/table format test/);
|
package/ts/subcommands.ts
CHANGED
|
@@ -11,11 +11,58 @@
|
|
|
11
11
|
* to the normal agent-spawning flow.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { readFile, stat } from "fs/promises";
|
|
14
|
+
import { appendFile, mkdir, readFile, stat, writeFile } from "fs/promises";
|
|
15
15
|
import { homedir } from "os";
|
|
16
16
|
import path from "path";
|
|
17
17
|
import { type GlobalPidRecord, readGlobalPids } from "./globalPidIndex.ts";
|
|
18
18
|
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// notes store (~/.agent-yes/notes.jsonl)
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
function notesPath(): string {
|
|
24
|
+
const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
25
|
+
return path.join(dir, "notes.jsonl");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function readNotes(): Promise<Map<number, string>> {
|
|
29
|
+
let raw: string;
|
|
30
|
+
try {
|
|
31
|
+
raw = await readFile(notesPath(), "utf-8");
|
|
32
|
+
} catch {
|
|
33
|
+
return new Map();
|
|
34
|
+
}
|
|
35
|
+
const map = new Map<number, string>();
|
|
36
|
+
for (const line of raw.split("\n")) {
|
|
37
|
+
const t = line.trim();
|
|
38
|
+
if (!t) continue;
|
|
39
|
+
try {
|
|
40
|
+
const { pid, note } = JSON.parse(t);
|
|
41
|
+
if (typeof pid === "number") {
|
|
42
|
+
if (note) map.set(pid, note);
|
|
43
|
+
else map.delete(pid);
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
/* skip */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return map;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function writeNote(pid: number, note: string): Promise<void> {
|
|
53
|
+
const p = notesPath();
|
|
54
|
+
await mkdir(path.dirname(p), { recursive: true });
|
|
55
|
+
await appendFile(p, JSON.stringify({ pid, note, updated_at: Date.now() }) + "\n");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function compactNotes(): Promise<void> {
|
|
59
|
+
const map = await readNotes();
|
|
60
|
+
const lines = Array.from(map.entries())
|
|
61
|
+
.map(([pid, note]) => JSON.stringify({ pid, note, updated_at: Date.now() }))
|
|
62
|
+
.join("\n");
|
|
63
|
+
await writeFile(notesPath(), lines ? lines + "\n" : "");
|
|
64
|
+
}
|
|
65
|
+
|
|
19
66
|
/**
|
|
20
67
|
* Read the per-cwd TS PidStore JSONL and convert to the global record shape,
|
|
21
68
|
* so pre-existing TS agents that were spawned before the global-index mirror
|
|
@@ -76,7 +123,18 @@ function mergeRecords(...buckets: GlobalPidRecord[][]): GlobalPidRecord[] {
|
|
|
76
123
|
return Array.from(out.values());
|
|
77
124
|
}
|
|
78
125
|
|
|
79
|
-
const SUBCOMMANDS = new Set([
|
|
126
|
+
const SUBCOMMANDS = new Set([
|
|
127
|
+
"ls",
|
|
128
|
+
"list",
|
|
129
|
+
"ps",
|
|
130
|
+
"read",
|
|
131
|
+
"cat",
|
|
132
|
+
"tail",
|
|
133
|
+
"head",
|
|
134
|
+
"send",
|
|
135
|
+
"restart",
|
|
136
|
+
"note",
|
|
137
|
+
]);
|
|
80
138
|
|
|
81
139
|
export function isSubcommand(name: string | undefined): boolean {
|
|
82
140
|
return !!name && SUBCOMMANDS.has(name);
|
|
@@ -109,6 +167,8 @@ export async function runSubcommand(argv: string[]): Promise<number | null> {
|
|
|
109
167
|
return await cmdSend(rest);
|
|
110
168
|
case "restart":
|
|
111
169
|
return await cmdRestart(rest);
|
|
170
|
+
case "note":
|
|
171
|
+
return await cmdNote(rest);
|
|
112
172
|
default:
|
|
113
173
|
return null;
|
|
114
174
|
}
|
|
@@ -300,6 +360,7 @@ async function cmdLs(rest: string[]): Promise<number> {
|
|
|
300
360
|
const promptBudget = Math.max(20, termWidth - fixedWidth - 1);
|
|
301
361
|
|
|
302
362
|
const IDLE_THRESHOLD_MS = 60 * 1000;
|
|
363
|
+
const notes = await readNotes();
|
|
303
364
|
const rows = await Promise.all(
|
|
304
365
|
records.map(async (r) => {
|
|
305
366
|
let displayStatus: string;
|
|
@@ -314,13 +375,16 @@ async function cmdLs(rest: string[]): Promise<number> {
|
|
|
314
375
|
} else {
|
|
315
376
|
displayStatus = "active";
|
|
316
377
|
}
|
|
378
|
+
const label = truncate(notes.get(r.pid) ?? r.prompt ?? "", promptBudget);
|
|
379
|
+
const hasNote = notes.has(r.pid);
|
|
317
380
|
return {
|
|
318
381
|
pid: String(r.pid),
|
|
319
382
|
cli: r.cli,
|
|
320
383
|
status: displayStatus,
|
|
321
384
|
age: humanizeAge(Date.now() - r.started_at),
|
|
322
385
|
cwd: shortenPath(r.cwd),
|
|
323
|
-
|
|
386
|
+
label,
|
|
387
|
+
hasNote,
|
|
324
388
|
_alive: displayStatus !== "stopped",
|
|
325
389
|
};
|
|
326
390
|
}),
|
|
@@ -333,7 +397,7 @@ async function cmdLs(rest: string[]): Promise<number> {
|
|
|
333
397
|
"STATUS".padEnd(widths.status),
|
|
334
398
|
"AGE".padEnd(widths.age),
|
|
335
399
|
"CWD".padEnd(widths.cwd),
|
|
336
|
-
"PROMPT",
|
|
400
|
+
"NOTE/PROMPT",
|
|
337
401
|
].join(" ") + "\n";
|
|
338
402
|
process.stdout.write(header);
|
|
339
403
|
|
|
@@ -345,7 +409,7 @@ async function cmdLs(rest: string[]): Promise<number> {
|
|
|
345
409
|
r.status.padEnd(widths.status),
|
|
346
410
|
r.age.padEnd(widths.age),
|
|
347
411
|
r.cwd.padEnd(widths.cwd),
|
|
348
|
-
r.
|
|
412
|
+
r.hasNote ? `* ${r.label}` : r.label,
|
|
349
413
|
].join(" ") + "\n",
|
|
350
414
|
);
|
|
351
415
|
}
|
|
@@ -359,6 +423,7 @@ async function cmdLs(rest: string[]): Promise<number> {
|
|
|
359
423
|
hints.push(` cy tail -f ${alive.pid} # follow live output\n`);
|
|
360
424
|
hints.push(` cy send ${alive.pid} "next: ..." # send a prompt\n`);
|
|
361
425
|
hints.push(` cy send ${alive.pid} "" --code=ctrl-c # interrupt\n`);
|
|
426
|
+
hints.push(` cy note ${alive.pid} "what it's doing" # set a note\n`);
|
|
362
427
|
}
|
|
363
428
|
if (stopped) {
|
|
364
429
|
hints.push(` cy restart ${stopped.pid} # restart stopped agent\n`);
|
|
@@ -433,7 +498,12 @@ async function cmdRead(rest: string[], { mode }: ReadOpts): Promise<number> {
|
|
|
433
498
|
|
|
434
499
|
const buf = await readFile(logPath);
|
|
435
500
|
const rendered = await renderRawLog(buf, { mode, n });
|
|
436
|
-
|
|
501
|
+
const notes = await readNotes();
|
|
502
|
+
const noteLabel = notes.get(record.pid);
|
|
503
|
+
const header = noteLabel
|
|
504
|
+
? `[pid ${record.pid} ${shortenPath(record.cwd)} * ${noteLabel}]`
|
|
505
|
+
: `[pid ${record.pid} ${shortenPath(record.cwd)}]`;
|
|
506
|
+
process.stderr.write(header + "\n");
|
|
437
507
|
process.stdout.write(rendered);
|
|
438
508
|
if (!rendered.endsWith("\n")) process.stdout.write("\n");
|
|
439
509
|
|
|
@@ -526,10 +596,10 @@ async function cmdSend(rest: string[]): Promise<number> {
|
|
|
526
596
|
const { flags, positional } = parseArgs(rest);
|
|
527
597
|
const opts = commonOpts(flags);
|
|
528
598
|
const keyword = positional[0];
|
|
529
|
-
const
|
|
599
|
+
const rawMessage = positional.slice(1).join(" ");
|
|
530
600
|
|
|
531
601
|
if (!keyword)
|
|
532
|
-
throw new Error("usage: cy send <keyword> <msg
|
|
602
|
+
throw new Error("usage: cy send <keyword> <msg|-> [--code=enter|esc|ctrl-c|ctrl-y|tab|none]");
|
|
533
603
|
|
|
534
604
|
const codeName = typeof flags.code === "string" ? flags.code.toLowerCase() : "enter";
|
|
535
605
|
const trailing = controlCodeFromName(codeName);
|
|
@@ -542,7 +612,15 @@ async function cmdSend(rest: string[]): Promise<number> {
|
|
|
542
612
|
);
|
|
543
613
|
}
|
|
544
614
|
|
|
545
|
-
|
|
615
|
+
let body: string;
|
|
616
|
+
if (rawMessage === "-") {
|
|
617
|
+
const chunks: Buffer[] = [];
|
|
618
|
+
for await (const chunk of process.stdin) chunks.push(chunk as Buffer);
|
|
619
|
+
body = Buffer.concat(chunks).toString("utf-8").trimEnd();
|
|
620
|
+
} else {
|
|
621
|
+
body = rawMessage;
|
|
622
|
+
}
|
|
623
|
+
|
|
546
624
|
if (body && trailing) {
|
|
547
625
|
await writeToIpc(fifoPath, body);
|
|
548
626
|
await new Promise((r) => setTimeout(r, 200));
|
|
@@ -657,3 +735,31 @@ async function cmdRestart(rest: string[]): Promise<number> {
|
|
|
657
735
|
);
|
|
658
736
|
return 0;
|
|
659
737
|
}
|
|
738
|
+
|
|
739
|
+
// ---------------------------------------------------------------------------
|
|
740
|
+
// cy note
|
|
741
|
+
// ---------------------------------------------------------------------------
|
|
742
|
+
|
|
743
|
+
async function cmdNote(rest: string[]): Promise<number> {
|
|
744
|
+
const { flags, positional } = parseArgs(rest);
|
|
745
|
+
const opts = commonOpts(flags);
|
|
746
|
+
const keyword = positional[0];
|
|
747
|
+
const note = positional.slice(1).join(" ");
|
|
748
|
+
|
|
749
|
+
if (!keyword) throw new Error('usage: cy note <keyword> ["note text"] (omit text to clear)');
|
|
750
|
+
|
|
751
|
+
const record = await resolveOne(keyword, { ...opts, all: true });
|
|
752
|
+
|
|
753
|
+
if (!note) {
|
|
754
|
+
// clear
|
|
755
|
+
await writeNote(record.pid, "");
|
|
756
|
+
await compactNotes();
|
|
757
|
+
process.stdout.write(`cleared note for pid ${record.pid}\n`);
|
|
758
|
+
return 0;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
await writeNote(record.pid, note);
|
|
762
|
+
process.stdout.write(`note set for pid ${record.pid}: ${note}\n`);
|
|
763
|
+
process.stderr.write(`\n cy ls # see updated note in list\n`);
|
|
764
|
+
return 0;
|
|
765
|
+
}
|