@songsid/agend 2.1.4-beta.31 → 2.1.4-beta.32
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/backend/kiro.d.ts +1 -0
- package/dist/backend/kiro.js +7 -0
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +8 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +2 -0
- package/dist/channel/adapters/discord.js +6 -0
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +6 -0
- package/dist/channel/adapters/telegram.js +10 -0
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/types.d.ts +2 -0
- package/dist/daemon.d.ts +7 -0
- package/dist/daemon.js +76 -8
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.js +19 -4
- package/dist/fleet-manager.js.map +1 -1
- package/dist/locale.js +2 -0
- package/dist/locale.js.map +1 -1
- package/dist/topic-commands.js +5 -1
- package/dist/topic-commands.js.map +1 -1
- package/package.json +1 -1
package/dist/daemon.js
CHANGED
|
@@ -1037,7 +1037,7 @@ export class Daemon extends EventEmitter {
|
|
|
1037
1037
|
}
|
|
1038
1038
|
else if (msg.type === "raw_paste") {
|
|
1039
1039
|
// Paste raw text directly to CLI without [user:] wrapping.
|
|
1040
|
-
this.queueRawPaste(msg.content, this.captureDeliveryEpoch(msg.delivery_epoch));
|
|
1040
|
+
this.queueRawPaste(msg.content, this.captureDeliveryEpoch(msg.delivery_epoch), msg.confirm_clear === true);
|
|
1041
1041
|
}
|
|
1042
1042
|
else if (msg.type === "config_update") {
|
|
1043
1043
|
this.applyConfigUpdate(msg.config);
|
|
@@ -1961,7 +1961,7 @@ export class Daemon extends EventEmitter {
|
|
|
1961
1961
|
isDeliveryEpochCurrent(epoch) {
|
|
1962
1962
|
return epoch === this.deliveryEpoch;
|
|
1963
1963
|
}
|
|
1964
|
-
queueRawPaste(rawText, deliveryEpoch = this.deliveryEpoch) {
|
|
1964
|
+
queueRawPaste(rawText, deliveryEpoch = this.deliveryEpoch, confirmClear = false) {
|
|
1965
1965
|
if (!this.tmux || !this.isDeliveryEpochCurrent(deliveryEpoch))
|
|
1966
1966
|
return;
|
|
1967
1967
|
this.pasteLock = this.pasteLock.then(async () => {
|
|
@@ -1973,11 +1973,62 @@ export class Daemon extends EventEmitter {
|
|
|
1973
1973
|
if (!this.isDeliveryEpochCurrent(deliveryEpoch))
|
|
1974
1974
|
return;
|
|
1975
1975
|
await this.deliverMessage(rawText, undefined, { deliveryEpoch });
|
|
1976
|
+
if (confirmClear)
|
|
1977
|
+
await this.confirmBackendClearDialog();
|
|
1976
1978
|
this.logger.debug({ text: rawText.slice(0, 100) }, "Raw paste delivered");
|
|
1977
1979
|
}).catch(err => {
|
|
1978
1980
|
this.logger.warn({ err: err.message }, "raw_paste delivery error");
|
|
1979
1981
|
});
|
|
1980
1982
|
}
|
|
1983
|
+
/**
|
|
1984
|
+
* Confirm a backend's terminal-level /clear prompt after the channel-level
|
|
1985
|
+
* admin confirmation has already succeeded. Poll instead of pasting `/clear\ny`
|
|
1986
|
+
* as one buffer: Kiro versions that clear immediately interpret that queued
|
|
1987
|
+
* `y` as a brand-new user message.
|
|
1988
|
+
*/
|
|
1989
|
+
async confirmBackendClearDialog() {
|
|
1990
|
+
const dialog = this.backend?.getClearConfirmationDialog?.();
|
|
1991
|
+
if (!dialog || !this.tmux)
|
|
1992
|
+
return;
|
|
1993
|
+
const matches = (pane) => {
|
|
1994
|
+
dialog.pattern.lastIndex = 0;
|
|
1995
|
+
return dialog.pattern.test(pane);
|
|
1996
|
+
};
|
|
1997
|
+
const deadline = Date.now() + 3_000;
|
|
1998
|
+
while (Date.now() <= deadline) {
|
|
1999
|
+
const pane = await this.tmux.capturePane().catch(() => "");
|
|
2000
|
+
if (matches(pane)) {
|
|
2001
|
+
const sent = await this.paneWriteLock.run(async () => {
|
|
2002
|
+
// Re-check under the write lock so a prompt that disappeared between
|
|
2003
|
+
// capture and lock acquisition never receives a stray literal `y`.
|
|
2004
|
+
const currentPane = await this.tmux.capturePane().catch(() => "");
|
|
2005
|
+
if (!matches(currentPane))
|
|
2006
|
+
return false;
|
|
2007
|
+
const specialKeys = new Set(["Up", "Down", "Enter", "Escape", "Right", "Left"]);
|
|
2008
|
+
for (const key of dialog.keys) {
|
|
2009
|
+
const ok = specialKeys.has(key)
|
|
2010
|
+
? await this.tmux.sendSpecialKey(key)
|
|
2011
|
+
: await this.tmux.sendKeys(key);
|
|
2012
|
+
if (!ok)
|
|
2013
|
+
return false;
|
|
2014
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
2015
|
+
}
|
|
2016
|
+
return true;
|
|
2017
|
+
});
|
|
2018
|
+
if (sent) {
|
|
2019
|
+
this.logger.info({ dialog: dialog.description }, "Auto-confirmed backend clear dialog");
|
|
2020
|
+
}
|
|
2021
|
+
else {
|
|
2022
|
+
this.logger.warn({ dialog: dialog.description }, "Backend clear dialog disappeared or confirmation keys failed");
|
|
2023
|
+
}
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
2027
|
+
}
|
|
2028
|
+
// Recent Kiro releases may clear immediately without a second prompt. That
|
|
2029
|
+
// is a successful no-op here, not an error.
|
|
2030
|
+
this.logger.debug({ dialog: dialog.description }, "Backend clear dialog did not appear");
|
|
2031
|
+
}
|
|
1981
2032
|
/** Send the backend-specific graceful quit command/key sequence. */
|
|
1982
2033
|
async sendQuitSequence() {
|
|
1983
2034
|
if (!this.tmux || !this.backend)
|
|
@@ -1985,18 +2036,20 @@ export class Daemon extends EventEmitter {
|
|
|
1985
2036
|
const quitCmd = this.backend.getQuitCommand();
|
|
1986
2037
|
const quitKey = this.backend.getQuitKey?.();
|
|
1987
2038
|
if (quitCmd) {
|
|
1988
|
-
await this.tmux.sendKeys(quitCmd)
|
|
2039
|
+
if (!await this.tmux.sendKeys(quitCmd))
|
|
2040
|
+
return false;
|
|
1989
2041
|
// Delay before Enter to prevent tmux server races when instances stop in
|
|
1990
2042
|
// parallel (same pattern as pasteText).
|
|
1991
2043
|
await new Promise(r => setTimeout(r, 150));
|
|
1992
|
-
|
|
1993
|
-
return true;
|
|
2044
|
+
return this.tmux.sendSpecialKey("Enter");
|
|
1994
2045
|
}
|
|
1995
2046
|
if (!quitKey)
|
|
1996
2047
|
return false;
|
|
1997
2048
|
const presses = Math.max(1, Math.floor(this.backend.getQuitKeyPresses?.() ?? 1));
|
|
1998
2049
|
for (let i = 0; i < presses; i++) {
|
|
1999
|
-
await this.tmux.sendSpecialKey(quitKey);
|
|
2050
|
+
const sent = await this.tmux.sendSpecialKey(quitKey);
|
|
2051
|
+
if (!sent)
|
|
2052
|
+
return false;
|
|
2000
2053
|
if (i + 1 < presses)
|
|
2001
2054
|
await new Promise(r => setTimeout(r, 250));
|
|
2002
2055
|
}
|
|
@@ -2029,8 +2082,23 @@ export class Daemon extends EventEmitter {
|
|
|
2029
2082
|
}
|
|
2030
2083
|
}
|
|
2031
2084
|
}
|
|
2032
|
-
if (!killed)
|
|
2033
|
-
this.logger.warn("CLI did not exit gracefully within 3s
|
|
2085
|
+
if (!killed) {
|
|
2086
|
+
this.logger.warn({ quitSent }, "CLI did not exit gracefully within 3s — falling back to SIGTERM");
|
|
2087
|
+
await this.killProcessTree("SIGTERM");
|
|
2088
|
+
for (let i = 0; i < 5; i++) {
|
|
2089
|
+
await new Promise(r => setTimeout(r, 200));
|
|
2090
|
+
const status = await this.tmux.getPaneStatus();
|
|
2091
|
+
if (!status || !status.alive) {
|
|
2092
|
+
killed = true;
|
|
2093
|
+
break;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
if (!killed) {
|
|
2098
|
+
this.logger.warn("CLI process tree survived SIGTERM — falling back to SIGKILL");
|
|
2099
|
+
await this.killProcessTree("SIGKILL");
|
|
2100
|
+
await new Promise(r => setTimeout(r, 200));
|
|
2101
|
+
}
|
|
2034
2102
|
// Always kill window — remain-on-exit keeps dead panes around after CLI exits
|
|
2035
2103
|
const stoppedWindowId = this.tmux.getWindowId();
|
|
2036
2104
|
await this.tmux.killWindow();
|