@songsid/agend 2.1.8-beta.1 → 2.1.8-beta.11
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/agent-cli.js +14 -0
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +4 -1
- package/dist/agent-endpoint.js +10 -1
- package/dist/agent-endpoint.js.map +1 -1
- 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/cli-env-probe-worker.d.ts +1 -0
- package/dist/backend/cli-env-probe-worker.js +25 -0
- package/dist/backend/cli-env-probe-worker.js.map +1 -0
- package/dist/backend/codex-session-lookup.d.ts +16 -0
- package/dist/backend/codex-session-lookup.js +76 -2
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.d.ts +3 -4
- package/dist/backend/codex.js +44 -6
- 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/muse.d.ts +6 -0
- package/dist/backend/muse.js +37 -3
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +13 -2
- package/dist/backend/types.js +14 -3
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +16 -4
- package/dist/channel/adapters/discord.js +20 -5
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-tools.js +6 -0
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/cli.js +138 -48
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +11 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -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 +130 -6
- package/dist/daemon.js +486 -69
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +9 -1
- package/dist/delivery-outbox.js +25 -4
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-context.d.ts +5 -0
- package/dist/fleet-context.js.map +1 -1
- package/dist/fleet-manager.d.ts +165 -18
- package/dist/fleet-manager.js +821 -121
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +160 -0
- package/dist/forged-envelope-scan.js +312 -0
- package/dist/forged-envelope-scan.js.map +1 -0
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +55 -0
- package/dist/instance-lifecycle.d.ts +81 -6
- package/dist/instance-lifecycle.js +201 -17
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +34 -4
- package/dist/locale.js.map +1 -1
- package/dist/login-controller.js +11 -4
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.d.ts +18 -1
- package/dist/login-flows.js +9 -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 +3 -3
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +23 -4
- package/dist/outbound-schemas.js +12 -0
- 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/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 +8 -8
- package/dist/settings-api.js +12 -5
- package/dist/settings-api.js.map +1 -1
- package/dist/status-emojis.d.ts +28 -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 +15 -4
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +9 -0
- package/dist/topic-commands.js +64 -21
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-monitor.js +3 -0
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +63 -0
- package/dist/transcript-sources.js +171 -27
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +26 -1
- package/dist/types.js +9 -1
- package/dist/types.js.map +1 -1
- package/dist/ui/settings.html +25 -13
- package/dist/wake-coordinator.d.ts +143 -0
- package/dist/wake-coordinator.js +321 -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-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
package/dist/cli.js
CHANGED
|
@@ -550,6 +550,92 @@ delivery
|
|
|
550
550
|
process.exitCode = 1;
|
|
551
551
|
}
|
|
552
552
|
});
|
|
553
|
+
delivery
|
|
554
|
+
.command("scan-forged-envelopes")
|
|
555
|
+
.description("Detect fabricated peer envelopes in a kiro receiver's own transcript (#995)")
|
|
556
|
+
.option("--instance <name>", "Scan one instance")
|
|
557
|
+
.option("--all", "Scan every kiro-cli instance in fleet.yaml")
|
|
558
|
+
.option("--json", "Machine-readable output")
|
|
559
|
+
.option("--kiro-db <path>", "Override the kiro conversation store path (testing)")
|
|
560
|
+
.option("--outbox-db <path>", "Override the delivery-outbox path (testing)")
|
|
561
|
+
.action(async (opts) => {
|
|
562
|
+
const { executeForgedEnvelopeScan, resolveScanTarget, loadReportedEnvelopeIds, recordReportedEnvelopeIds } = await import("./forged-envelope-scan.js");
|
|
563
|
+
if (!opts.instance && !opts.all) {
|
|
564
|
+
console.error("Specify --instance <name> or --all.");
|
|
565
|
+
process.exitCode = 1;
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
let rawConfig;
|
|
569
|
+
try {
|
|
570
|
+
const loaded = loadRawFleetConfig(FLEET_CONFIG_PATH);
|
|
571
|
+
rawConfig = {
|
|
572
|
+
...(loaded.defaults ? { defaults: loaded.defaults } : {}),
|
|
573
|
+
...(loaded.instances ? { instances: loaded.instances } : {}),
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
catch (err) {
|
|
577
|
+
console.error(`Could not read fleet config: ${err.message}`);
|
|
578
|
+
process.exitCode = 1;
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
const instances = rawConfig.instances ?? {};
|
|
582
|
+
const defaults = (rawConfig.defaults ?? {});
|
|
583
|
+
const knownInstances = new Set(Object.keys(instances));
|
|
584
|
+
const names = opts.all ? [...knownInstances] : [opts.instance];
|
|
585
|
+
if (names.length === 0 || (names.length === 1 && !knownInstances.has(names[0]))) {
|
|
586
|
+
console.error(`Unknown instance: ${names[0] ?? "(fleet has no instances)"}`);
|
|
587
|
+
process.exitCode = 1;
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
// Effective config exactly like the daemon's: fleet defaults deep-merged
|
|
591
|
+
// under instance overrides — a credential profile inherited from defaults
|
|
592
|
+
// must resolve to the profile store (#1007 round-3).
|
|
593
|
+
const targets = names.map(name => resolveScanTarget(name, instances[name], defaults));
|
|
594
|
+
const reported = loadReportedEnvelopeIds(DATA_DIR);
|
|
595
|
+
const result = executeForgedEnvelopeScan({
|
|
596
|
+
targets,
|
|
597
|
+
knownInstances,
|
|
598
|
+
outboxDbPath: opts.outboxDb ?? join(DATA_DIR, "delivery-outbox.db"),
|
|
599
|
+
dataDir: DATA_DIR,
|
|
600
|
+
...(opts.kiroDb ? { kiroDbOverride: opts.kiroDb } : {}),
|
|
601
|
+
alreadyReportedIds: reported,
|
|
602
|
+
});
|
|
603
|
+
for (const row of result.rows) {
|
|
604
|
+
for (const f of row.findings)
|
|
605
|
+
reported.add(f.message_id);
|
|
606
|
+
}
|
|
607
|
+
recordReportedEnvelopeIds(DATA_DIR, reported);
|
|
608
|
+
if (opts.json) {
|
|
609
|
+
console.log(JSON.stringify({ scans: result.rows, new_findings: result.newFindings }, null, 2));
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
for (const row of result.rows) {
|
|
613
|
+
if (row.status === "unsupported-backend" || row.status === "error" || row.status === "unreadable-store") {
|
|
614
|
+
console.log(`- ${row.instance}: ${row.status} (${row.reason ?? row.note})`);
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
console.log(`- ${row.instance}: ${row.status} (checked ${row.checked}, delivered ${row.delivered}, unverifiable ${row.unverifiable})`);
|
|
618
|
+
for (const f of row.findings) {
|
|
619
|
+
console.log(` FORGED [from:${f.from}] (message_id: ${f.message_id})`);
|
|
620
|
+
console.log(` excerpt: ${f.excerpt}`);
|
|
621
|
+
console.log(` inject via send_to_instance: ${f.suggested_injection}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
// Operator notification: visible here; wire to a schedule for routine runs.
|
|
626
|
+
if (result.newFindings > 0) {
|
|
627
|
+
console.error(`FORGED ENVELOPES: ${result.newFindings} new finding(s) — notify the operator and inject the warning(s) above.`);
|
|
628
|
+
}
|
|
629
|
+
else if (result.exitCode === 3) {
|
|
630
|
+
console.error(`UNREADABLE TRANSCRIPT: ${result.unreadable} instance(s) could not be scanned — not clean.`);
|
|
631
|
+
}
|
|
632
|
+
else if (result.exitCode === 4) {
|
|
633
|
+
// Fail-closed: no-conversation / partially-unverified / missing
|
|
634
|
+
// working_directory are "could not verify", never clean.
|
|
635
|
+
console.error(`INCOMPLETE SCAN: ${result.incomplete} instance(s) could not be fully verified — not clean.`);
|
|
636
|
+
}
|
|
637
|
+
process.exitCode = result.exitCode;
|
|
638
|
+
});
|
|
553
639
|
fleet
|
|
554
640
|
.command("activity")
|
|
555
641
|
.description("Show fleet activity log — who talked to whom, tool calls, task updates")
|
|
@@ -1604,7 +1690,7 @@ program
|
|
|
1604
1690
|
// service's own HOME, which may differ from what this command resolves (sudo,
|
|
1605
1691
|
// AGEND_HOME) — an absent pid file does NOT mean it's stopped. Ask the service
|
|
1606
1692
|
// manager first. This is the canonical restart the `update` flow spawns.
|
|
1607
|
-
const { detectPlatform, getServicePath, getSystemServicePath, getSystemdServiceState, restartSystemdService, } = await import("./service-installer.js");
|
|
1693
|
+
const { detectPlatform, getServicePath, getSystemServicePath, getSystemdServiceState, restartSystemdService, ensureSystemdKillModeMixed, } = await import("./service-installer.js");
|
|
1608
1694
|
const { spawn, spawnSync } = await import("node:child_process");
|
|
1609
1695
|
const plat = detectPlatform();
|
|
1610
1696
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
@@ -1643,7 +1729,52 @@ program
|
|
|
1643
1729
|
process.exitCode = 1;
|
|
1644
1730
|
return;
|
|
1645
1731
|
}
|
|
1646
|
-
|
|
1732
|
+
// #908: before this restart's stop, so it already lets the fleet quit
|
|
1733
|
+
// each CLI itself instead of systemd SIGTERMing them all at once. A
|
|
1734
|
+
// restart that would still run on control-group (the line could not be
|
|
1735
|
+
// read, written or loaded) is refused: it is exactly the restart that
|
|
1736
|
+
// aborts kiro-cli into a core dump.
|
|
1737
|
+
const unitPath = systemdTarget.user ? getServicePath() : getSystemServicePath();
|
|
1738
|
+
const reloadCmd = systemdTarget.user ? "systemctl --user daemon-reload" : "systemctl daemon-reload";
|
|
1739
|
+
let outcome = "present";
|
|
1740
|
+
if (unitPath) {
|
|
1741
|
+
try {
|
|
1742
|
+
outcome = ensureSystemdKillModeMixed(unitPath);
|
|
1743
|
+
}
|
|
1744
|
+
catch {
|
|
1745
|
+
outcome = "unwritable";
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
if (outcome === "unreadable" || outcome === "unwritable") {
|
|
1749
|
+
console.error(` ✗ Could not ${outcome === "unreadable" ? "read" : "update"} ${unitPath}, so this restart would still let systemd SIGTERM every CLI at once (kiro-cli core dumps, #908).`);
|
|
1750
|
+
console.error(` Not restarting. Add KillMode=mixed under [Service] in ${unitPath}, run \`${reloadCmd}\`, then \`agend restart\`.`);
|
|
1751
|
+
process.exitCode = 1;
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
if (outcome === "custom")
|
|
1755
|
+
console.log(` ⚠ ${unitPath} sets its own KillMode; left as is. KillMode=mixed avoids kiro-cli core dumps on restart (#908).`);
|
|
1756
|
+
const reloaded = run(reloadCmd);
|
|
1757
|
+
if (outcome !== "custom") {
|
|
1758
|
+
// Gate on what systemd has LOADED, not on what this run wrote: `agend
|
|
1759
|
+
// update` runs the new binary's `install --no-activate` first, which
|
|
1760
|
+
// already puts KillMode=mixed in the file, so a failed reload here
|
|
1761
|
+
// would otherwise go unnoticed and stop the fleet with control-group.
|
|
1762
|
+
const showCmd = `systemctl${systemdTarget.user ? " --user" : ""} show -p KillMode --value ${systemdTarget.unit}`;
|
|
1763
|
+
let loaded = "";
|
|
1764
|
+
try {
|
|
1765
|
+
loaded = execSync(showCmd, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 5000 }).trim();
|
|
1766
|
+
}
|
|
1767
|
+
catch { /* unknown → refused below */ }
|
|
1768
|
+
if (loaded !== "mixed") {
|
|
1769
|
+
console.error(` ✗ systemd has ${loaded ? `KillMode=${loaded}` : "an unknown KillMode"} loaded for ${systemdTarget.unit}${reloaded ? "" : ` (\`${reloadCmd}\` failed)`}, so it would still SIGTERM every CLI at once (kiro-cli core dumps, #908).`);
|
|
1770
|
+
console.error(` Not restarting. Make sure ${unitPath ?? "the unit"} has KillMode=mixed under [Service], run \`${reloadCmd}\`, then \`agend restart\`.`);
|
|
1771
|
+
process.exitCode = 1;
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
if (outcome === "added") {
|
|
1776
|
+
console.log(` ✓ ${unitPath}: added KillMode=mixed (the fleet stops its CLIs; systemd no longer signals them all at once)`);
|
|
1777
|
+
}
|
|
1647
1778
|
if (systemdTarget.user) {
|
|
1648
1779
|
try {
|
|
1649
1780
|
execSync("systemctl --user reset-failed com.agend.fleet", { stdio: "pipe", timeout: 5000 });
|
|
@@ -2368,7 +2499,7 @@ async function lsAction(opts) {
|
|
|
2368
2499
|
};
|
|
2369
2500
|
// Row collection runs concurrently (see ls-rows.ts): the per-instance
|
|
2370
2501
|
// tmux captures overlap instead of stacking their 2s bounds serially.
|
|
2371
|
-
const { collectLsRows, capturePaneAsync, formatTimeSince } = await import("./ls-rows.js");
|
|
2502
|
+
const { collectLsRows, capturePaneAsync, formatTimeSince, lsStatusIcon, lsStatusLabel, displayWidth } = await import("./ls-rows.js");
|
|
2372
2503
|
const { getTmuxSocketName } = await import("./paths.js");
|
|
2373
2504
|
const socketName = getTmuxSocketName();
|
|
2374
2505
|
const rows = await collectLsRows(allNames.map(name => {
|
|
@@ -2434,51 +2565,10 @@ async function lsAction(opts) {
|
|
|
2434
2565
|
console.log(JSON.stringify(rows, null, 2));
|
|
2435
2566
|
return;
|
|
2436
2567
|
}
|
|
2437
|
-
//
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
if (s === "stopped")
|
|
2442
|
-
return "\x1b[90m○\x1b[0m";
|
|
2443
|
-
if (state === "stuck")
|
|
2444
|
-
return "\x1b[31m●\x1b[0m";
|
|
2445
|
-
if (state === "paused" || s === "paused")
|
|
2446
|
-
return "\x1b[2;33m●\x1b[0m";
|
|
2447
|
-
if (state === "working")
|
|
2448
|
-
return "\x1b[34m●\x1b[0m";
|
|
2449
|
-
if (state === "idle")
|
|
2450
|
-
return "\x1b[32m●\x1b[0m";
|
|
2451
|
-
// Fallback for when API is unreachable
|
|
2452
|
-
if (s === "running")
|
|
2453
|
-
return idle === false ? "\x1b[34m●\x1b[0m" : "\x1b[32m●\x1b[0m";
|
|
2454
|
-
return "\x1b[90m○\x1b[0m";
|
|
2455
|
-
};
|
|
2456
|
-
const statusLabel = (s, idle, state) => {
|
|
2457
|
-
if (s === "crashed")
|
|
2458
|
-
return "Crashed";
|
|
2459
|
-
if (s === "stopped")
|
|
2460
|
-
return "Stopped";
|
|
2461
|
-
if (state === "stuck")
|
|
2462
|
-
return "Stuck";
|
|
2463
|
-
if (state === "paused" || s === "paused")
|
|
2464
|
-
return "Paused";
|
|
2465
|
-
if (state === "working")
|
|
2466
|
-
return "Working";
|
|
2467
|
-
if (state === "idle")
|
|
2468
|
-
return "Idle";
|
|
2469
|
-
if (s === "running")
|
|
2470
|
-
return idle === false ? "Busy" : "Idle";
|
|
2471
|
-
return "Stopped";
|
|
2472
|
-
};
|
|
2473
|
-
/** Get display width accounting for fullwidth (CJK) characters */
|
|
2474
|
-
const displayWidth = (s) => {
|
|
2475
|
-
let w = 0;
|
|
2476
|
-
for (const ch of s) {
|
|
2477
|
-
const cp = ch.codePointAt(0);
|
|
2478
|
-
w += (cp > 0x7f && cp !== 0x200b) ? 2 : 1;
|
|
2479
|
-
}
|
|
2480
|
-
return w;
|
|
2481
|
-
};
|
|
2568
|
+
// Merged State column (#1052): one glyph per lifecycle/execution state,
|
|
2569
|
+
// shared with /status via ls-rows (○ paused, ✗ stopped).
|
|
2570
|
+
const statusIcon = lsStatusIcon;
|
|
2571
|
+
const statusLabel = lsStatusLabel;
|
|
2482
2572
|
const padDisplay = (s, width) => s + " ".repeat(Math.max(0, width - displayWidth(s)));
|
|
2483
2573
|
const displayName = (row) => row.name;
|
|
2484
2574
|
const nameW = Math.max(20, ...rows.map(r => displayWidth(displayName(r)) + 2));
|