@songsid/agend 2.1.8 → 2.1.10-beta.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/README.md +8 -3
- package/README.zh-TW.md +11 -5
- package/dist/backend/claude-code.d.ts +35 -5
- package/dist/backend/claude-code.js +288 -17
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +13 -0
- package/dist/backend/codex.js +74 -2
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +9 -0
- package/dist/backend/credential-profile.js +20 -0
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/grok.js +19 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +0 -2
- package/dist/backend/kiro.js +8 -7
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.d.ts +6 -0
- package/dist/backend/muse.js +7 -1
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +1 -1
- package/dist/channel/adapters/telegram.js +4 -3
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-operation-response.js +5 -4
- package/dist/channel/mcp-operation-response.js.map +1 -1
- package/dist/channel/mcp-server.js +9 -0
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.js +1 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +7 -0
- package/dist/cli.js +150 -52
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +24 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +27 -1
- package/dist/config.js.map +1 -1
- package/dist/cross-instance-envelope.d.ts +7 -0
- package/dist/cross-instance-envelope.js +19 -1
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +112 -3
- package/dist/daemon.js +360 -41
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +9 -1
- package/dist/delivery-outbox.js +43 -27
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-manager.d.ts +133 -5
- package/dist/fleet-manager.js +525 -86
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +160 -0
- package/dist/forged-envelope-scan.js +309 -0
- package/dist/forged-envelope-scan.js.map +1 -0
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +5 -2
- package/dist/instance-lifecycle.d.ts +90 -6
- package/dist/instance-lifecycle.js +238 -30
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +180 -8
- package/dist/locale.js.map +1 -1
- package/dist/login-controller.d.ts +38 -0
- package/dist/login-controller.js +236 -8
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.d.ts +25 -1
- package/dist/login-flows.js +10 -2
- package/dist/login-flows.js.map +1 -1
- package/dist/ls-rows.d.ts +17 -0
- package/dist/ls-rows.js +73 -0
- package/dist/ls-rows.js.map +1 -1
- package/dist/outbound-handlers.d.ts +3 -0
- package/dist/outbound-handlers.js +17 -19
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +2 -0
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/paths.js +4 -2
- package/dist/paths.js.map +1 -1
- package/dist/pause-marker.d.ts +10 -1
- package/dist/pause-marker.js +26 -2
- package/dist/pause-marker.js.map +1 -1
- package/dist/routing-engine.d.ts +17 -2
- package/dist/routing-engine.js +48 -5
- package/dist/routing-engine.js.map +1 -1
- package/dist/service-installer.d.ts +8 -0
- package/dist/service-installer.js +36 -1
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.d.ts +2 -0
- package/dist/settings-api.js +3 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/setup-wizard.js +3 -1
- package/dist/setup-wizard.js.map +1 -1
- package/dist/status-emojis.d.ts +9 -1
- package/dist/status-emojis.js +11 -1
- package/dist/status-emojis.js.map +1 -1
- package/dist/target-queue-worker.d.ts +67 -0
- package/dist/target-queue-worker.js +76 -0
- package/dist/target-queue-worker.js.map +1 -0
- package/dist/tool-permissions.js +7 -2
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +23 -19
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.d.ts +30 -0
- package/dist/transcript-sources.js +78 -0
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +23 -5
- package/dist/tunnel/cloudflared.js +32 -13
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/manager.d.ts +6 -0
- package/dist/tunnel/manager.js +60 -22
- package/dist/tunnel/manager.js.map +1 -1
- package/dist/tunnel/public-fetch.d.ts +30 -0
- package/dist/tunnel/public-fetch.js +156 -0
- package/dist/tunnel/public-fetch.js.map +1 -0
- package/dist/tunnel/types.d.ts +8 -2
- package/dist/tunnel/types.js +8 -2
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +50 -1
- package/dist/types.js +9 -1
- package/dist/types.js.map +1 -1
- package/dist/ui/settings.html +2 -2
- package/dist/ui/view.html +14 -0
- package/dist/ui/web-terminal/terminal.html +1 -0
- package/dist/wake-coordinator.d.ts +128 -0
- package/dist/wake-coordinator.js +337 -0
- package/dist/wake-coordinator.js.map +1 -0
- package/dist/web-api.d.ts +3 -1
- package/dist/web-api.js +1 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-host-guard.d.ts +47 -0
- package/dist/web-host-guard.js +75 -0
- package/dist/web-host-guard.js.map +1 -0
- package/dist/web-terminal-http.d.ts +34 -0
- package/dist/web-terminal-http.js +63 -0
- package/dist/web-terminal-http.js.map +1 -1
- package/dist/web-terminal.d.ts +2 -0
- package/dist/web-terminal.js +3 -6
- package/dist/web-terminal.js.map +1 -1
- package/package.json +1 -1
- package/templates/systemd.service.ejs +7 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The readiness probe's way of seeing a tunnel the way a phone does.
|
|
3
|
+
*
|
|
4
|
+
* A brand-new `*.trycloudflare.com` name resolves instantly through a public
|
|
5
|
+
* resolver and, on a corporate or WSL network, can take a minute or more
|
|
6
|
+
* through the machine's own forwarder (measured: 1.1.1.1 in ~13 ms, the system
|
|
7
|
+
* resolver 60 s+). Probing through the system resolver therefore reports a
|
|
8
|
+
* tunnel that works as "never became reachable". So the probe asks a public
|
|
9
|
+
* resolver, then connects to the address it was given with the real hostname
|
|
10
|
+
* as SNI and `Host` — certificate verification still runs against the
|
|
11
|
+
* hostname, so a wrong or forged answer yields a TLS failure, never a page.
|
|
12
|
+
*
|
|
13
|
+
* Only the probe does this. The browser that actually uses the tunnel resolves
|
|
14
|
+
* however it resolves. The one thing that leaves the machine is a DNS query
|
|
15
|
+
* for the tunnel's random hostname, sent to Cloudflare, who is already
|
|
16
|
+
* carrying the tunnel.
|
|
17
|
+
*
|
|
18
|
+
* The system resolver stays as the fallback: a network that blocks outbound
|
|
19
|
+
* DNS to 1.1.1.1 must not make a working tunnel look dead.
|
|
20
|
+
*/
|
|
21
|
+
import { isIPv4 } from "node:net";
|
|
22
|
+
import { request as httpsRequest } from "node:https";
|
|
23
|
+
import { Resolver } from "node:dns/promises";
|
|
24
|
+
export const PUBLIC_RESOLVERS = ["1.1.1.1", "1.0.0.1"];
|
|
25
|
+
/** One DNS attempt is short: the caller retries, and the whole probe has a deadline. */
|
|
26
|
+
const RESOLVE_TIMEOUT_MS = 3_000;
|
|
27
|
+
/** The probe wants a page, not a download. Exactly this many bytes are accepted; one more is refused. */
|
|
28
|
+
export const MAX_PROBE_BODY = 256 * 1024;
|
|
29
|
+
/** Addresses a public resolver has no business returning for a Cloudflare edge name. */
|
|
30
|
+
export function isPublicIPv4(ip) {
|
|
31
|
+
if (!isIPv4(ip))
|
|
32
|
+
return false;
|
|
33
|
+
const [a, b] = ip.split(".").map(Number);
|
|
34
|
+
if (a === 0 || a === 10 || a === 127)
|
|
35
|
+
return false;
|
|
36
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
37
|
+
return false; // CGNAT
|
|
38
|
+
if (a === 169 && b === 254)
|
|
39
|
+
return false; // link-local
|
|
40
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
41
|
+
return false;
|
|
42
|
+
if (a === 192 && b === 168)
|
|
43
|
+
return false;
|
|
44
|
+
if (a >= 224)
|
|
45
|
+
return false; // multicast / reserved
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
function defaultResolve4(resolvers) {
|
|
49
|
+
const resolver = new Resolver({ timeout: RESOLVE_TIMEOUT_MS, tries: 1 });
|
|
50
|
+
resolver.setServers([...resolvers]);
|
|
51
|
+
return host => resolver.resolve4(host);
|
|
52
|
+
}
|
|
53
|
+
export async function fetchViaPublicResolver(url, signal, deps) {
|
|
54
|
+
const resolvers = deps.resolvers ?? PUBLIC_RESOLVERS;
|
|
55
|
+
let target;
|
|
56
|
+
try {
|
|
57
|
+
target = new URL(url);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return deps.fallback(url, signal);
|
|
61
|
+
}
|
|
62
|
+
if (resolvers.length === 0 || target.protocol !== "https:")
|
|
63
|
+
return deps.fallback(url, signal);
|
|
64
|
+
let address;
|
|
65
|
+
try {
|
|
66
|
+
const resolve4 = deps.resolve4 ?? defaultResolve4(resolvers);
|
|
67
|
+
address = (await resolve4(target.hostname)).find(isPublicIPv4);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
address = undefined;
|
|
71
|
+
}
|
|
72
|
+
// No usable answer from the public resolver: say nothing about the tunnel,
|
|
73
|
+
// just let the ordinary path try.
|
|
74
|
+
if (!address)
|
|
75
|
+
return deps.fallback(url, signal);
|
|
76
|
+
return requestAt(address, target, signal, deps.request ?? httpsRequest);
|
|
77
|
+
}
|
|
78
|
+
function requestAt(address, target, signal, request) {
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const options = {
|
|
81
|
+
host: address,
|
|
82
|
+
port: 443,
|
|
83
|
+
method: "GET",
|
|
84
|
+
path: `${target.pathname}${target.search}`,
|
|
85
|
+
// Both, and the hostname for both purposes: SNI picks the certificate,
|
|
86
|
+
// `servername` is also what the certificate is verified against, and
|
|
87
|
+
// `Host` is what the edge routes on. Never `rejectUnauthorized: false`.
|
|
88
|
+
servername: target.hostname,
|
|
89
|
+
headers: { host: target.hostname, "cache-control": "no-store" },
|
|
90
|
+
signal,
|
|
91
|
+
};
|
|
92
|
+
const req = request(options, res => {
|
|
93
|
+
const status = res.statusCode ?? 0;
|
|
94
|
+
const contentType = String(res.headers["content-type"] ?? "");
|
|
95
|
+
res.on("error", reject);
|
|
96
|
+
// Only a 200 can be the page. Any other body is discarded as it arrives, not collected.
|
|
97
|
+
if (status !== 200) {
|
|
98
|
+
res.on("end", () => resolve({ status, contentType, body: "" }));
|
|
99
|
+
res.resume();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const chunks = [];
|
|
103
|
+
let size = 0;
|
|
104
|
+
res.on("data", (chunk) => {
|
|
105
|
+
size += chunk.length;
|
|
106
|
+
if (size > MAX_PROBE_BODY) {
|
|
107
|
+
req.destroy(new Error("probe response too large"));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
chunks.push(chunk);
|
|
111
|
+
});
|
|
112
|
+
res.on("end", () => resolve({ status, contentType, body: Buffer.concat(chunks).toString("utf8") }));
|
|
113
|
+
});
|
|
114
|
+
req.on("error", reject);
|
|
115
|
+
req.end();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The ordinary path — the system resolver, a plain `fetch` — with the same limits as the public one.
|
|
120
|
+
*
|
|
121
|
+
* `res.text()` has no ceiling, and this is the path taken exactly when public DNS is unavailable, so the
|
|
122
|
+
* cap has to live here too. A redirect is not this page, and following one would let the edge decide
|
|
123
|
+
* what we call ready.
|
|
124
|
+
*/
|
|
125
|
+
export async function fetchViaSystemResolver(url, signal, fetchImpl = fetch) {
|
|
126
|
+
const res = await fetchImpl(url, { signal, redirect: "manual", cache: "no-store" });
|
|
127
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
128
|
+
if (res.status !== 200) {
|
|
129
|
+
await res.body?.cancel().catch(() => { });
|
|
130
|
+
return { status: res.status, contentType, body: "" };
|
|
131
|
+
}
|
|
132
|
+
return { status: 200, contentType, body: await readBoundedText(res.body) };
|
|
133
|
+
}
|
|
134
|
+
async function readBoundedText(body) {
|
|
135
|
+
if (!body)
|
|
136
|
+
return "";
|
|
137
|
+
const reader = body.getReader();
|
|
138
|
+
const chunks = [];
|
|
139
|
+
let size = 0;
|
|
140
|
+
try {
|
|
141
|
+
for (;;) {
|
|
142
|
+
const { done, value } = await reader.read();
|
|
143
|
+
if (done)
|
|
144
|
+
break;
|
|
145
|
+
size += value.byteLength;
|
|
146
|
+
if (size > MAX_PROBE_BODY)
|
|
147
|
+
throw new Error("probe response too large");
|
|
148
|
+
chunks.push(value);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
await reader.cancel().catch(() => { });
|
|
153
|
+
}
|
|
154
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=public-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-fetch.js","sourceRoot":"","sources":["../../src/tunnel/public-fetch.ts"],"names":[],"mappings":"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"}
|
package/dist/tunnel/types.d.ts
CHANGED
|
@@ -111,8 +111,14 @@ export declare class TunnelStartError extends Error {
|
|
|
111
111
|
readonly identity: string | null;
|
|
112
112
|
} | undefined);
|
|
113
113
|
}
|
|
114
|
-
/**
|
|
115
|
-
|
|
114
|
+
/**
|
|
115
|
+
* One wall-clock budget for spawn, URL and readiness together — not per step.
|
|
116
|
+
*
|
|
117
|
+
* A minute: with QUIC blocked and a slow resolver in between, a tunnel that does
|
|
118
|
+
* work can take well over thirty seconds to become reachable, and giving up on it
|
|
119
|
+
* is a worse outcome than waiting for it.
|
|
120
|
+
*/
|
|
121
|
+
export declare const TUNNEL_STARTUP_DEADLINE_MS = 60000;
|
|
116
122
|
/** Preflight is a stat, not a network call. */
|
|
117
123
|
export declare const TUNNEL_PREFLIGHT_TIMEOUT_MS = 5000;
|
|
118
124
|
/** How long a polite stop is given before escalating, and again before giving up. */
|
package/dist/tunnel/types.js
CHANGED
|
@@ -24,8 +24,14 @@ export class TunnelStartError extends Error {
|
|
|
24
24
|
this.name = "TunnelStartError";
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
27
|
+
/**
|
|
28
|
+
* One wall-clock budget for spawn, URL and readiness together — not per step.
|
|
29
|
+
*
|
|
30
|
+
* A minute: with QUIC blocked and a slow resolver in between, a tunnel that does
|
|
31
|
+
* work can take well over thirty seconds to become reachable, and giving up on it
|
|
32
|
+
* is a worse outcome than waiting for it.
|
|
33
|
+
*/
|
|
34
|
+
export const TUNNEL_STARTUP_DEADLINE_MS = 60_000;
|
|
29
35
|
/** Preflight is a stat, not a network call. */
|
|
30
36
|
export const TUNNEL_PREFLIGHT_TIMEOUT_MS = 5_000;
|
|
31
37
|
/** How long a polite stop is given before escalating, and again before giving up. */
|
package/dist/tunnel/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tunnel/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAoGH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAE9B;IAGA;IAJX,YACW,SAA0B,EACnC,OAAe;IACf,6EAA6E;IACpE,WAA+E;QAExF,KAAK,CAAC,OAAO,CAAC,CAAC;QALN,cAAS,GAAT,SAAS,CAAiB;QAG1B,gBAAW,GAAX,WAAW,CAAoE;QAGxF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tunnel/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAoGH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAE9B;IAGA;IAJX,YACW,SAA0B,EACnC,OAAe;IACf,6EAA6E;IACpE,WAA+E;QAExF,KAAK,CAAC,OAAO,CAAC,CAAC;QALN,cAAS,GAAT,SAAS,CAAiB;QAG1B,gBAAW,GAAX,WAAW,CAAoE;QAGxF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AACjD,+CAA+C;AAC/C,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,CAAC;AACjD,qFAAqF;AACrF,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -76,6 +76,17 @@ export interface ChannelConfig {
|
|
|
76
76
|
/** Topic ID for mirroring all cross-instance messages (read-only observation). */
|
|
77
77
|
mirror_topic_id?: number | string;
|
|
78
78
|
}
|
|
79
|
+
export type DeliveryWorkerMode = "off" | "wake_only" | "on";
|
|
80
|
+
export declare const DELIVERY_WORKER_MODES: readonly DeliveryWorkerMode[];
|
|
81
|
+
/** The delivery_worker mode for `name`: instance override, then fleet default, then "off". */
|
|
82
|
+
export declare function resolveDeliveryWorkerMode(config: {
|
|
83
|
+
defaults?: {
|
|
84
|
+
delivery_worker?: unknown;
|
|
85
|
+
};
|
|
86
|
+
instances?: Record<string, {
|
|
87
|
+
delivery_worker?: unknown;
|
|
88
|
+
}>;
|
|
89
|
+
} | null | undefined, name: string): DeliveryWorkerMode;
|
|
79
90
|
export interface InstanceConfig {
|
|
80
91
|
working_directory: string;
|
|
81
92
|
/** Minutes an idle CLI may remain resident before auto-pause. 0 disables it. */
|
|
@@ -87,12 +98,26 @@ export interface InstanceConfig {
|
|
|
87
98
|
* 0 = unlimited (default). Complementary to auto_pause_after (time-based).
|
|
88
99
|
*/
|
|
89
100
|
warm_cap?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Phase 2b: how far `defaults.warm_cap` may be exceeded to wake targets for
|
|
103
|
+
* queued durable work (delivery_worker ≠ off). Default 2. The hard cap is
|
|
104
|
+
* warm_cap + warm_overflow; with warm_cap 0 there is no cap at all.
|
|
105
|
+
*/
|
|
106
|
+
warm_overflow?: number;
|
|
107
|
+
/**
|
|
108
|
+
* Phase 2 delivery owner for this target (docs/design/phase2-submit-contract.md):
|
|
109
|
+
* `off` (default) keeps the current outbox pump, `wake_only` adds the wake
|
|
110
|
+
* coordinator (2b), `on` hands claim/submit to the per-target worker (2c).
|
|
111
|
+
* Read from `defaults.delivery_worker` with a per-instance override. In 2a
|
|
112
|
+
* only the setting exists — every mode behaves as `off`.
|
|
113
|
+
*/
|
|
114
|
+
delivery_worker?: DeliveryWorkerMode;
|
|
90
115
|
/** Agent display name (e.g. "Kuro", "Luna") — chosen by the agent itself */
|
|
91
116
|
display_name?: string;
|
|
92
117
|
/**
|
|
93
118
|
* #1005: this instance's own delivery-status emojis, overriding its
|
|
94
119
|
* channel's `options.status_emojis` per key. Keys: received, queued,
|
|
95
|
-
* processing, delivered, failed, progress_prefix.
|
|
120
|
+
* processing, delivered, failed, progress_prefix, photo, attachment.
|
|
96
121
|
*/
|
|
97
122
|
status_emojis?: import("./status-emojis.js").StatusEmojiConfig;
|
|
98
123
|
/** Human-readable description of what this instance does */
|
|
@@ -293,12 +318,34 @@ export interface WebConfig {
|
|
|
293
318
|
usage_panel?: boolean;
|
|
294
319
|
/** Expose provider API-key verify/apply endpoints (default false until dark-shipped). */
|
|
295
320
|
provider_secrets?: boolean;
|
|
321
|
+
/**
|
|
322
|
+
* Extra `Host` names the dashboard answers to, for a reverse proxy or port
|
|
323
|
+
* forward that presents a name other than localhost / 127.0.0.1 / [::1] / `hostname`.
|
|
324
|
+
* Names only (a port is ignored); anything not listed is refused with 403.
|
|
325
|
+
*/
|
|
326
|
+
allowed_hosts?: string[];
|
|
296
327
|
}
|
|
297
328
|
/** `login:` section — remote /login behaviour. */
|
|
298
329
|
export interface LoginConfig {
|
|
299
330
|
/** web (default): token-gated browser terminal. relay: the pre-2.1.5 chat relay, kept for rollback in 2.1.5 only. */
|
|
300
331
|
mode?: "web" | "relay";
|
|
301
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* `web_terminal.tunnel:` — the escape hatch for finishing a /login from somewhere that cannot
|
|
335
|
+
* reach this machine (a phone away from the desk). Off unless `allow_public` is true, and even
|
|
336
|
+
* then each login asks first and only flows marked `tunnelOk` may use it.
|
|
337
|
+
*/
|
|
338
|
+
export interface WebTerminalTunnelConfig {
|
|
339
|
+
/** The only provider today: a Cloudflare Quick Tunnel. */
|
|
340
|
+
provider?: "cloudflared";
|
|
341
|
+
/**
|
|
342
|
+
* Whether /login may offer to open a temporary public HTTPS link to its terminal.
|
|
343
|
+
* Default false — nothing is ever exposed beyond this machine unless you set it.
|
|
344
|
+
*/
|
|
345
|
+
allow_public?: boolean;
|
|
346
|
+
/** How cloudflared reaches Cloudflare. Default http2 (QUIC is blocked on many networks); auto lets cloudflared choose. */
|
|
347
|
+
protocol?: "http2" | "quic" | "auto";
|
|
348
|
+
}
|
|
302
349
|
/** `web_terminal:` section — the browser terminal behind /login and /install-cli. */
|
|
303
350
|
export interface WebTerminalConfig {
|
|
304
351
|
/** Default true. false makes /login refuse in web mode. */
|
|
@@ -307,6 +354,8 @@ export interface WebTerminalConfig {
|
|
|
307
354
|
bind?: string;
|
|
308
355
|
/** Session time limit. 1..20 (engine hard cap 20), default 10. */
|
|
309
356
|
ttl_minutes?: number;
|
|
357
|
+
/** Optional public link for /login (see WebTerminalTunnelConfig). Absent = never. */
|
|
358
|
+
tunnel?: WebTerminalTunnelConfig;
|
|
310
359
|
}
|
|
311
360
|
export interface FleetConfig {
|
|
312
361
|
channel?: ChannelConfig;
|
package/dist/types.js
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const DELIVERY_WORKER_MODES = ["off", "wake_only", "on"];
|
|
2
|
+
/** The delivery_worker mode for `name`: instance override, then fleet default, then "off". */
|
|
3
|
+
export function resolveDeliveryWorkerMode(config, name) {
|
|
4
|
+
for (const value of [config?.instances?.[name]?.delivery_worker, config?.defaults?.delivery_worker]) {
|
|
5
|
+
if (typeof value === "string" && DELIVERY_WORKER_MODES.includes(value))
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
return "off";
|
|
9
|
+
}
|
|
2
10
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAgFA,MAAM,CAAC,MAAM,qBAAqB,GAAkC,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;AAE/F,8FAA8F;AAC9F,MAAM,UAAU,yBAAyB,CACvC,MAAkI,EAClI,IAAY;IAEZ,KAAK,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC;QACpG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAK,qBAA2C,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,KAA2B,CAAC;IACpI,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/ui/settings.html
CHANGED
|
@@ -263,7 +263,7 @@
|
|
|
263
263
|
description: "Description", systemPrompt: "System prompt", tags: "Tags", generalTopicField: "General topic (fleet dispatcher)",
|
|
264
264
|
runtimeResources: "Runtime & Resources", autoPause: "Auto-pause after", minutes: "minutes", inheritDefault: "Inherit from defaults",
|
|
265
265
|
statusEmojis: "Status emojis", statusEmojisInstance: "This agent's status emojis (override the connection's)", statusEmojisChannel: "Status emojis for this connection's bots",
|
|
266
|
-
se_received: "Received", se_queued: "Queued", se_processing: "Processing", se_delivered: "Delivered", se_failed: "Failed", se_progress_prefix: "Progress prefix",
|
|
266
|
+
se_received: "Received", se_queued: "Queued", se_processing: "Processing", se_delivered: "Delivered", se_failed: "Failed", se_progress_prefix: "Progress prefix", se_photo: "Photo saved", se_attachment: "File saved",
|
|
267
267
|
se_src_instance: "agent", se_src_platform: "connection", se_src_builtin: "default", se_pick: "Pick…", se_useDefault: "Use the default", se_fallback: "the default is used instead",
|
|
268
268
|
se_unicode: "Emoji", se_telegramOnly: "Telegram allows only these reactions", se_serverEmojis: "Server emojis", se_noServerEmojis: "No custom emojis on this server.", se_primaryServer: "primary", se_externalEmojiHint: "Another server's emoji needs the bot's Use External Emojis permission in the channel it reacts in.", se_unavailable: "unavailable",
|
|
269
269
|
se_hint: "Empty keeps the default. The preview is resolved by AgEnD exactly as the bot will react.",
|
|
@@ -315,7 +315,7 @@
|
|
|
315
315
|
},
|
|
316
316
|
"zh-TW": {
|
|
317
317
|
statusEmojis: "狀態 emoji", statusEmojisInstance: "此 Agent 的狀態 emoji(覆蓋連線設定)", statusEmojisChannel: "此連線 bot 的狀態 emoji",
|
|
318
|
-
se_received: "已收到", se_queued: "排隊中", se_processing: "處理中", se_delivered: "已送達", se_failed: "失敗", se_progress_prefix: "進度前綴",
|
|
318
|
+
se_received: "已收到", se_queued: "排隊中", se_processing: "處理中", se_delivered: "已送達", se_failed: "失敗", se_progress_prefix: "進度前綴", se_photo: "已存圖片", se_attachment: "已存檔案",
|
|
319
319
|
se_src_instance: "Agent", se_src_platform: "連線", se_src_builtin: "預設", se_pick: "選擇…", se_useDefault: "使用預設", se_fallback: "改用預設值",
|
|
320
320
|
se_unicode: "Emoji", se_telegramOnly: "Telegram 只允許這些反應", se_serverEmojis: "伺服器 emoji", se_noServerEmojis: "此伺服器沒有自訂 emoji。", se_primaryServer: "主伺服器", se_externalEmojiHint: "使用其他伺服器的 emoji,bot 在要加反應的頻道需有「使用外部表情符號」權限。", se_unavailable: "無法使用",
|
|
321
321
|
se_hint: "留空即使用預設值。預覽由 AgEnD 依 bot 實際 react 的方式解析。",
|
package/dist/ui/view.html
CHANGED
|
@@ -18,6 +18,20 @@
|
|
|
18
18
|
#sidebar { width: 240px; flex: 0 0 240px; background: var(--panel); border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; }
|
|
19
19
|
/* The list scrolls; the filter stays pinned to the bottom of the sidebar. */
|
|
20
20
|
#list { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
|
|
21
|
+
/* The UA's default scrollbar is a light grey bar with arrows on this dark panel.
|
|
22
|
+
Tinted from the sidebar's own --dim; scoped to #list so the terminal's own
|
|
23
|
+
scrollbar (#term) is left alone. WebKit/Blink get the pseudo-elements (thin,
|
|
24
|
+
rounded, no arrows, a hover state); Chromium 121+ would ignore them if
|
|
25
|
+
scrollbar-color were also set, so the standard properties are Firefox-only. */
|
|
26
|
+
#list::-webkit-scrollbar { width: 10px; }
|
|
27
|
+
#list::-webkit-scrollbar-track { background: transparent; }
|
|
28
|
+
#list::-webkit-scrollbar-button { display: none; }
|
|
29
|
+
#list::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--dim) 35%, transparent); background-clip: padding-box; border: 2px solid transparent; border-radius: 5px; }
|
|
30
|
+
#list::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--dim) 70%, transparent); background-clip: padding-box; }
|
|
31
|
+
@supports (-moz-appearance: none) {
|
|
32
|
+
#list { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--dim) 35%, transparent) transparent; }
|
|
33
|
+
#list:hover { scrollbar-color: color-mix(in srgb, var(--dim) 70%, transparent) transparent; }
|
|
34
|
+
}
|
|
21
35
|
#filterBar { flex: 0 0 auto; border-top: 1px solid var(--border); padding: 8px 10px 9px; background: var(--panel); }
|
|
22
36
|
.filter-wrap { position: relative; display: flex; align-items: center; }
|
|
23
37
|
.filter-wrap .filter-icon { position: absolute; left: 8px; width: 13px; height: 13px; color: var(--dim); pointer-events: none; }
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
6
6
|
<meta name="referrer" content="no-referrer">
|
|
7
|
+
<meta name="agend-terminal" content="__AGEND_TERMINAL_MARKER__">
|
|
7
8
|
<title>AgEnD terminal</title>
|
|
8
9
|
<link rel="stylesheet" href="assets/xterm.css">
|
|
9
10
|
<link rel="stylesheet" href="assets/terminal.css">
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { DeliveryWorkerMode } from "./types.js";
|
|
2
|
+
import type { OutboxDelivery } from "./delivery-outbox.js";
|
|
3
|
+
import type { PauseReason } from "./pause-marker.js";
|
|
4
|
+
/** Row kinds that never warrant waking a target. Empty: every current kind asks for action (§1.2). */
|
|
5
|
+
export declare const PASSIVE_KINDS: ReadonlySet<string>;
|
|
6
|
+
export declare const isWakeEligibleKind: (kind: string) => boolean;
|
|
7
|
+
export declare const WAKE_BACKOFF_BASE_MS = 1000;
|
|
8
|
+
export declare const WAKE_BACKOFF_MAX_MS = 60000;
|
|
9
|
+
/** Consecutive wake failures before both topics are told, once per failure episode. */
|
|
10
|
+
export declare const WAKE_FAILURE_NOTICE_AFTER = 3;
|
|
11
|
+
/** Pre-claim lease length (mirrors instance-lifecycle PRECLAIM_LEASE_MS). */
|
|
12
|
+
export declare const PRECLAIM_WINDOW_MS = 120000;
|
|
13
|
+
export declare const PARK_BASE_MS = 60000;
|
|
14
|
+
export declare const PARK_MAX_MS: number;
|
|
15
|
+
/** Queued work on an awake target that has not been claimed for this long is reported once (§1.4). */
|
|
16
|
+
export declare const CLAIM_BLOCK_NOTICE_MS: number;
|
|
17
|
+
/** How far `warm_cap` may be exceeded for leased work (§1.6). */
|
|
18
|
+
export declare const DEFAULT_WARM_OVERFLOW = 2;
|
|
19
|
+
export declare const WATCHDOG_INTERVAL_MS = 30000;
|
|
20
|
+
export interface WakeCoordinatorDeps {
|
|
21
|
+
mode(target: string): DeliveryWorkerMode;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the outbox can be read now. False once its database is closed
|
|
24
|
+
* (fleet shutdown, a test tearing down): the coordinator then does nothing,
|
|
25
|
+
* and stops itself, instead of querying a closed connection.
|
|
26
|
+
*/
|
|
27
|
+
available(): boolean;
|
|
28
|
+
/** Rows still to deliver: queued, retry_wait, delivering, submission_started (created_seq order). */
|
|
29
|
+
listPending(): OutboxDelivery[];
|
|
30
|
+
isPaused(target: string): boolean;
|
|
31
|
+
pauseReason(target: string): PauseReason | null;
|
|
32
|
+
isRestarting(target: string): boolean;
|
|
33
|
+
/** The single-flight lifecycle wake, marked as the coordinator's own. */
|
|
34
|
+
wake(target: string): Promise<void>;
|
|
35
|
+
/** Instances counted against warm_cap right now (running, not paused, not general). */
|
|
36
|
+
residentNames(): string[];
|
|
37
|
+
/** warm_cap; 0 or less means unlimited. */
|
|
38
|
+
warmCap(): number;
|
|
39
|
+
warmOverflow(): number;
|
|
40
|
+
/** When the target was last woken or started for work (the pre-claim clock). */
|
|
41
|
+
wokeAt(target: string): number | undefined;
|
|
42
|
+
/** Why an awake target is not accepting input (dialog, auth hold…), or null. */
|
|
43
|
+
notAcceptingReason(target: string): string | null;
|
|
44
|
+
notifyTarget(target: string, text: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Run the outbox pump. A wake changes no outbox row, so nothing else would
|
|
47
|
+
* tell the pump that the target it skipped while paused can be claimed now.
|
|
48
|
+
*/
|
|
49
|
+
kickPump(): void;
|
|
50
|
+
notifySender(source: string, text: string): void;
|
|
51
|
+
now(): number;
|
|
52
|
+
logger: {
|
|
53
|
+
info(obj: object, msg: string): void;
|
|
54
|
+
warn(obj: object, msg: string): void;
|
|
55
|
+
debug?(obj: object, msg: string): void;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export declare class WakeCoordinator {
|
|
59
|
+
private readonly deps;
|
|
60
|
+
private readonly states;
|
|
61
|
+
/** Targets whose wake is in flight (a reservation each, counted against the hard cap). */
|
|
62
|
+
private readonly reserved;
|
|
63
|
+
private scanTimer;
|
|
64
|
+
private watchdog;
|
|
65
|
+
private stopped;
|
|
66
|
+
constructor(deps: WakeCoordinatorDeps);
|
|
67
|
+
start(): void;
|
|
68
|
+
stop(): void;
|
|
69
|
+
/** Schedule a scan soon (coalesced). Safe to call from any event. */
|
|
70
|
+
kick(delayMs?: number): void;
|
|
71
|
+
private state;
|
|
72
|
+
private active;
|
|
73
|
+
/**
|
|
74
|
+
* The pump must not claim this target (§3.1, §1.4): it is paused, being
|
|
75
|
+
* woken, or awake but not accepting input by the daemon's own account
|
|
76
|
+
* (a dialog, a login failure, stuck). Called from the pump's claim
|
|
77
|
+
* callback, in the same synchronous step that reads the daemon's bootId, so
|
|
78
|
+
* the verdict and the claim are about the same daemon generation. A busy
|
|
79
|
+
* (working) target is accepting: the manager's idle gate still waits it out.
|
|
80
|
+
*/
|
|
81
|
+
blocksClaim(target: string): boolean;
|
|
82
|
+
isWaking(target: string): boolean;
|
|
83
|
+
/** The last wake error, while the target is failing to wake (for the expiry reason). */
|
|
84
|
+
wakeFailure(target: string): string | null;
|
|
85
|
+
isParked(target: string): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* A wake that did not come from here (an operator's /wake or wake_instance,
|
|
88
|
+
* a user's channel message) *succeeded*. Park and backoff block only
|
|
89
|
+
* automatic wakes, so such a wake always gets its one attempt (§1.6); only
|
|
90
|
+
* its success lifts them. A failed attempt, or a refusal for capacity,
|
|
91
|
+
* leaves the park and backoff exactly as they were. If the hold persists
|
|
92
|
+
* after a successful wake, the park comes back on its next window with the
|
|
93
|
+
* level kept (it is reset only by a delivery).
|
|
94
|
+
*/
|
|
95
|
+
noteExternalWake(target: string): void;
|
|
96
|
+
/** A row for `target` was delivered: the hold is over, and so are the backoffs. */
|
|
97
|
+
noteDelivered(target: string): void;
|
|
98
|
+
/** Free warm slots under the hard cap, counting every target exactly once. */
|
|
99
|
+
private freeSlots;
|
|
100
|
+
/** Synchronously take a slot for `target` (before any await). */
|
|
101
|
+
tryReserve(target: string): symbol | null;
|
|
102
|
+
/** Return exactly the slot `token` holds (idempotent). */
|
|
103
|
+
release(target: string, token: symbol): void;
|
|
104
|
+
get reservedCount(): number;
|
|
105
|
+
/**
|
|
106
|
+
* One pass over the pending queue: wake what needs waking, park what will
|
|
107
|
+
* not take work. Runs from timers, so it must never throw: an exception
|
|
108
|
+
* there is uncaught and takes the whole fleet process down (e.g. a scan
|
|
109
|
+
* landing after the outbox's database was closed). The next kick or the
|
|
110
|
+
* watchdog retries.
|
|
111
|
+
*/
|
|
112
|
+
scan(): void;
|
|
113
|
+
private scanOnce;
|
|
114
|
+
/**
|
|
115
|
+
* An awake target with queued work: past its pre-claim window without the
|
|
116
|
+
* work moving, it is parked (no automatic re-wake until the hold clears or
|
|
117
|
+
* the park expires), and a long pre-claim block is reported once.
|
|
118
|
+
*/
|
|
119
|
+
private checkAwakeTarget;
|
|
120
|
+
/**
|
|
121
|
+
* Whether a wake completion must do nothing but return its slot: the
|
|
122
|
+
* coordinator was stopped, or the outbox went away while the wake was in
|
|
123
|
+
* flight (the coordinator stops itself then). Checked before any side
|
|
124
|
+
* effect, so a late completion can never kick a pump at a closed database.
|
|
125
|
+
*/
|
|
126
|
+
private fencedCompletion;
|
|
127
|
+
private startWake;
|
|
128
|
+
}
|