agent-yes 1.271.0 → 1.272.0-beta.658.1
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-3wwg1X8T.js → SUPPORTED_CLIS-DNNdMJN_.js} +2 -2
- package/dist/{SUPPORTED_CLIS-lreAQcHS.js → SUPPORTED_CLIS-tpJdgRCT.js} +3 -3
- package/dist/{agentShare-DnewJUOO.js → agentShare-DJDnjvQc.js} +3 -3
- package/dist/{callback-Besk3KFx.js → callback-Dc1PCZUk.js} +3 -3
- package/dist/{callback-D521tLFf.js → callback-pDrrtfQ8.js} +3 -3
- package/dist/cli.js +5 -5
- package/dist/{cmdPs-4An2s2t8.js → cmdPs-YBWZA9q_.js} +3 -3
- package/dist/index.js +2 -2
- package/dist/{notifyDaemon-kIOLWrEI.js → notifyDaemon-ByJtcbbX.js} +3 -3
- package/dist/{parentPingLoop-D2A9Fkhf.js → parentPingLoop-D1oxgeES.js} +2 -2
- package/dist/{remotes-IzQHupeo.js → remotes-BL2MegXx.js} +16 -8
- package/dist/{remotes-BiftUp09.js → remotes-CNNWole7.js} +1 -1
- package/dist/{rustBinary-BK03gMMg.js → rustBinary-DPRR_QOA.js} +2 -2
- package/dist/{schedule-BdK4RVQ5.js → schedule-B8S10ci8.js} +4 -4
- package/dist/{serve-XWSfUL8i.js → serve-CcVhTYIX.js} +18 -18
- package/dist/{setup-B-Cui8R6.js → setup-CJGkmk3P.js} +2 -2
- package/dist/{subcommands-ByZspogJ.js → subcommands-C0-NKq4X.js} +2 -2
- package/dist/{subcommands-C3NO344d.js → subcommands-DX0iQzwD.js} +24 -24
- package/dist/{terminal-BxWNOBW4.js → terminal-CCLw4qIt.js} +2 -2
- package/dist/trayApp-10o8DC7r.js +5 -0
- package/dist/{trayApp-CcQDIINw.js → trayApp-BxrNX0KY.js} +2 -2
- package/dist/{ts-BG759sO1.js → ts-C5yjBnoI.js} +3 -3
- package/dist/{versionChecker-DCtcFwZ7.js → versionChecker-DHrDPEw3.js} +2 -2
- package/dist/{widget-DobxsxXa.js → widget-Bf-hAxpl.js} +3 -3
- package/dist/{ws-Bk2cJphr.js → ws-CWMIHaJ8.js} +3 -3
- package/dist/{ws-DO1UpPDw.js → ws-KZfHmxtS.js} +2 -2
- package/lab/ui/lab/index.md +16 -0
- package/lab/ui/lab/posts/2026-08-11-slack-term-safe-writes.md +240 -0
- package/package.json +1 -1
- package/ts/remotes.ts +24 -7
- package/ts/subcommands.ts +9 -9
- package/dist/trayApp-XJit7gRr.js +0 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-C5yjBnoI.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-DNNdMJN_.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-DHrDPEw3.js";
|
|
3
|
+
import "./ts-C5yjBnoI.js";
|
|
4
4
|
import "./todoAutomation-BETGOik9.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-Dq4KY2IV.js";
|
|
7
7
|
import "./pidStore-DJqSZPJi.js";
|
|
8
8
|
import "./messageLog-BYFwioFY.js";
|
|
9
9
|
import "./todoStore-Wk8U4zJ8.js";
|
|
10
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
10
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DNNdMJN_.js";
|
|
11
11
|
|
|
12
12
|
export { SUPPORTED_CLIS };
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-OLfcNxiv.js";
|
|
5
5
|
import "./configShared-DYxlvrH0.js";
|
|
6
|
-
import { B as resolveOne } from "./subcommands-
|
|
6
|
+
import { B as resolveOne } from "./subcommands-DX0iQzwD.js";
|
|
7
7
|
import "./notifyStore-Dus2D1XA.js";
|
|
8
8
|
import "./webrtcLink-B72AQ2eb.js";
|
|
9
|
-
import "./remotes-
|
|
9
|
+
import "./remotes-BL2MegXx.js";
|
|
10
10
|
import { a as startShare } from "./share-RgJUhzqG.js";
|
|
11
11
|
|
|
12
12
|
//#region ts/agentShare.ts
|
|
@@ -230,4 +230,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
|
|
|
230
230
|
|
|
231
231
|
//#endregion
|
|
232
232
|
export { createScopedShare, listShares, revokeAllShares, revokeShare };
|
|
233
|
-
//# sourceMappingURL=agentShare-
|
|
233
|
+
//# sourceMappingURL=agentShare-DJDnjvQc.js.map
|
|
@@ -3,11 +3,11 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-OLfcNxiv.js";
|
|
5
5
|
import "./configShared-DYxlvrH0.js";
|
|
6
|
-
import "./subcommands-
|
|
6
|
+
import "./subcommands-DX0iQzwD.js";
|
|
7
7
|
import "./notifyStore-Dus2D1XA.js";
|
|
8
8
|
import "./webrtcLink-B72AQ2eb.js";
|
|
9
|
-
import "./remotes-
|
|
9
|
+
import "./remotes-BL2MegXx.js";
|
|
10
10
|
import "./callbackCore-Bbe7rpN2.js";
|
|
11
|
-
import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-
|
|
11
|
+
import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-pDrrtfQ8.js";
|
|
12
12
|
|
|
13
13
|
export { cmdCallback };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
2
|
-
import { B as resolveOne } from "./subcommands-
|
|
2
|
+
import { B as resolveOne } from "./subcommands-DX0iQzwD.js";
|
|
3
3
|
import { a as mintCapability, o as parseExpires } from "./callbackCore-Bbe7rpN2.js";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
import { chmodSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
|
|
|
72
72
|
if (flag) return flag;
|
|
73
73
|
if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
|
|
74
74
|
try {
|
|
75
|
-
const { resolveLocalServeUrl } = await import("./serve-
|
|
75
|
+
const { resolveLocalServeUrl } = await import("./serve-CcVhTYIX.js");
|
|
76
76
|
const url = await resolveLocalServeUrl();
|
|
77
77
|
if (url) return url;
|
|
78
78
|
} catch {}
|
|
@@ -187,4 +187,4 @@ async function cmdCallback(rest) {
|
|
|
187
187
|
|
|
188
188
|
//#endregion
|
|
189
189
|
export { loadOrCreateCallbackSecret as i, isCallbackRevoked as n, loadCallbackSecretReadOnly as r, cmdCallback as t };
|
|
190
|
-
//# sourceMappingURL=callback-
|
|
190
|
+
//# sourceMappingURL=callback-pDrrtfQ8.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
|
|
3
3
|
import { n as logger } from "./logger-CDIsZ-Pp.js";
|
|
4
|
-
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-
|
|
5
|
-
import { r as getRustBinary } from "./rustBinary-
|
|
4
|
+
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-DHrDPEw3.js";
|
|
5
|
+
import { r as getRustBinary } from "./rustBinary-DPRR_QOA.js";
|
|
6
6
|
import { argv } from "process";
|
|
7
7
|
import { spawn } from "child_process";
|
|
8
8
|
import ms from "ms";
|
|
@@ -295,7 +295,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
295
295
|
const rawArg = process.argv[2];
|
|
296
296
|
const managerCommands = !invokedCliName(process.argv);
|
|
297
297
|
const isHelpFlag = rawArg === "-h" || rawArg === "--help";
|
|
298
|
-
const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken, isBareManagerInvocation } = await import("./subcommands-
|
|
298
|
+
const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken, isBareManagerInvocation } = await import("./subcommands-C0-NKq4X.js");
|
|
299
299
|
if (isHelpFlag && process.argv.length === 3) {
|
|
300
300
|
await cmdHelp(managerCommands);
|
|
301
301
|
process.exit(0);
|
|
@@ -309,7 +309,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
309
309
|
process.exit(code ?? 0);
|
|
310
310
|
}
|
|
311
311
|
{
|
|
312
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
312
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-tpJdgRCT.js");
|
|
313
313
|
if (isUnknownManagerToken(rawArg, managerCommands, SUPPORTED_CLIS)) {
|
|
314
314
|
process.stderr.write(`ay: unknown subcommand or CLI '${rawArg}'.\n See 'ay help' for subcommands. To run an agent, name a CLI:\n 'ay <cli> …' (e.g. 'ay claude …') or 'ay --cli <cli> …'.\n`);
|
|
315
315
|
process.exit(1);
|
|
@@ -360,7 +360,7 @@ if (config.useRust) {
|
|
|
360
360
|
}
|
|
361
361
|
}
|
|
362
362
|
if (rustBinary) {
|
|
363
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
363
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-tpJdgRCT.js");
|
|
364
364
|
const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
|
|
365
365
|
if (config.verbose) {
|
|
366
366
|
console.log(`[rust] Using binary: ${rustBinary}`);
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-OLfcNxiv.js";
|
|
5
5
|
import "./configShared-DYxlvrH0.js";
|
|
6
|
-
import { O as listRecords, d as deriveLiveState, et as buildAgentForest, tt as flattenForest } from "./subcommands-
|
|
6
|
+
import { O as listRecords, d as deriveLiveState, et as buildAgentForest, tt as flattenForest } from "./subcommands-DX0iQzwD.js";
|
|
7
7
|
import "./notifyStore-Dus2D1XA.js";
|
|
8
8
|
import "./webrtcLink-B72AQ2eb.js";
|
|
9
|
-
import "./remotes-
|
|
9
|
+
import "./remotes-BL2MegXx.js";
|
|
10
10
|
import yargs from "yargs";
|
|
11
11
|
import { execFile } from "node:child_process";
|
|
12
12
|
import { readFileSync } from "node:fs";
|
|
@@ -574,4 +574,4 @@ function readPpidSync(pid) {
|
|
|
574
574
|
|
|
575
575
|
//#endregion
|
|
576
576
|
export { cmdPs };
|
|
577
|
-
//# sourceMappingURL=cmdPs-
|
|
577
|
+
//# sourceMappingURL=cmdPs-YBWZA9q_.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-
|
|
2
|
+
import "./versionChecker-DHrDPEw3.js";
|
|
3
|
+
import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-C5yjBnoI.js";
|
|
4
4
|
import { a as renderTree, c as describeBlock, i as renderDigest, l as monitorHint, o as unblockedTasks, r as openBlockers, t as reconcileTodos, u as removeControlCharacters } from "./todoAutomation-BETGOik9.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-Dq4KY2IV.js";
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-OLfcNxiv.js";
|
|
5
5
|
import "./configShared-DYxlvrH0.js";
|
|
6
|
-
import { L as renderLogTailLines, O as listRecords, d as deriveLiveState, x as isPidAlive } from "./subcommands-
|
|
6
|
+
import { L as renderLogTailLines, O as listRecords, d as deriveLiveState, x as isPidAlive } from "./subcommands-DX0iQzwD.js";
|
|
7
7
|
import { f as readInbox, g as daemonLockOwnerPath, h as daemonLockDir, i as gcInboxes, l as listInboxParents, m as shouldStealLock, n as appendEvent, s as hostId, u as liveWatchers, x as notifyDir } from "./notifyStore-Dus2D1XA.js";
|
|
8
8
|
import "./webrtcLink-B72AQ2eb.js";
|
|
9
|
-
import "./remotes-
|
|
9
|
+
import "./remotes-BL2MegXx.js";
|
|
10
10
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
12
|
import { execFile, execFileSync } from "node:child_process";
|
|
@@ -863,4 +863,4 @@ async function ensureDaemon() {
|
|
|
863
863
|
|
|
864
864
|
//#endregion
|
|
865
865
|
export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
|
|
866
|
-
//# sourceMappingURL=notifyDaemon-
|
|
866
|
+
//# sourceMappingURL=notifyDaemon-ByJtcbbX.js.map
|
|
@@ -338,7 +338,7 @@ async function isParentWatching(parentWrapperPid, parentAgentPid, selfAgentPid,
|
|
|
338
338
|
logger.debug("[parent-ping] watcher lookup failed:", error);
|
|
339
339
|
}
|
|
340
340
|
try {
|
|
341
|
-
const { lastReadAt, READ_WINDOW_MS } = await import("./subcommands-
|
|
341
|
+
const { lastReadAt, READ_WINDOW_MS } = await import("./subcommands-C0-NKq4X.js");
|
|
342
342
|
const last = await lastReadAt(`agent:${parentAgentPid}`, selfAgentPid);
|
|
343
343
|
if (last !== null && now - last <= READ_WINDOW_MS) return true;
|
|
344
344
|
} catch (error) {
|
|
@@ -466,4 +466,4 @@ function startParentPingLoop(opts) {
|
|
|
466
466
|
|
|
467
467
|
//#endregion
|
|
468
468
|
export { startParentPingLoop };
|
|
469
|
-
//# sourceMappingURL=parentPingLoop-
|
|
469
|
+
//# sourceMappingURL=parentPingLoop-D1oxgeES.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as isWebrtcSpec } from "./webrtcLink-B72AQ2eb.js";
|
|
1
|
+
import { n as isWebrtcSpec, r as parseWebrtcLink } from "./webrtcLink-B72AQ2eb.js";
|
|
2
2
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import path from "path";
|
|
@@ -9,6 +9,11 @@ function remotesPath() {
|
|
|
9
9
|
const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
10
10
|
return path.join(dir, "remotes.yaml");
|
|
11
11
|
}
|
|
12
|
+
/** A display label for a WebRTC share link: the room id, never the local bridge. */
|
|
13
|
+
function webrtcLabel(link) {
|
|
14
|
+
const parsed = parseWebrtcLink(link);
|
|
15
|
+
return parsed ? `webrtc:${parsed.room}` : "webrtc";
|
|
16
|
+
}
|
|
12
17
|
async function readRemotes() {
|
|
13
18
|
let raw;
|
|
14
19
|
try {
|
|
@@ -61,23 +66,25 @@ function parseDirectRemoteSpec(spec) {
|
|
|
61
66
|
* Returns null if the spec doesn't match any remote.
|
|
62
67
|
*/
|
|
63
68
|
async function resolveRemoteSpec(spec) {
|
|
64
|
-
if (isWebrtcSpec(spec)) return resolveWebrtc(spec, void 0);
|
|
69
|
+
if (isWebrtcSpec(spec)) return resolveWebrtc(spec, void 0, webrtcLabel(spec));
|
|
65
70
|
const direct = parseDirectRemoteSpec(spec);
|
|
66
71
|
if (direct) return {
|
|
67
72
|
url: direct.baseUrl,
|
|
68
73
|
token: direct.token,
|
|
69
|
-
keyword: direct.keyword
|
|
74
|
+
keyword: direct.keyword,
|
|
75
|
+
label: `${direct.host}:${direct.port}`
|
|
70
76
|
};
|
|
71
77
|
const colonIdx = spec.indexOf(":");
|
|
72
78
|
const alias = colonIdx >= 0 ? spec.slice(0, colonIdx) : spec;
|
|
73
79
|
const keyword = colonIdx >= 0 ? spec.slice(colonIdx + 1) || void 0 : void 0;
|
|
74
80
|
const cfg = (await readRemotes()).get(alias);
|
|
75
81
|
if (!cfg) return null;
|
|
76
|
-
if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword);
|
|
82
|
+
if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword, alias);
|
|
77
83
|
return {
|
|
78
84
|
url: cfg.url,
|
|
79
85
|
token: cfg.token,
|
|
80
|
-
keyword
|
|
86
|
+
keyword,
|
|
87
|
+
label: alias
|
|
81
88
|
};
|
|
82
89
|
}
|
|
83
90
|
/**
|
|
@@ -85,13 +92,14 @@ async function resolveRemoteSpec(spec) {
|
|
|
85
92
|
* ordinary http remote, so every fetch-based remote command works unchanged.
|
|
86
93
|
* The bridge lives for the rest of the process (torn down on `process.exit`).
|
|
87
94
|
*/
|
|
88
|
-
async function resolveWebrtc(link, keyword) {
|
|
95
|
+
async function resolveWebrtc(link, keyword, label) {
|
|
89
96
|
const { startWebrtcBridge } = await import("./webrtcRemote-D68dkqFp.js");
|
|
90
97
|
const bridge = await startWebrtcBridge(link);
|
|
91
98
|
return {
|
|
92
99
|
url: bridge.baseUrl,
|
|
93
100
|
token: bridge.token,
|
|
94
|
-
keyword
|
|
101
|
+
keyword,
|
|
102
|
+
label
|
|
95
103
|
};
|
|
96
104
|
}
|
|
97
105
|
async function cmdRemote(rest) {
|
|
@@ -173,4 +181,4 @@ async function cmdRemote(rest) {
|
|
|
173
181
|
|
|
174
182
|
//#endregion
|
|
175
183
|
export { resolveRemoteSpec as a, readRemotes as i, deleteRemoteAlias as n, writeRemoteAlias as o, parseDirectRemoteSpec as r, cmdRemote as t };
|
|
176
|
-
//# sourceMappingURL=remotes-
|
|
184
|
+
//# sourceMappingURL=remotes-BL2MegXx.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./e2e-OLfcNxiv.js";
|
|
2
2
|
import "./webrtcLink-B72AQ2eb.js";
|
|
3
|
-
import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-
|
|
3
|
+
import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-BL2MegXx.js";
|
|
4
4
|
|
|
5
5
|
export { cmdRemote };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
1
|
+
import { r as getInstalledPackage } from "./versionChecker-DHrDPEw3.js";
|
|
2
2
|
import { execFileSync } from "child_process";
|
|
3
3
|
import { existsSync, mkdirSync, unlinkSync } from "fs";
|
|
4
4
|
import { chmod, copyFile } from "fs/promises";
|
|
@@ -243,4 +243,4 @@ async function getRustBinary(options = {}) {
|
|
|
243
243
|
|
|
244
244
|
//#endregion
|
|
245
245
|
export { findTrayLauncher as n, getRustBinary as r, findSpawnHiddenLauncher as t };
|
|
246
|
-
//# sourceMappingURL=rustBinary-
|
|
246
|
+
//# sourceMappingURL=rustBinary-DPRR_QOA.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-DHrDPEw3.js";
|
|
3
|
+
import "./ts-C5yjBnoI.js";
|
|
4
4
|
import "./todoAutomation-BETGOik9.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-Dq4KY2IV.js";
|
|
7
7
|
import "./pidStore-DJqSZPJi.js";
|
|
8
8
|
import "./messageLog-BYFwioFY.js";
|
|
9
9
|
import "./todoStore-Wk8U4zJ8.js";
|
|
10
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
10
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DNNdMJN_.js";
|
|
11
11
|
import { f as resolveSpawnCwd } from "./workspaceConfig-EK7XNsgR.js";
|
|
12
12
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-CKc1BN5J.js";
|
|
13
13
|
import { createHash } from "node:crypto";
|
|
@@ -154,4 +154,4 @@ async function cmdSchedule(rest) {
|
|
|
154
154
|
|
|
155
155
|
//#endregion
|
|
156
156
|
export { cmdSchedule };
|
|
157
|
-
//# sourceMappingURL=schedule-
|
|
157
|
+
//# sourceMappingURL=schedule-B8S10ci8.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
3
|
-
import { t as findSpawnHiddenLauncher } from "./rustBinary-
|
|
4
|
-
import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-DHrDPEw3.js";
|
|
3
|
+
import { t as findSpawnHiddenLauncher } from "./rustBinary-DPRR_QOA.js";
|
|
4
|
+
import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-C5yjBnoI.js";
|
|
5
5
|
import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
|
|
6
6
|
import { u as removeControlCharacters } from "./todoAutomation-BETGOik9.js";
|
|
7
7
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
@@ -12,18 +12,18 @@ import { t as pgidForWrapper } from "./reaper-C4BvNylH.js";
|
|
|
12
12
|
import "./todoStore-Wk8U4zJ8.js";
|
|
13
13
|
import "./e2e-OLfcNxiv.js";
|
|
14
14
|
import "./configShared-DYxlvrH0.js";
|
|
15
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
16
|
-
import { $ as TYPING_BADGE, B as resolveOne, F as recentMessageEdges, G as snapshotStatus, I as recentReadEdges, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, Q as withIpcLock, R as renderRawLog, T as isUserTyping, Z as writeToIpc, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, l as controlCodeFromName, p as extractBadges, z as renderRawLogLines } from "./subcommands-
|
|
15
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DNNdMJN_.js";
|
|
16
|
+
import { $ as TYPING_BADGE, B as resolveOne, F as recentMessageEdges, G as snapshotStatus, I as recentReadEdges, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, Q as withIpcLock, R as renderRawLog, T as isUserTyping, Z as writeToIpc, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, l as controlCodeFromName, p as extractBadges, z as renderRawLogLines } from "./subcommands-DX0iQzwD.js";
|
|
17
17
|
import { c as isTransientLockMkdirError } from "./notifyStore-Dus2D1XA.js";
|
|
18
18
|
import "./webrtcLink-B72AQ2eb.js";
|
|
19
|
-
import "./remotes-
|
|
19
|
+
import "./remotes-BL2MegXx.js";
|
|
20
20
|
import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-Bbe7rpN2.js";
|
|
21
|
-
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-
|
|
21
|
+
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-pDrrtfQ8.js";
|
|
22
22
|
import { a as getProvisionRoot, d as isProvisionAllowed, f as resolveSpawnCwd, i as getProvisionHook, l as hasProvisionHook, o as getSpawnHook, t as allowsSkipPermissions, u as hasSpawnHook } from "./workspaceConfig-EK7XNsgR.js";
|
|
23
23
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-CKc1BN5J.js";
|
|
24
|
-
import { i as importProvisionModule } from "./ws-
|
|
24
|
+
import { i as importProvisionModule } from "./ws-KZfHmxtS.js";
|
|
25
25
|
import { r as spawnRejectionReason } from "./spawnGate-CS3oFdJ9.js";
|
|
26
|
-
import { i as launchTray } from "./trayApp-
|
|
26
|
+
import { i as launchTray } from "./trayApp-BxrNX0KY.js";
|
|
27
27
|
import yargs from "yargs";
|
|
28
28
|
import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "fs/promises";
|
|
29
29
|
import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
|
|
@@ -2436,7 +2436,7 @@ Options:
|
|
|
2436
2436
|
}
|
|
2437
2437
|
});
|
|
2438
2438
|
if (req.method === "GET" && p === "/api/ws") {
|
|
2439
|
-
const ws = await import("./ws-
|
|
2439
|
+
const ws = await import("./ws-CWMIHaJ8.js");
|
|
2440
2440
|
try {
|
|
2441
2441
|
await ws.loadProvision();
|
|
2442
2442
|
} catch (e) {
|
|
@@ -2456,7 +2456,7 @@ Options:
|
|
|
2456
2456
|
if (req.method === "GET" && p === "/api/ws/status") {
|
|
2457
2457
|
const dirRaw = url.searchParams.get("path");
|
|
2458
2458
|
if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
|
|
2459
|
-
const ws = await import("./ws-
|
|
2459
|
+
const ws = await import("./ws-CWMIHaJ8.js");
|
|
2460
2460
|
let prov;
|
|
2461
2461
|
try {
|
|
2462
2462
|
prov = await ws.loadProvision();
|
|
@@ -2478,7 +2478,7 @@ Options:
|
|
|
2478
2478
|
}
|
|
2479
2479
|
}
|
|
2480
2480
|
if (req.method === "GET" && p === "/api/ws/repos") {
|
|
2481
|
-
const ws = await import("./ws-
|
|
2481
|
+
const ws = await import("./ws-CWMIHaJ8.js");
|
|
2482
2482
|
try {
|
|
2483
2483
|
await ws.loadProvision();
|
|
2484
2484
|
} catch (e) {
|
|
@@ -2559,7 +2559,7 @@ Options:
|
|
|
2559
2559
|
const m = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/.exec(repoParam);
|
|
2560
2560
|
if (!m || m[1] === "." || m[1] === ".." || m[2] === "." || m[2] === "..") return new Response("missing/invalid ?repo=<owner>/<repo>", { status: 400 });
|
|
2561
2561
|
const [, owner, repo] = m;
|
|
2562
|
-
const ws = await import("./ws-
|
|
2562
|
+
const ws = await import("./ws-CWMIHaJ8.js");
|
|
2563
2563
|
let prov;
|
|
2564
2564
|
try {
|
|
2565
2565
|
prov = await ws.loadProvision();
|
|
@@ -3470,7 +3470,7 @@ Options:
|
|
|
3470
3470
|
const perm = body.perm ?? "r";
|
|
3471
3471
|
if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
|
|
3472
3472
|
try {
|
|
3473
|
-
const { createScopedShare } = await import("./agentShare-
|
|
3473
|
+
const { createScopedShare } = await import("./agentShare-DJDnjvQc.js");
|
|
3474
3474
|
const share = await createScopedShare({
|
|
3475
3475
|
agent: body.agent,
|
|
3476
3476
|
perm,
|
|
@@ -3485,12 +3485,12 @@ Options:
|
|
|
3485
3485
|
}
|
|
3486
3486
|
}
|
|
3487
3487
|
if (req.method === "GET" && p === "/api/shares") {
|
|
3488
|
-
const { listShares } = await import("./agentShare-
|
|
3488
|
+
const { listShares } = await import("./agentShare-DJDnjvQc.js");
|
|
3489
3489
|
return Response.json(listShares());
|
|
3490
3490
|
}
|
|
3491
3491
|
const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
|
|
3492
3492
|
if (req.method === "DELETE" && revokeM) {
|
|
3493
|
-
const { revokeShare } = await import("./agentShare-
|
|
3493
|
+
const { revokeShare } = await import("./agentShare-DJDnjvQc.js");
|
|
3494
3494
|
const ok = revokeShare(decodeURIComponent(revokeM[1]));
|
|
3495
3495
|
return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
|
|
3496
3496
|
}
|
|
@@ -3795,7 +3795,7 @@ Options:
|
|
|
3795
3795
|
const shutdown = (resolve) => {
|
|
3796
3796
|
if (heartbeat) clearInterval(heartbeat);
|
|
3797
3797
|
closeShare?.();
|
|
3798
|
-
import("./agentShare-
|
|
3798
|
+
import("./agentShare-DJDnjvQc.js").then((m) => m.revokeAllShares()).catch(() => {});
|
|
3799
3799
|
server?.stop();
|
|
3800
3800
|
Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
|
|
3801
3801
|
};
|
|
@@ -3808,4 +3808,4 @@ Options:
|
|
|
3808
3808
|
|
|
3809
3809
|
//#endregion
|
|
3810
3810
|
export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
|
|
3811
|
-
//# sourceMappingURL=serve-
|
|
3811
|
+
//# sourceMappingURL=serve-CcVhTYIX.js.map
|
|
@@ -40,7 +40,7 @@ async function cmdSetup(rest) {
|
|
|
40
40
|
} catch {}
|
|
41
41
|
if (noShare) return 0;
|
|
42
42
|
process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
|
|
43
|
-
const { cmdServe } = await import("./serve-
|
|
43
|
+
const { cmdServe } = await import("./serve-CcVhTYIX.js");
|
|
44
44
|
return cmdServe([
|
|
45
45
|
"install",
|
|
46
46
|
"--share",
|
|
@@ -50,4 +50,4 @@ async function cmdSetup(rest) {
|
|
|
50
50
|
|
|
51
51
|
//#endregion
|
|
52
52
|
export { cmdSetup };
|
|
53
|
-
//# sourceMappingURL=setup-
|
|
53
|
+
//# sourceMappingURL=setup-CJGkmk3P.js.map
|
|
@@ -3,9 +3,9 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-OLfcNxiv.js";
|
|
5
5
|
import "./configShared-DYxlvrH0.js";
|
|
6
|
-
import { A as menuSelectKeys, B as resolveOne, C as isSubcommand, D as lastStdinAt, E as lastReadAt, F as recentMessageEdges, G as snapshotStatus, H as resolveResumeArgs, I as recentReadEdges, J as submitAndConfirm, K as stdinActivityPath, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, R as renderRawLog, S as isSlashCommand, T as isUserTyping, U as restartHintLines, V as resolveReadWindow, W as runSubcommand, X as writeKeysPaced, Y as waitForLogQuiet, Z as writeToIpc, _ as finalizedLines, a as TYPING_WINDOW_MS, b as isExitRequest, c as cmdHelp, d as deriveLiveState, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, i as READ_WINDOW_MS, j as readAgentPtysize, k as matchKeyword, l as controlCodeFromName, m as extractMenu, n as MAX_RENDER_BYTES, o as backoffWhileTyping, p as extractBadges, q as stopTipForCli, r as READ_PAGE_DEFAULT, s as cmdDeepseek, t as GRACEFUL_EXIT_COMMANDS, u as cursorAbs, v as isAgentStuck, w as isUnknownManagerToken, x as isPidAlive, y as isBareManagerInvocation, z as renderRawLogLines } from "./subcommands-
|
|
6
|
+
import { A as menuSelectKeys, B as resolveOne, C as isSubcommand, D as lastStdinAt, E as lastReadAt, F as recentMessageEdges, G as snapshotStatus, H as resolveResumeArgs, I as recentReadEdges, J as submitAndConfirm, K as stdinActivityPath, L as renderLogTailLines, M as readLogForRender, N as readNotes, O as listRecords, P as readPtysize, R as renderRawLog, S as isSlashCommand, T as isUserTyping, U as restartHintLines, V as resolveReadWindow, W as runSubcommand, X as writeKeysPaced, Y as waitForLogQuiet, Z as writeToIpc, _ as finalizedLines, a as TYPING_WINDOW_MS, b as isExitRequest, c as cmdHelp, d as deriveLiveState, f as deriveLiveStatus, g as extractTaskCounts, h as extractNeedsInput, i as READ_WINDOW_MS, j as readAgentPtysize, k as matchKeyword, l as controlCodeFromName, m as extractMenu, n as MAX_RENDER_BYTES, o as backoffWhileTyping, p as extractBadges, q as stopTipForCli, r as READ_PAGE_DEFAULT, s as cmdDeepseek, t as GRACEFUL_EXIT_COMMANDS, u as cursorAbs, v as isAgentStuck, w as isUnknownManagerToken, x as isPidAlive, y as isBareManagerInvocation, z as renderRawLogLines } from "./subcommands-DX0iQzwD.js";
|
|
7
7
|
import "./notifyStore-Dus2D1XA.js";
|
|
8
8
|
import "./webrtcLink-B72AQ2eb.js";
|
|
9
|
-
import "./remotes-
|
|
9
|
+
import "./remotes-BL2MegXx.js";
|
|
10
10
|
|
|
11
11
|
export { READ_WINDOW_MS, cmdHelp, isBareManagerInvocation, isSubcommand, isUnknownManagerToken, lastReadAt, runSubcommand };
|
|
@@ -7,7 +7,7 @@ import { t as formatIdentity } from "./identity-CLaJ9-uE.js";
|
|
|
7
7
|
import { n as isWorkingScreen, r as parseMenu, t as classifyNeedsInput } from "./needsInput-DhfIwxse.js";
|
|
8
8
|
import { S as postmortemStartedAt, _ as filterSinceSeq, a as getCursor, b as maxSeq, f as readInbox, o as heartbeatWatcher, p as setCursor, r as clearWatcher, s as hostId, v as filterSinceTs, y as filterUnread } from "./notifyStore-Dus2D1XA.js";
|
|
9
9
|
import { n as isWebrtcSpec } from "./webrtcLink-B72AQ2eb.js";
|
|
10
|
-
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-
|
|
10
|
+
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-BL2MegXx.js";
|
|
11
11
|
import { spawn } from "child_process";
|
|
12
12
|
import ms from "ms";
|
|
13
13
|
import yargs from "yargs";
|
|
@@ -907,7 +907,7 @@ async function runSubcommand(argv) {
|
|
|
907
907
|
switch (sub) {
|
|
908
908
|
case "ls":
|
|
909
909
|
case "list": return await cmdLs(rest);
|
|
910
|
-
case "ps": return await (await import("./cmdPs-
|
|
910
|
+
case "ps": return await (await import("./cmdPs-YBWZA9q_.js")).cmdPs(rest);
|
|
911
911
|
case "status": return await cmdStatus(rest);
|
|
912
912
|
case "whoami": return await cmdWhoami(rest);
|
|
913
913
|
case "result": return await cmdResult(rest);
|
|
@@ -954,39 +954,39 @@ async function runSubcommand(argv) {
|
|
|
954
954
|
return cmdCh(rest);
|
|
955
955
|
}
|
|
956
956
|
case "term": {
|
|
957
|
-
const { cmdTerm } = await import("./terminal-
|
|
957
|
+
const { cmdTerm } = await import("./terminal-CCLw4qIt.js");
|
|
958
958
|
return cmdTerm(rest);
|
|
959
959
|
}
|
|
960
960
|
case "widget": {
|
|
961
|
-
const { cmdWidget } = await import("./widget-
|
|
961
|
+
const { cmdWidget } = await import("./widget-Bf-hAxpl.js");
|
|
962
962
|
return cmdWidget(rest);
|
|
963
963
|
}
|
|
964
964
|
case "mint": {
|
|
965
|
-
const { cmdMint } = await import("./widget-
|
|
965
|
+
const { cmdMint } = await import("./widget-Bf-hAxpl.js");
|
|
966
966
|
return cmdMint(rest);
|
|
967
967
|
}
|
|
968
968
|
case "serve": {
|
|
969
|
-
const { cmdServe } = await import("./serve-
|
|
969
|
+
const { cmdServe } = await import("./serve-CcVhTYIX.js");
|
|
970
970
|
return cmdServe(rest);
|
|
971
971
|
}
|
|
972
972
|
case "tray": {
|
|
973
|
-
const { cmdTray } = await import("./trayApp-
|
|
973
|
+
const { cmdTray } = await import("./trayApp-10o8DC7r.js");
|
|
974
974
|
return cmdTray(rest);
|
|
975
975
|
}
|
|
976
976
|
case "setup": {
|
|
977
|
-
const { cmdSetup } = await import("./setup-
|
|
977
|
+
const { cmdSetup } = await import("./setup-CJGkmk3P.js");
|
|
978
978
|
return cmdSetup(rest);
|
|
979
979
|
}
|
|
980
980
|
case "ws": {
|
|
981
|
-
const { cmdWs } = await import("./ws-
|
|
981
|
+
const { cmdWs } = await import("./ws-CWMIHaJ8.js");
|
|
982
982
|
return cmdWs(rest);
|
|
983
983
|
}
|
|
984
984
|
case "schedule": {
|
|
985
|
-
const { cmdSchedule } = await import("./schedule-
|
|
985
|
+
const { cmdSchedule } = await import("./schedule-B8S10ci8.js");
|
|
986
986
|
return cmdSchedule(rest);
|
|
987
987
|
}
|
|
988
988
|
case "remote": {
|
|
989
|
-
const { cmdRemote } = await import("./remotes-
|
|
989
|
+
const { cmdRemote } = await import("./remotes-CNNWole7.js");
|
|
990
990
|
return cmdRemote(rest);
|
|
991
991
|
}
|
|
992
992
|
case "expose": {
|
|
@@ -994,7 +994,7 @@ async function runSubcommand(argv) {
|
|
|
994
994
|
return cmdExpose(rest);
|
|
995
995
|
}
|
|
996
996
|
case "callback": {
|
|
997
|
-
const { cmdCallback } = await import("./callback-
|
|
997
|
+
const { cmdCallback } = await import("./callback-Dc1PCZUk.js");
|
|
998
998
|
return cmdCallback(rest);
|
|
999
999
|
}
|
|
1000
1000
|
case "reap":
|
|
@@ -1234,10 +1234,10 @@ async function runRemoteLs(remote, opts) {
|
|
|
1234
1234
|
}
|
|
1235
1235
|
const records = await res.json();
|
|
1236
1236
|
if (records.length === 0) {
|
|
1237
|
-
process.stderr.write(remote.keyword ? `no agents matched "${remote.keyword}" on ${remote.
|
|
1237
|
+
process.stderr.write(remote.keyword ? `no agents matched "${remote.keyword}" on ${remote.label}\n` : `no running agents on ${remote.label}\n`);
|
|
1238
1238
|
return 0;
|
|
1239
1239
|
}
|
|
1240
|
-
process.stderr.write(`[remote ${remote.
|
|
1240
|
+
process.stderr.write(`[remote ${remote.label}]\n`);
|
|
1241
1241
|
const termWidth = process.stdout.columns ?? 120;
|
|
1242
1242
|
const widths = {
|
|
1243
1243
|
pid: Math.max(3, ...records.map((r) => String(r.pid).length)),
|
|
@@ -1280,7 +1280,7 @@ async function runRemoteRead(remote, mode, follow, n, reconnectTimeoutMs = 12e4,
|
|
|
1280
1280
|
const deadline = Date.now() + reconnectTimeoutMs;
|
|
1281
1281
|
let delay = 1e3;
|
|
1282
1282
|
let attempt = 0;
|
|
1283
|
-
process.stderr.write(`[remote ${remote.
|
|
1283
|
+
process.stderr.write(`[remote ${remote.label} ${keyword}]\nfollowing... (Ctrl-C to stop, timeout: ${Math.round(reconnectTimeoutMs / 1e3)}s)\n`);
|
|
1284
1284
|
while (!ac.signal.aborted) try {
|
|
1285
1285
|
const res = await fetch(`${remote.url}/api/tail/${encodeURIComponent(keyword)}`, {
|
|
1286
1286
|
headers: {
|
|
@@ -1347,7 +1347,7 @@ async function runRemoteRead(remote, mode, follow, n, reconnectTimeoutMs = 12e4,
|
|
|
1347
1347
|
return 1;
|
|
1348
1348
|
}
|
|
1349
1349
|
const text = await res.text();
|
|
1350
|
-
process.stderr.write(`[remote ${remote.
|
|
1350
|
+
process.stderr.write(`[remote ${remote.label} ${keyword}]\n`);
|
|
1351
1351
|
process.stdout.write(text);
|
|
1352
1352
|
if (!text.endsWith("\n")) process.stdout.write("\n");
|
|
1353
1353
|
return 0;
|
|
@@ -1376,7 +1376,7 @@ async function runRemoteSend(remote, msg, code) {
|
|
|
1376
1376
|
return 1;
|
|
1377
1377
|
}
|
|
1378
1378
|
const data = await res.json();
|
|
1379
|
-
process.stdout.write(`sent to remote pid ${data.pid} (${remote.
|
|
1379
|
+
process.stdout.write(`sent to remote pid ${data.pid} (${remote.label} ${keyword})\n`);
|
|
1380
1380
|
if (msg && msg !== "-") await recordOutbox({
|
|
1381
1381
|
at: Date.now(),
|
|
1382
1382
|
from,
|
|
@@ -1390,7 +1390,7 @@ async function runRemoteSend(remote, msg, code) {
|
|
|
1390
1390
|
code: code.toLowerCase() === "enter" ? void 0 : code.toLowerCase(),
|
|
1391
1391
|
confirmed: true,
|
|
1392
1392
|
wrapped: false,
|
|
1393
|
-
remote: remote.
|
|
1393
|
+
remote: remote.label
|
|
1394
1394
|
});
|
|
1395
1395
|
return 0;
|
|
1396
1396
|
}
|
|
@@ -1417,7 +1417,7 @@ async function runRemoteSpawn(remote, hint, spec) {
|
|
|
1417
1417
|
} catch (e) {
|
|
1418
1418
|
const name = e?.name;
|
|
1419
1419
|
if (name === "TimeoutError" || name === "AbortError") {
|
|
1420
|
-
process.stderr.write(`remote spawn: no response from ${remote.
|
|
1420
|
+
process.stderr.write(`remote spawn: no response from ${remote.label} within ${Math.round(SPAWN_TIMEOUT_MS / 1e3)}s — result UNKNOWN (not retried).\n ay ls ${hint} # check whether it started\n`);
|
|
1421
1421
|
return 2;
|
|
1422
1422
|
}
|
|
1423
1423
|
process.stderr.write(`remote spawn failed: ${e.message}\n`);
|
|
@@ -1428,7 +1428,7 @@ async function runRemoteSpawn(remote, hint, spec) {
|
|
|
1428
1428
|
return 1;
|
|
1429
1429
|
}
|
|
1430
1430
|
const r = await res.json();
|
|
1431
|
-
process.stdout.write(`spawned ${r.cli} on ${remote.
|
|
1431
|
+
process.stdout.write(`spawned ${r.cli} on ${remote.label} in ${r.cwd}${r.hook ? " (via spawn hook)" : ""}${r.provisioned ? ` (${r.provisioned.action})` : ""}\n`);
|
|
1432
1432
|
if (r.agentId && !hint.includes("://")) process.stderr.write(`\n ay tail ${hint}:${r.agentId} # watch its output\n ay status ${hint}:${r.agentId} --wait # block until it needs you\n`);
|
|
1433
1433
|
else process.stderr.write(`\n ay ls ${hint} # the new ${r.cli} agent appears here\n`);
|
|
1434
1434
|
return 0;
|
|
@@ -3500,7 +3500,7 @@ async function cmdAttach(rest) {
|
|
|
3500
3500
|
const winsizeDir = path.join(ayHome, "winsize");
|
|
3501
3501
|
await mkdir(winsizeDir, { recursive: true });
|
|
3502
3502
|
const winsizePath = path.join(winsizeDir, String(record.pid));
|
|
3503
|
-
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-
|
|
3503
|
+
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-CcVhTYIX.js");
|
|
3504
3504
|
const daemonBase = await resolveDaemonHttpBase().catch(() => null);
|
|
3505
3505
|
const daemonToken = daemonBase ? await loadTokenReadOnly().catch(() => null) ?? "" : "";
|
|
3506
3506
|
const capViewer = `attach:${process.pid}`;
|
|
@@ -4210,7 +4210,7 @@ async function cmdNotify(rest) {
|
|
|
4210
4210
|
}
|
|
4211
4211
|
const ensure = async () => {
|
|
4212
4212
|
if (!argv["ensure-daemon"]) return;
|
|
4213
|
-
const { ensureDaemon } = await import("./notifyDaemon-
|
|
4213
|
+
const { ensureDaemon } = await import("./notifyDaemon-ByJtcbbX.js");
|
|
4214
4214
|
await ensureDaemon().catch(() => null);
|
|
4215
4215
|
};
|
|
4216
4216
|
await heartbeatWatcher(parent, selfStartedAt);
|
|
@@ -4284,7 +4284,7 @@ async function cmdNotifyCursor(args) {
|
|
|
4284
4284
|
}
|
|
4285
4285
|
async function cmdNotifyd(rest) {
|
|
4286
4286
|
const sub = rest[0] ?? "status";
|
|
4287
|
-
const daemon = await import("./notifyDaemon-
|
|
4287
|
+
const daemon = await import("./notifyDaemon-ByJtcbbX.js");
|
|
4288
4288
|
switch (sub) {
|
|
4289
4289
|
case "run": return daemon.runDaemon();
|
|
4290
4290
|
case "once": return daemon.runDaemon({ once: true });
|
|
@@ -4311,4 +4311,4 @@ async function cmdNotifyd(rest) {
|
|
|
4311
4311
|
|
|
4312
4312
|
//#endregion
|
|
4313
4313
|
export { TYPING_BADGE as $, menuSelectKeys as A, resolveOne as B, isSubcommand as C, lastStdinAt as D, lastReadAt as E, recentMessageEdges as F, snapshotStatus as G, resolveResumeArgs as H, recentReadEdges as I, submitAndConfirm as J, stdinActivityPath as K, renderLogTailLines as L, readLogForRender as M, readNotes as N, listRecords as O, readPtysize as P, withIpcLock as Q, renderRawLog as R, isSlashCommand as S, isUserTyping as T, restartHintLines as U, resolveReadWindow as V, runSubcommand as W, writeKeysPaced as X, waitForLogQuiet as Y, writeToIpc as Z, finalizedLines as _, TYPING_WINDOW_MS as a, isExitRequest as b, cmdHelp as c, deriveLiveState as d, buildAgentForest as et, deriveLiveStatus as f, extractTaskCounts as g, extractNeedsInput as h, READ_WINDOW_MS as i, readAgentPtysize as j, matchKeyword as k, controlCodeFromName as l, extractMenu as m, MAX_RENDER_BYTES as n, backoffWhileTyping as o, extractBadges as p, stopTipForCli as q, READ_PAGE_DEFAULT as r, cmdDeepseek as s, GRACEFUL_EXIT_COMMANDS as t, flattenForest as tt, cursorAbs as u, isAgentStuck as v, isUnknownManagerToken as w, isPidAlive as x, isBareManagerInvocation as y, renderRawLogLines as z };
|
|
4314
|
-
//# sourceMappingURL=subcommands-
|
|
4314
|
+
//# sourceMappingURL=subcommands-DX0iQzwD.js.map
|
|
@@ -98,7 +98,7 @@ async function cmdTermMint(args) {
|
|
|
98
98
|
if (flags.ro && flags.interactive) throw new Error("--ro and --interactive are mutually exclusive");
|
|
99
99
|
const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
|
|
100
100
|
const canSend = flags.interactive === true;
|
|
101
|
-
const { mintScopedTermToken } = await import("./serve-
|
|
101
|
+
const { mintScopedTermToken } = await import("./serve-CcVhTYIX.js");
|
|
102
102
|
const r = await mintScopedTermToken(pid, {
|
|
103
103
|
ttlSec,
|
|
104
104
|
canSend
|
|
@@ -135,4 +135,4 @@ async function cmdTerm(args) {
|
|
|
135
135
|
|
|
136
136
|
//#endregion
|
|
137
137
|
export { cmdTerm };
|
|
138
|
-
//# sourceMappingURL=terminal-
|
|
138
|
+
//# sourceMappingURL=terminal-CCLw4qIt.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as findTrayLauncher } from "./rustBinary-
|
|
1
|
+
import { n as findTrayLauncher } from "./rustBinary-DPRR_QOA.js";
|
|
2
2
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -97,4 +97,4 @@ async function cmdTray(args) {
|
|
|
97
97
|
|
|
98
98
|
//#endregion
|
|
99
99
|
export { trayHiddenMarker as a, launchTray as i, hasDesktop as n, isTrayHidden as r, cmdTray as t };
|
|
100
|
-
//# sourceMappingURL=trayApp-
|
|
100
|
+
//# sourceMappingURL=trayApp-BxrNX0KY.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __esmMin, r as __exportAll } from "./chunk-cZBX9HZv.js";
|
|
2
2
|
import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
3
|
+
import { r as getInstalledPackage } from "./versionChecker-DHrDPEw3.js";
|
|
4
4
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
5
5
|
import { u as removeControlCharacters } from "./todoAutomation-BETGOik9.js";
|
|
6
6
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-DBoONoM-.js";
|
|
@@ -2074,7 +2074,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
|
|
|
2074
2074
|
}, 100);
|
|
2075
2075
|
const cleanupHeartbeat = () => clearInterval(heartbeatInterval);
|
|
2076
2076
|
shell.onExit(cleanupHeartbeat);
|
|
2077
|
-
const { startParentPingLoop } = await import("./parentPingLoop-
|
|
2077
|
+
const { startParentPingLoop } = await import("./parentPingLoop-D1oxgeES.js");
|
|
2078
2078
|
const parentPingLoop = startParentPingLoop({
|
|
2079
2079
|
parentPid,
|
|
2080
2080
|
selfWrapperPid: process.pid,
|
|
@@ -2338,4 +2338,4 @@ function sleep(ms) {
|
|
|
2338
2338
|
|
|
2339
2339
|
//#endregion
|
|
2340
2340
|
export { hasTodoStore as a, permissionBadge as c, answerAsk as i, AgentContext as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t, CLAUDE_SESSION_PIN_ENV as u };
|
|
2341
|
-
//# sourceMappingURL=ts-
|
|
2341
|
+
//# sourceMappingURL=ts-C5yjBnoI.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.272.0-beta.658.1";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -215,4 +215,4 @@ async function displayVersion() {
|
|
|
215
215
|
|
|
216
216
|
//#endregion
|
|
217
217
|
export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
|
|
218
|
-
//# sourceMappingURL=versionChecker-
|
|
218
|
+
//# sourceMappingURL=versionChecker-DHrDPEw3.js.map
|
|
@@ -28,7 +28,7 @@ function parseFlags(args, known) {
|
|
|
28
28
|
}
|
|
29
29
|
/** Resolve the local daemon base URL + token (flags override discovery). */
|
|
30
30
|
async function daemonTarget(flags) {
|
|
31
|
-
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-
|
|
31
|
+
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-CcVhTYIX.js");
|
|
32
32
|
const base = typeof flags.base === "string" ? flags.base : await resolveDaemonHttpBase();
|
|
33
33
|
if (!base) throw new Error("no running ay serve daemon found — start `ay serve` or pass --base <url> (e.g. http://127.0.0.1:PORT)");
|
|
34
34
|
const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
|
|
@@ -186,7 +186,7 @@ async function cmdMint(args) {
|
|
|
186
186
|
const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
|
|
187
187
|
if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
|
|
188
188
|
const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
|
|
189
|
-
const { mintScopedTermToken } = await import("./serve-
|
|
189
|
+
const { mintScopedTermToken } = await import("./serve-CcVhTYIX.js");
|
|
190
190
|
const r = await mintScopedTermToken(target, {
|
|
191
191
|
ttlSec,
|
|
192
192
|
caps
|
|
@@ -202,4 +202,4 @@ async function cmdMint(args) {
|
|
|
202
202
|
|
|
203
203
|
//#endregion
|
|
204
204
|
export { cmdMint, cmdWidget };
|
|
205
|
-
//# sourceMappingURL=widget-
|
|
205
|
+
//# sourceMappingURL=widget-Bf-hAxpl.js.map
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-OLfcNxiv.js";
|
|
5
5
|
import "./configShared-DYxlvrH0.js";
|
|
6
|
-
import "./subcommands-
|
|
6
|
+
import "./subcommands-DX0iQzwD.js";
|
|
7
7
|
import "./notifyStore-Dus2D1XA.js";
|
|
8
8
|
import "./webrtcLink-B72AQ2eb.js";
|
|
9
|
-
import "./remotes-
|
|
10
|
-
import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-
|
|
9
|
+
import "./remotes-BL2MegXx.js";
|
|
10
|
+
import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-KZfHmxtS.js";
|
|
11
11
|
|
|
12
12
|
export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, walkWorkspaces, workspaceStatus };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { O as listRecords } from "./subcommands-
|
|
1
|
+
import { O as listRecords } from "./subcommands-DX0iQzwD.js";
|
|
2
2
|
import { a as getProvisionRoot } from "./workspaceConfig-EK7XNsgR.js";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
4
|
import { lstat, opendir } from "fs/promises";
|
|
@@ -424,4 +424,4 @@ async function cmdWs(args) {
|
|
|
424
424
|
|
|
425
425
|
//#endregion
|
|
426
426
|
export { isPathInside as a, walkWorkspaces as c, importProvisionModule as i, workspaceStatus as l, cmdWs as n, loadProvision as o, collectWorkspaces as r, resolveOperand as s, WS_JSON_SCHEMA as t };
|
|
427
|
-
//# sourceMappingURL=ws-
|
|
427
|
+
//# sourceMappingURL=ws-KZfHmxtS.js.map
|
package/lab/ui/lab/index.md
CHANGED
|
@@ -79,6 +79,22 @@ machine, and any one person's attention.** The long version is a post below —
|
|
|
79
79
|
address space, a bus that humans are also on, and delegation with accountability, and it is honest
|
|
80
80
|
about the four places the current system is still cluttered.
|
|
81
81
|
|
|
82
|
+
## The ecosystem
|
|
83
|
+
|
|
84
|
+
agent-yes is the fleet. Around it sit tools that give the fleet somewhere to *reach* — each a
|
|
85
|
+
standalone CLI in its own right, each usable without the others:
|
|
86
|
+
|
|
87
|
+
| | |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| **[agent-yes](https://github.com/snomiao/agent-yes)** | run, watch, message and delegate to a fleet of AI coding agents |
|
|
90
|
+
| **[slack-term](https://github.com/snomiao/slack-term)** | the human-comms surface — read and write Slack from a terminal, with a confirm gate built for operators who are sometimes machines |
|
|
91
|
+
|
|
92
|
+
The connective tissue is a shared stance rather than a shared library: file-based state over
|
|
93
|
+
daemons, one command surface across two runtimes, gates on the irreversible and warnings on the
|
|
94
|
+
merely unwise, and a hard rule that no real operational data lands in a public repo. Both projects
|
|
95
|
+
arrived at the same interrupt-safety reasoning against completely different substrates — one over
|
|
96
|
+
`pids.jsonl` and a FIFO, the other over Slack reactions.
|
|
97
|
+
|
|
82
98
|
---
|
|
83
99
|
|
|
84
100
|
## Notes
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: A confirm code that goes stale — how slack-term makes agents safe to give a voice
|
|
3
|
+
tag: Ecosystem
|
|
4
|
+
summary: slack-term is the agent-yes fleet's human-comms surface. Its confirm gate hashes the destination, the actor and the conversation's current last message — so it expires the moment anything that mattered moves. Plus what it gets right, and where it is thinner than its README claims.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<p class="lede">An agent that can only read is a curiosity. An agent that can write into the
|
|
8
|
+
channel where your colleagues work is either infrastructure or a hazard, and which one it is
|
|
9
|
+
comes down to a handful of design decisions. <a
|
|
10
|
+
href="https://github.com/snomiao/slack-term">slack-term</a> is the Slack CLI the agent-yes fleet
|
|
11
|
+
uses to talk to humans, and it is worth reading for one idea in particular: a confirmation code
|
|
12
|
+
that <b>goes stale when the conversation moves</b>.</p>
|
|
13
|
+
|
|
14
|
+
## Where it sits in the ecosystem
|
|
15
|
+
|
|
16
|
+
agent-yes gives a fleet of agents an address space — they can be listed, tailed, messaged and
|
|
17
|
+
delegated to. But a fleet that can only talk to itself is a closed loop. The parts of the system
|
|
18
|
+
that face *humans* are the ones that decide whether any of it is useful: `ay callback` puts a reply
|
|
19
|
+
box on a published report, `ay ch` gives humans and agents one channel, and slack-term takes the
|
|
20
|
+
fleet into the place work already happens.
|
|
21
|
+
|
|
22
|
+
That last one carries a different risk profile from the rest. A callback widget is send-only into a
|
|
23
|
+
terminal you own. Posting to `#general` is irreversible, public, and attributed to *you*. So the
|
|
24
|
+
interesting engineering is not the Slack API wrapper — it is everything built around the moment of
|
|
25
|
+
writing.
|
|
26
|
+
|
|
27
|
+
## The gate: hash the write, not the intent
|
|
28
|
+
|
|
29
|
+
Every gated write — `send`, `edit`, `delete`, `upload`, `schedule`, `channel create`, `drafts` —
|
|
30
|
+
runs twice. The first run previews and prints a 4-hex code; the second run must present it:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
$ slack send "#general" "deploying v2 now"
|
|
34
|
+
From: @alice (U00000001) — Acme
|
|
35
|
+
To: #general
|
|
36
|
+
...preview of the channel's recent messages...
|
|
37
|
+
Rerun with --code=3f9c
|
|
38
|
+
|
|
39
|
+
$ slack send "#general" "deploying v2 now" --code=3f9c
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The code is not a nonce and there is no server, no session, and no stored state. It is
|
|
43
|
+
`sha256(parts.join("\n")).slice(0, 4)` — recomputed from scratch on both runs. What goes into
|
|
44
|
+
`parts` is the whole design (`ts/cli.ts:1433`):
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
const code = safetyCode(channelId, threadTs ?? "", lastText, message, self?.userId ?? "");
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Read that as a list of things that must not have changed between preview and confirm:
|
|
51
|
+
|
|
52
|
+
- **`channelId` + `threadTs`** — a code minted for one destination cannot confirm a send to another.
|
|
53
|
+
- **`self.userId`** — the acting identity. Preview as one profile, switch, confirm → the code is
|
|
54
|
+
dead. Every gate prints a `From: @handle (Uxxxx) — Workspace` line naming who it will act as, and
|
|
55
|
+
binds that identity into the code, so the label cannot drift from the act.
|
|
56
|
+
- **`lastText`** — **the destination's current last message.**
|
|
57
|
+
|
|
58
|
+
That third one is the good idea. If anyone posts between your preview and your confirm, the code
|
|
59
|
+
you were given no longer verifies, and you are shown the conversation again before you can proceed.
|
|
60
|
+
It is a time-of-check/time-of-use defense built out of content rather than a clock: **no timestamp,
|
|
61
|
+
no expiry, no session — freshness is derived from the thing that would make you change your mind.**
|
|
62
|
+
For `edit` and `delete`, the same trick binds the target's *current remote text*, so you cannot
|
|
63
|
+
edit-over something that was rewritten while you were reading it.
|
|
64
|
+
|
|
65
|
+
## Gates block, guards warn
|
|
66
|
+
|
|
67
|
+
Four heuristics fire around a send, and not one of them can stop it:
|
|
68
|
+
|
|
69
|
+
| | |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| **near-duplicate** | character-bigram Dice similarity over normalized text; warns at ≥0.82 against messages already in the thread |
|
|
72
|
+
| **unreplied** | the destination's last message is already yours — you are about to double-post, so it prints a ready-to-paste `slack edit` command for that message instead |
|
|
73
|
+
| **self-DM** | DMing yourself with your own user token delivers but never notifies |
|
|
74
|
+
| **mentions** | `@handle` tokens that could not be resolved will post as plain text and notify nobody |
|
|
75
|
+
|
|
76
|
+
All four are `console.error` and fall through. The only hard stop in the whole path is a missing or
|
|
77
|
+
wrong `--code`.
|
|
78
|
+
|
|
79
|
+
That split is worth stating as a rule, because it is what keeps the system coherent: **irreversible
|
|
80
|
+
things get a gate; advisory things get a line on stderr.** Heuristics that can block teach people to
|
|
81
|
+
reach for a bypass flag — and the moment a bypass flag exists, it will eventually be used on the
|
|
82
|
+
real gate too. Because the fuzzy signals stay advisory, the repo ships **no `--yes`, no `--force`,
|
|
83
|
+
no `SKIP_CONFIRM`** at all.
|
|
84
|
+
|
|
85
|
+
## The honest part: it is a review gate, not an authorization gate
|
|
86
|
+
|
|
87
|
+
Here is the thing the project is refreshingly clear-eyed about. The gate holds no secret. The
|
|
88
|
+
expected code is deterministic, and the CLI prints it straight back to you on a wrong-code retry:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Code mismatch (got 0000, expected 3f9c)
|
|
92
|
+
Rerun with --code=3f9c
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Any script can defeat that in two lines — and the repo's own test suite does exactly that, regexing
|
|
96
|
+
`--code=([0-9a-f]{4})` out of stderr at roughly 19 call sites. The Rust implementation says so in
|
|
97
|
+
its own source: *"Always print the hash so scripts can capture and rerun."*
|
|
98
|
+
|
|
99
|
+
So the gate is not a permission boundary. It is a **forced-review step**: it makes the default path
|
|
100
|
+
one where a human or an agent must look at a rendered preview of exactly what will be posted, where,
|
|
101
|
+
and as whom, before anything happens. An agent determined to route around it can. The value is that
|
|
102
|
+
nothing does so *by accident* — and accident, not malice, is what actually posts to the wrong
|
|
103
|
+
channel at 3am.
|
|
104
|
+
|
|
105
|
+
Calling that out is better engineering than pretending otherwise, because a team that believes a
|
|
106
|
+
review gate is an authorization gate will eventually put something behind it that needed a real one.
|
|
107
|
+
|
|
108
|
+
## Display names are attacker-controlled
|
|
109
|
+
|
|
110
|
+
Anyone in a Slack workspace can set their own display name, and that name gets drawn into your
|
|
111
|
+
terminal — inside the confirm preview you are about to make a decision from.
|
|
112
|
+
`stripTerminalControls()` (`ts/cli.ts:811`) removes ANSI CSI sequences, all C0/C1 control characters
|
|
113
|
+
including a lone ESC, **and Unicode bidi controls** (LRM/RLM, LRE/RLE/PDF/LRO/RLO, LRI/RLI/FSI/PDI).
|
|
114
|
+
|
|
115
|
+
Stripping ANSI is common. Remembering that a right-to-left override can visually reorder the line
|
|
116
|
+
that is supposed to be telling you what you are about to send is not. Sanitizing *the preview
|
|
117
|
+
itself* follows from taking the gate seriously: a preview that can be made to lie is worse than no
|
|
118
|
+
preview, because it is trusted.
|
|
119
|
+
|
|
120
|
+
The coverage is deliberate but not yet total — it is applied to the sender label and the mention
|
|
121
|
+
previews; the gate's own quoted message previews and channel labels still render Slack-controlled
|
|
122
|
+
text unstripped.
|
|
123
|
+
|
|
124
|
+
## A denylist stored as hashes
|
|
125
|
+
|
|
126
|
+
The repo is public and its test fixtures come from real Slack recordings, so it treats its own
|
|
127
|
+
corpus as a leak risk. `.githooks/denylist.sha256` holds ~26 SHA-256 hashes and no plaintext, and
|
|
128
|
+
says why in the file:
|
|
129
|
+
|
|
130
|
+
> Stored as hashes on purpose: this repo is public, so it must not spell out the real names and IDs
|
|
131
|
+
> it is protecting.
|
|
132
|
+
|
|
133
|
+
A plaintext list of the names you are protecting is itself the disclosure. There is a second-order
|
|
134
|
+
reason too: plaintext would be rewritten by any future history scrub, silently inverting what the
|
|
135
|
+
hook blocks.
|
|
136
|
+
|
|
137
|
+
Two modes, and the docs are explicit about why both must exist:
|
|
138
|
+
|
|
139
|
+
| mode | sees | role |
|
|
140
|
+
| --- | --- | --- |
|
|
141
|
+
| default | the **staged diff** — added lines only | commit hook |
|
|
142
|
+
| `--all` | **every tracked file** | `prepublishOnly` + CI |
|
|
143
|
+
|
|
144
|
+
The commit hook is *structurally blind* to data already sitting in the tree: committed once, never
|
|
145
|
+
re-added by any later diff, therefore invisible to every future staged scan. That blind spot is not
|
|
146
|
+
hypothetical — it is how real workspace data once reached npm, and the whole-tree gate exists
|
|
147
|
+
specifically to close it. One scanner, three enforcement points (hook, CI, publish), no
|
|
148
|
+
reimplementation per venue.
|
|
149
|
+
|
|
150
|
+
The placeholder scheme deserves a mention because it is *machine-decidable* rather than a style
|
|
151
|
+
guide. A real Slack ID is a type letter followed by 8+ `[A-Z0-9]` **whose tail mixes letters and
|
|
152
|
+
digits**; a `0000` run separately marks an ID as fake. Testing the tail rather than the whole string
|
|
153
|
+
is load-bearing: the leading `C` of `C00000001` would otherwise count as "the letter" and make every
|
|
154
|
+
placeholder read as real. It scans fixture **filenames** as well as bodies.
|
|
155
|
+
|
|
156
|
+
## Built so an agent is a good citizen
|
|
157
|
+
|
|
158
|
+
The affordances that only make sense when the operator is a machine:
|
|
159
|
+
|
|
160
|
+
- **Reaction-as-ack is deliberately ungated** — "a reaction is trivial and fully reversible, and the
|
|
161
|
+
whole point is a lightweight ack." The cheap polite action stays frictionless while the loud one
|
|
162
|
+
stays gated. 👀 for *seen*, ✅ for *done*, ⏳ for *working on it* — a thread that does not grow.
|
|
163
|
+
- **`--unreplied`** — "only conversations whose last word isn't mine." Whose ball it is, computed
|
|
164
|
+
rather than guessed.
|
|
165
|
+
- **`[+N replies]`** — Slack's history endpoint returns thread parents but no replies, so a naive
|
|
166
|
+
renderer hides entire conversations. Marking them means a reader is never misled into thinking it
|
|
167
|
+
has read everything.
|
|
168
|
+
- **stdout is data, stderr is commentary** in the streaming path, so `slack tail "#general" | grep
|
|
169
|
+
deploy` sees messages and not chrome.
|
|
170
|
+
- **Output is valid input** — a printed permalink or ISO stamp can be pasted straight back as a
|
|
171
|
+
target, with strict parsers that throw rather than guess.
|
|
172
|
+
- **`SKILL.md` ships in the npm tarball** with agent-skill frontmatter, so it triggers on how a user
|
|
173
|
+
*talks* ("any mentions?", "DM @person") rather than on the tool's name.
|
|
174
|
+
|
|
175
|
+
Then there is `ts/todo.ts`, which encodes task state entirely in Slack reactions — 📌 marker,
|
|
176
|
+
✅/🚫/👀/⏳ progress, stacking reason flags — with no external store, so humans see the same state in
|
|
177
|
+
the Slack UI that the agent queries. Two comments in that file are the best writing in either repo.
|
|
178
|
+
|
|
179
|
+
The first records a **measured negative result**:
|
|
180
|
+
|
|
181
|
+
> the obvious alternative — posting a machine-readable token like `todo:v1 blocked-on=@alice` — does
|
|
182
|
+
> NOT work: Slack's full-text index splits on punctuation, so a quoted search for "blocked-on"
|
|
183
|
+
> returns 0 hits (measured), and "1.91" matches 1.91.0.
|
|
184
|
+
|
|
185
|
+
The second explains an ordering invariant:
|
|
186
|
+
|
|
187
|
+
> **ORDER IS THE WHOLE POINT**: `reactions.add` runs FIRST, then removes. Never invert this.
|
|
188
|
+
> Removing first leaves a window with zero progress reactions; a crash, a 429 or a Ctrl-C inside
|
|
189
|
+
> that window drops the task out of every `todo ls` query permanently, with nothing left to point at
|
|
190
|
+
> it.
|
|
191
|
+
|
|
192
|
+
Add-first's worst case is a message carrying two progress reactions — harmless, *because the
|
|
193
|
+
invariant is "at least one, readers collapse by priority" rather than "exactly one."* Choosing the
|
|
194
|
+
weaker invariant is what makes the operation safe to interrupt. Removes are awaited serially because
|
|
195
|
+
`Promise.all` would drop the ordering guarantee. That is the same reasoning agent-yes applies to its
|
|
196
|
+
own file-based fabric, arrived at independently against a completely different substrate.
|
|
197
|
+
|
|
198
|
+
## Where it is thinner than it looks
|
|
199
|
+
|
|
200
|
+
A fair reading has to include these.
|
|
201
|
+
|
|
202
|
+
**Credentials at rest are unhardened.** `~/.config/slack-cli/profiles.json` holds tokens and session
|
|
203
|
+
cookies and is written with `writeFileSync` and no `mode` argument, so it lands at the process umask
|
|
204
|
+
— typically world-readable. There is no `chmod` call anywhere in `ts/` or `rs/`. For a project this
|
|
205
|
+
careful about every other boundary, this is the odd one out.
|
|
206
|
+
|
|
207
|
+
**"Verified byte-for-byte" oversells the parity test.** The mechanism is real and well-built —
|
|
208
|
+
byte-identical stdout from both runtimes against a mock server, with an isolated `HOME` so no real
|
|
209
|
+
profile bleeds in — but it covers **2 of 23 commands** (`news`, `search`), and it *skips silently*
|
|
210
|
+
when the Rust binary or the fixtures are absent. A gate that skips by default is not a gate. Worse,
|
|
211
|
+
the one thing that most needs to match across implementations — the write gate — is the thing that
|
|
212
|
+
matches least: the Rust `send` uses `--confirm` rather than `--code`, binds neither the thread nor
|
|
213
|
+
the acting identity, and collapses to `sha256(message)` when its context fetch comes back empty.
|
|
214
|
+
|
|
215
|
+
The two runtimes are not really peers; one is the product and the other is a frozen subset. Compare
|
|
216
|
+
agent-yes, which has the same TS/Rust split and solves it with the opposite polarity: it does not
|
|
217
|
+
diff behavior, it *pins the surface* — a test parses both `ts/subcommands.ts` and `rs/src/cli.rs` as
|
|
218
|
+
text and fails when the subcommand lists disagree, and everything else lives in a parity table
|
|
219
|
+
allowed to say "not planned." Enforce the surface, negotiate the behavior.
|
|
220
|
+
|
|
221
|
+
**`SKILL.md` still points agents at a deprecated package.** It says to install `@snomiao/slack`; the
|
|
222
|
+
README marks that deprecated in favour of `slack-term`. Of the three, this is the one that actively
|
|
223
|
+
misleads, because SKILL.md is the file an agent reads.
|
|
224
|
+
|
|
225
|
+
## What carries over
|
|
226
|
+
|
|
227
|
+
Three ideas here are worth stealing regardless of Slack:
|
|
228
|
+
|
|
229
|
+
1. **Bind your confirmation to the state that would change your mind.** Not a nonce, not a
|
|
230
|
+
timestamp — the destination, the actor, and the conversation's current last message. It goes
|
|
231
|
+
stale exactly when it should.
|
|
232
|
+
2. **Gates block, guards warn — and never mix them.** One hard stop, uniformly applied, is
|
|
233
|
+
comprehensible and needs no bypass flag. The moment a fuzzy heuristic can block, someone builds a
|
|
234
|
+
`--force`, and then it is on the real gate too.
|
|
235
|
+
3. **Say which one you built.** A forced-review step and an authorization boundary look similar from
|
|
236
|
+
the outside and fail very differently. Naming it correctly is what stops someone putting
|
|
237
|
+
something behind it that needed the other kind.
|
|
238
|
+
|
|
239
|
+
<p class="note">Related: <a href="./2026-08-11-an-address-space-for-agents">an address space for
|
|
240
|
+
agents</a> — why a fleet needs a bus that humans are on too.</p>
|
package/package.json
CHANGED
package/ts/remotes.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { mkdir, readFile, writeFile } from "fs/promises";
|
|
|
2
2
|
import { homedir } from "os";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import yaml from "yaml";
|
|
5
|
-
import { isWebrtcSpec } from "./webrtcLink.ts";
|
|
5
|
+
import { isWebrtcSpec, parseWebrtcLink } from "./webrtcLink.ts";
|
|
6
6
|
|
|
7
7
|
function remotesPath(): string {
|
|
8
8
|
const dir = process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes");
|
|
@@ -18,6 +18,14 @@ export interface ResolvedRemote {
|
|
|
18
18
|
url: string;
|
|
19
19
|
token: string;
|
|
20
20
|
keyword?: string;
|
|
21
|
+
/** Stable, human-readable name for display — never the loopback bridge URL. */
|
|
22
|
+
label: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A display label for a WebRTC share link: the room id, never the local bridge. */
|
|
26
|
+
function webrtcLabel(link: string): string {
|
|
27
|
+
const parsed = parseWebrtcLink(link);
|
|
28
|
+
return parsed ? `webrtc:${parsed.room}` : "webrtc";
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
export async function readRemotes(): Promise<Map<string, RemoteConfig>> {
|
|
@@ -82,11 +90,16 @@ export function parseDirectRemoteSpec(
|
|
|
82
90
|
export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote | null> {
|
|
83
91
|
// Inline WebRTC share link: `ay ls webrtc://…` or `ay ls https://…/w/#room:token`.
|
|
84
92
|
// These carry their own secret and have no keyword (use an alias to add one).
|
|
85
|
-
if (isWebrtcSpec(spec)) return resolveWebrtc(spec, undefined);
|
|
93
|
+
if (isWebrtcSpec(spec)) return resolveWebrtc(spec, undefined, webrtcLabel(spec));
|
|
86
94
|
|
|
87
95
|
const direct = parseDirectRemoteSpec(spec);
|
|
88
96
|
if (direct) {
|
|
89
|
-
return {
|
|
97
|
+
return {
|
|
98
|
+
url: direct.baseUrl,
|
|
99
|
+
token: direct.token,
|
|
100
|
+
keyword: direct.keyword,
|
|
101
|
+
label: `${direct.host}:${direct.port}`,
|
|
102
|
+
};
|
|
90
103
|
}
|
|
91
104
|
|
|
92
105
|
// alias[:keyword]
|
|
@@ -98,8 +111,8 @@ export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote |
|
|
|
98
111
|
const cfg = remotes.get(alias);
|
|
99
112
|
if (!cfg) return null;
|
|
100
113
|
// A saved alias may point at a WebRTC link; bridge it just like an inline one.
|
|
101
|
-
if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword);
|
|
102
|
-
return { url: cfg.url, token: cfg.token, keyword };
|
|
114
|
+
if (isWebrtcSpec(cfg.url)) return resolveWebrtc(cfg.url, keyword, alias);
|
|
115
|
+
return { url: cfg.url, token: cfg.token, keyword, label: alias };
|
|
103
116
|
}
|
|
104
117
|
|
|
105
118
|
/**
|
|
@@ -107,10 +120,14 @@ export async function resolveRemoteSpec(spec: string): Promise<ResolvedRemote |
|
|
|
107
120
|
* ordinary http remote, so every fetch-based remote command works unchanged.
|
|
108
121
|
* The bridge lives for the rest of the process (torn down on `process.exit`).
|
|
109
122
|
*/
|
|
110
|
-
async function resolveWebrtc(
|
|
123
|
+
async function resolveWebrtc(
|
|
124
|
+
link: string,
|
|
125
|
+
keyword: string | undefined,
|
|
126
|
+
label: string,
|
|
127
|
+
): Promise<ResolvedRemote> {
|
|
111
128
|
const { startWebrtcBridge } = await import("./webrtcRemote.ts");
|
|
112
129
|
const bridge = await startWebrtcBridge(link);
|
|
113
|
-
return { url: bridge.baseUrl, token: bridge.token, keyword };
|
|
130
|
+
return { url: bridge.baseUrl, token: bridge.token, keyword, label };
|
|
114
131
|
}
|
|
115
132
|
|
|
116
133
|
// ---------------------------------------------------------------------------
|
package/ts/subcommands.ts
CHANGED
|
@@ -1181,12 +1181,12 @@ async function runRemoteLs(
|
|
|
1181
1181
|
if (records.length === 0) {
|
|
1182
1182
|
process.stderr.write(
|
|
1183
1183
|
remote.keyword
|
|
1184
|
-
? `no agents matched "${remote.keyword}" on ${remote.
|
|
1185
|
-
: `no running agents on ${remote.
|
|
1184
|
+
? `no agents matched "${remote.keyword}" on ${remote.label}\n`
|
|
1185
|
+
: `no running agents on ${remote.label}\n`,
|
|
1186
1186
|
);
|
|
1187
1187
|
return 0;
|
|
1188
1188
|
}
|
|
1189
|
-
process.stderr.write(`[remote ${remote.
|
|
1189
|
+
process.stderr.write(`[remote ${remote.label}]\n`);
|
|
1190
1190
|
const termWidth = (process.stdout as any).columns ?? 120;
|
|
1191
1191
|
const widths = {
|
|
1192
1192
|
pid: Math.max(3, ...records.map((r: any) => String(r.pid).length)),
|
|
@@ -1249,7 +1249,7 @@ async function runRemoteRead(
|
|
|
1249
1249
|
let attempt = 0;
|
|
1250
1250
|
|
|
1251
1251
|
process.stderr.write(
|
|
1252
|
-
`[remote ${remote.
|
|
1252
|
+
`[remote ${remote.label} ${keyword}]\nfollowing... (Ctrl-C to stop, timeout: ${Math.round(reconnectTimeoutMs / 1000)}s)\n`,
|
|
1253
1253
|
);
|
|
1254
1254
|
|
|
1255
1255
|
while (!ac.signal.aborted) {
|
|
@@ -1325,7 +1325,7 @@ async function runRemoteRead(
|
|
|
1325
1325
|
return 1;
|
|
1326
1326
|
}
|
|
1327
1327
|
const text = await res.text();
|
|
1328
|
-
process.stderr.write(`[remote ${remote.
|
|
1328
|
+
process.stderr.write(`[remote ${remote.label} ${keyword}]\n`);
|
|
1329
1329
|
process.stdout.write(text);
|
|
1330
1330
|
if (!text.endsWith("\n")) process.stdout.write("\n");
|
|
1331
1331
|
return 0;
|
|
@@ -1359,7 +1359,7 @@ async function runRemoteSend(remote: ResolvedRemote, msg: string, code: string):
|
|
|
1359
1359
|
cwd?: string;
|
|
1360
1360
|
agentId?: string;
|
|
1361
1361
|
};
|
|
1362
|
-
process.stdout.write(`sent to remote pid ${data.pid} (${remote.
|
|
1362
|
+
process.stdout.write(`sent to remote pid ${data.pid} (${remote.label} ${keyword})\n`);
|
|
1363
1363
|
// Record the sender's half of the exchange locally (the recipient's inbox is
|
|
1364
1364
|
// recorded on the remote host by its /api/send handler). Only real bodies.
|
|
1365
1365
|
if (msg && msg !== "-") {
|
|
@@ -1376,7 +1376,7 @@ async function runRemoteSend(remote: ResolvedRemote, msg: string, code: string):
|
|
|
1376
1376
|
code: code.toLowerCase() === "enter" ? undefined : code.toLowerCase(),
|
|
1377
1377
|
confirmed: true,
|
|
1378
1378
|
wrapped: false,
|
|
1379
|
-
remote: remote.
|
|
1379
|
+
remote: remote.label,
|
|
1380
1380
|
});
|
|
1381
1381
|
}
|
|
1382
1382
|
return 0;
|
|
@@ -1419,7 +1419,7 @@ async function runRemoteSpawn(
|
|
|
1419
1419
|
if (name === "TimeoutError" || name === "AbortError") {
|
|
1420
1420
|
// The request may or may not have spawned — do NOT retry. Let the operator check.
|
|
1421
1421
|
process.stderr.write(
|
|
1422
|
-
`remote spawn: no response from ${remote.
|
|
1422
|
+
`remote spawn: no response from ${remote.label} within ${Math.round(SPAWN_TIMEOUT_MS / 1000)}s — ` +
|
|
1423
1423
|
`result UNKNOWN (not retried).\n ay ls ${hint} # check whether it started\n`,
|
|
1424
1424
|
);
|
|
1425
1425
|
return 2;
|
|
@@ -1440,7 +1440,7 @@ async function runRemoteSpawn(
|
|
|
1440
1440
|
provisioned?: { action: string };
|
|
1441
1441
|
};
|
|
1442
1442
|
process.stdout.write(
|
|
1443
|
-
`spawned ${r.cli} on ${remote.
|
|
1443
|
+
`spawned ${r.cli} on ${remote.label} in ${r.cwd}` +
|
|
1444
1444
|
`${r.hook ? " (via spawn hook)" : ""}` +
|
|
1445
1445
|
`${r.provisioned ? ` (${r.provisioned.action})` : ""}\n`,
|
|
1446
1446
|
);
|
package/dist/trayApp-XJit7gRr.js
DELETED