@snowyroad/arp 0.5.0 → 0.5.2
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/cli.js +31 -14
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -336,6 +336,18 @@ var CTRL_RE = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g;
|
|
|
336
336
|
function sanitizeForTty(s) {
|
|
337
337
|
return s.replace(ANSI_RE, "").replace(CTRL_RE, "");
|
|
338
338
|
}
|
|
339
|
+
var ESC = String.fromCharCode(27);
|
|
340
|
+
function restoreTerminal() {
|
|
341
|
+
const out = process.stdout;
|
|
342
|
+
if (!out.isTTY) return;
|
|
343
|
+
out.write(
|
|
344
|
+
`${ESC}[?1l${ESC}>${ESC}[?25h${ESC}[?1049l${ESC}[?2004l${ESC}[?1000l${ESC}[?1002l${ESC}[?1003l${ESC}[?1006l`
|
|
345
|
+
);
|
|
346
|
+
try {
|
|
347
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
348
|
+
} catch {
|
|
349
|
+
}
|
|
350
|
+
}
|
|
339
351
|
function isShellSafeName(s) {
|
|
340
352
|
return /^[A-Za-z0-9_.-]+$/.test(s);
|
|
341
353
|
}
|
|
@@ -781,14 +793,14 @@ ${fence("peer roster", joinUntrusted(lines, "\n"))}`;
|
|
|
781
793
|
}
|
|
782
794
|
|
|
783
795
|
// src/channelContext.ts
|
|
784
|
-
var
|
|
796
|
+
var MAX_INJECTED_INSTRUCTIONS_CHARS = 8e3;
|
|
785
797
|
var MAX_INJECTED_SOURCE_CHARS = 8e3;
|
|
786
798
|
var MAX_INJECTED_SOURCES_TOTAL_CHARS = 24e3;
|
|
787
799
|
function buildChannelContext(input) {
|
|
788
800
|
let out = "";
|
|
789
|
-
if (!isBlankText(input.
|
|
790
|
-
const raw = rawUntrusted(input.
|
|
791
|
-
const bounded = raw.length >
|
|
801
|
+
if (!isBlankText(input.instructions)) {
|
|
802
|
+
const raw = rawUntrusted(input.instructions);
|
|
803
|
+
const bounded = raw.length > MAX_INJECTED_INSTRUCTIONS_CHARS ? untrusted(raw.slice(0, MAX_INJECTED_INSTRUCTIONS_CHARS) + "\n[...truncated]") : input.instructions;
|
|
792
804
|
out += `## Channel Instructions (standing guidance for this channel)
|
|
793
805
|
${fence("channel instructions", bounded)}
|
|
794
806
|
---
|
|
@@ -1505,21 +1517,21 @@ var RelayClient = class {
|
|
|
1505
1517
|
console.warn("[arp-bridge] flow post failed:", sanitizeForTty(String(err)));
|
|
1506
1518
|
}
|
|
1507
1519
|
}
|
|
1508
|
-
/** Channel
|
|
1509
|
-
async
|
|
1520
|
+
/** Channel instructions text (empty if none or on error — never throws). Branded (H2-4). */
|
|
1521
|
+
async fetchChannelInstructions(channelId) {
|
|
1510
1522
|
const ch = this.pathId(channelId, "channelId");
|
|
1511
1523
|
if (!ch) return untrusted("");
|
|
1512
|
-
const url = `${this.cfg.relayHttpUrl}/channels/${ch}/
|
|
1524
|
+
const url = `${this.cfg.relayHttpUrl}/channels/${ch}/instructions`;
|
|
1513
1525
|
try {
|
|
1514
1526
|
const res = await this.deps.fetchFn(url, { headers: { Authorization: `Bearer ${this.cfg.token}` } });
|
|
1515
1527
|
if (!res.ok) {
|
|
1516
|
-
console.warn("[arp-bridge]
|
|
1528
|
+
console.warn("[arp-bridge] instructions HTTP", res.status);
|
|
1517
1529
|
return untrusted("");
|
|
1518
1530
|
}
|
|
1519
1531
|
const data = await res.json();
|
|
1520
1532
|
return untrusted(typeof data?.content === "string" ? data.content : "");
|
|
1521
1533
|
} catch (err) {
|
|
1522
|
-
console.warn("[arp-bridge]
|
|
1534
|
+
console.warn("[arp-bridge] instructions fetch failed:", sanitizeForTty(String(err)));
|
|
1523
1535
|
return untrusted("");
|
|
1524
1536
|
}
|
|
1525
1537
|
}
|
|
@@ -1604,18 +1616,18 @@ var RelayClient = class {
|
|
|
1604
1616
|
return null;
|
|
1605
1617
|
}
|
|
1606
1618
|
}
|
|
1607
|
-
/** Assemble the situational channel-context block (
|
|
1619
|
+
/** Assemble the situational channel-context block (instructions + sources + topics) for a
|
|
1608
1620
|
* passive message. Parallel fetch with per-source graceful degradation (each fetcher
|
|
1609
1621
|
* swallows its own errors). Returns "" when there is nothing to inject.
|
|
1610
1622
|
* The fetchers return raw structured data; untrusted-data fencing happens ONCE, in
|
|
1611
1623
|
* buildChannelContext (the single-layer rule, see untrusted.ts). Do not fence here. */
|
|
1612
1624
|
async fetchChannelContext(channelId) {
|
|
1613
|
-
const [
|
|
1614
|
-
this.
|
|
1625
|
+
const [instructions, topics, pins] = await Promise.all([
|
|
1626
|
+
this.fetchChannelInstructions(channelId),
|
|
1615
1627
|
this.fetchChannelTopics(channelId),
|
|
1616
1628
|
this.fetchSourcesContext(channelId)
|
|
1617
1629
|
]);
|
|
1618
|
-
return buildChannelContext({
|
|
1630
|
+
return buildChannelContext({ instructions, topics, pins });
|
|
1619
1631
|
}
|
|
1620
1632
|
/** Fetch a flow's transcript (used to backfill a minimal turn_notification). [] on error. */
|
|
1621
1633
|
async fetchFlowMessages(channelId, flowId) {
|
|
@@ -2838,7 +2850,10 @@ function withTimeout(p, ms) {
|
|
|
2838
2850
|
// src/shutdown.ts
|
|
2839
2851
|
var SHUTDOWN_TIMEOUT_MS = 8e3;
|
|
2840
2852
|
async function drainAndExit(sessions, exitCode, relay, brokers) {
|
|
2841
|
-
const force = setTimeout(() =>
|
|
2853
|
+
const force = setTimeout(() => {
|
|
2854
|
+
restoreTerminal();
|
|
2855
|
+
process.exit(exitCode);
|
|
2856
|
+
}, SHUTDOWN_TIMEOUT_MS);
|
|
2842
2857
|
force.unref?.();
|
|
2843
2858
|
try {
|
|
2844
2859
|
relay?.stop();
|
|
@@ -2857,9 +2872,11 @@ async function drainAndExit(sessions, exitCode, relay, brokers) {
|
|
|
2857
2872
|
}
|
|
2858
2873
|
}
|
|
2859
2874
|
clearTimeout(force);
|
|
2875
|
+
restoreTerminal();
|
|
2860
2876
|
process.exit(exitCode);
|
|
2861
2877
|
}
|
|
2862
2878
|
function installGracefulShutdown(bridge) {
|
|
2879
|
+
process.on("exit", () => restoreTerminal());
|
|
2863
2880
|
let shuttingDown = false;
|
|
2864
2881
|
const shutdown = async (sig) => {
|
|
2865
2882
|
if (shuttingDown) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snowyroad/arp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Connect your own coding agent (Claude Code, Codex, Gemini, Grok) to an Agent Relay Protocol channel and collaborate with other agents and humans.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "SnowyRoad",
|