style: apply formatter to runtime files
This commit is contained in:
@@ -300,7 +300,10 @@ function prepareGroupEnvironment(
|
|||||||
: '';
|
: '';
|
||||||
// Remove existing nanoclaw/memento MCP sections if present (to refresh env vars)
|
// Remove existing nanoclaw/memento MCP sections if present (to refresh env vars)
|
||||||
toml = toml.replace(/\n?\[mcp_servers\.nanoclaw\][\s\S]*?(?=\n\[|$)/, '');
|
toml = toml.replace(/\n?\[mcp_servers\.nanoclaw\][\s\S]*?(?=\n\[|$)/, '');
|
||||||
toml = toml.replace(/\n?\[mcp_servers\.memento-mcp\][\s\S]*?(?=\n\[|$)/, '');
|
toml = toml.replace(
|
||||||
|
/\n?\[mcp_servers\.memento-mcp\][\s\S]*?(?=\n\[|$)/,
|
||||||
|
'',
|
||||||
|
);
|
||||||
const mcpSection = `
|
const mcpSection = `
|
||||||
[mcp_servers.nanoclaw]
|
[mcp_servers.nanoclaw]
|
||||||
command = "node"
|
command = "node"
|
||||||
|
|||||||
15
src/db.ts
15
src/db.ts
@@ -379,7 +379,10 @@ export function storeMessage(msg: NewMessage): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeMessageRow(
|
function normalizeMessageRow(
|
||||||
row: NewMessage & { is_from_me?: boolean | number; is_bot_message?: boolean | number },
|
row: NewMessage & {
|
||||||
|
is_from_me?: boolean | number;
|
||||||
|
is_bot_message?: boolean | number;
|
||||||
|
},
|
||||||
): NewMessage {
|
): NewMessage {
|
||||||
return {
|
return {
|
||||||
...row,
|
...row,
|
||||||
@@ -415,7 +418,10 @@ export function getNewMessages(
|
|||||||
const rows = db
|
const rows = db
|
||||||
.prepare(sql)
|
.prepare(sql)
|
||||||
.all(lastTimestamp, ...jids, `${botPrefix}:%`, limit) as Array<
|
.all(lastTimestamp, ...jids, `${botPrefix}:%`, limit) as Array<
|
||||||
NewMessage & { is_from_me?: boolean | number; is_bot_message?: boolean | number }
|
NewMessage & {
|
||||||
|
is_from_me?: boolean | number;
|
||||||
|
is_bot_message?: boolean | number;
|
||||||
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
let newTimestamp = lastTimestamp;
|
let newTimestamp = lastTimestamp;
|
||||||
@@ -449,7 +455,10 @@ export function getMessagesSince(
|
|||||||
const rows = db
|
const rows = db
|
||||||
.prepare(sql)
|
.prepare(sql)
|
||||||
.all(chatJid, sinceTimestamp, `${botPrefix}:%`, limit) as Array<
|
.all(chatJid, sinceTimestamp, `${botPrefix}:%`, limit) as Array<
|
||||||
NewMessage & { is_from_me?: boolean | number; is_bot_message?: boolean | number }
|
NewMessage & {
|
||||||
|
is_from_me?: boolean | number;
|
||||||
|
is_bot_message?: boolean | number;
|
||||||
|
}
|
||||||
>;
|
>;
|
||||||
return rows.map(normalizeMessageRow);
|
return rows.map(normalizeMessageRow);
|
||||||
}
|
}
|
||||||
|
|||||||
68
src/index.ts
68
src/index.ts
@@ -112,7 +112,10 @@ function loadState(): void {
|
|||||||
// claude-code and codex rows for the same Discord JID.
|
// claude-code and codex rows for the same Discord JID.
|
||||||
registeredGroups = getAllRegisteredGroups(SERVICE_AGENT_TYPE);
|
registeredGroups = getAllRegisteredGroups(SERVICE_AGENT_TYPE);
|
||||||
logger.info(
|
logger.info(
|
||||||
{ groupCount: Object.keys(registeredGroups).length, agentType: SERVICE_AGENT_TYPE },
|
{
|
||||||
|
groupCount: Object.keys(registeredGroups).length,
|
||||||
|
agentType: SERVICE_AGENT_TYPE,
|
||||||
|
},
|
||||||
'State loaded',
|
'State loaded',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -198,7 +201,11 @@ async function processGroupMessages(chatJid: string): Promise<boolean> {
|
|||||||
sinceTimestamp,
|
sinceTimestamp,
|
||||||
ASSISTANT_NAME,
|
ASSISTANT_NAME,
|
||||||
);
|
);
|
||||||
const missedMessages = getProcessableMessages(chatJid, rawMissedMessages, channel);
|
const missedMessages = getProcessableMessages(
|
||||||
|
chatJid,
|
||||||
|
rawMissedMessages,
|
||||||
|
channel,
|
||||||
|
);
|
||||||
|
|
||||||
if (missedMessages.length === 0) {
|
if (missedMessages.length === 0) {
|
||||||
const lastIgnored = rawMissedMessages[rawMissedMessages.length - 1];
|
const lastIgnored = rawMissedMessages[rawMissedMessages.length - 1];
|
||||||
@@ -262,7 +269,10 @@ async function processGroupMessages(chatJid: string): Promise<boolean> {
|
|||||||
// Advance cursor so the piping path in startMessageLoop won't re-fetch
|
// Advance cursor so the piping path in startMessageLoop won't re-fetch
|
||||||
// these messages. Save the old cursor so we can roll back on error.
|
// these messages. Save the old cursor so we can roll back on error.
|
||||||
const previousCursor = lastAgentTimestamp[chatJid] || '';
|
const previousCursor = lastAgentTimestamp[chatJid] || '';
|
||||||
advanceLastAgentCursor(chatJid, missedMessages[missedMessages.length - 1].timestamp);
|
advanceLastAgentCursor(
|
||||||
|
chatJid,
|
||||||
|
missedMessages[missedMessages.length - 1].timestamp,
|
||||||
|
);
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
{ group: group.name, messageCount: missedMessages.length },
|
{ group: group.name, messageCount: missedMessages.length },
|
||||||
@@ -289,7 +299,8 @@ async function processGroupMessages(chatJid: string): Promise<boolean> {
|
|||||||
let finalOutputSentToUser = false;
|
let finalOutputSentToUser = false;
|
||||||
let progressOutputSentToUser = false;
|
let progressOutputSentToUser = false;
|
||||||
let poisonedSessionDetected = false;
|
let poisonedSessionDetected = false;
|
||||||
const isClaudeCodeAgent = (group.agentType || 'claude-code') === 'claude-code';
|
const isClaudeCodeAgent =
|
||||||
|
(group.agentType || 'claude-code') === 'claude-code';
|
||||||
|
|
||||||
const clearProgressTicker = () => {
|
const clearProgressTicker = () => {
|
||||||
if (progressTicker) {
|
if (progressTicker) {
|
||||||
@@ -620,7 +631,9 @@ async function refreshChannelMeta(): Promise<void> {
|
|||||||
if (!ch?.getChannelMeta) return;
|
if (!ch?.getChannelMeta) return;
|
||||||
|
|
||||||
// Include jids from both local registeredGroups and other service snapshots
|
// Include jids from both local registeredGroups and other service snapshots
|
||||||
const localJids = Object.keys(registeredGroups).filter((j) => j.startsWith('dc:'));
|
const localJids = Object.keys(registeredGroups).filter((j) =>
|
||||||
|
j.startsWith('dc:'),
|
||||||
|
);
|
||||||
const snapshotJids = readStatusSnapshots(STATUS_SNAPSHOT_MAX_AGE_MS)
|
const snapshotJids = readStatusSnapshots(STATUS_SNAPSHOT_MAX_AGE_MS)
|
||||||
.flatMap((s) => s.entries.map((e) => e.jid))
|
.flatMap((s) => s.entries.map((e) => e.jid))
|
||||||
.filter((j) => j.startsWith('dc:'));
|
.filter((j) => j.startsWith('dc:'));
|
||||||
@@ -729,7 +742,9 @@ function writeLocalStatusSnapshot(): void {
|
|||||||
|
|
||||||
function buildStatusContent(): string {
|
function buildStatusContent(): string {
|
||||||
const snapshots = readStatusSnapshots(STATUS_SNAPSHOT_MAX_AGE_MS);
|
const snapshots = readStatusSnapshots(STATUS_SNAPSHOT_MAX_AGE_MS);
|
||||||
const chatNameByJid = new Map(getAllChats().map((chat) => [chat.jid, chat.name]));
|
const chatNameByJid = new Map(
|
||||||
|
getAllChats().map((chat) => [chat.jid, chat.name]),
|
||||||
|
);
|
||||||
|
|
||||||
// Collect all entries keyed by jid, with agent type info
|
// Collect all entries keyed by jid, with agent type info
|
||||||
interface RoomEntry {
|
interface RoomEntry {
|
||||||
@@ -798,15 +813,17 @@ function buildStatusContent(): string {
|
|||||||
|
|
||||||
const sections: string[] = [];
|
const sections: string[] = [];
|
||||||
for (const [catName, rooms] of sortedCategories) {
|
for (const [catName, rooms] of sortedCategories) {
|
||||||
rooms.sort(
|
rooms.sort((a, b) => (a.meta?.position ?? 999) - (b.meta?.position ?? 999));
|
||||||
(a, b) => (a.meta?.position ?? 999) - (b.meta?.position ?? 999),
|
|
||||||
);
|
|
||||||
|
|
||||||
const roomLines: string[] = [];
|
const roomLines: string[] = [];
|
||||||
for (const room of rooms) {
|
for (const room of rooms) {
|
||||||
// Sort agents: claude-code first, codex second
|
// Sort agents: claude-code first, codex second
|
||||||
room.agents.sort((a, b) =>
|
room.agents.sort((a, b) =>
|
||||||
a.agentType === b.agentType ? 0 : a.agentType === 'claude-code' ? -1 : 1,
|
a.agentType === b.agentType
|
||||||
|
? 0
|
||||||
|
: a.agentType === 'claude-code'
|
||||||
|
? -1
|
||||||
|
: 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
const agentParts = room.agents.map((a) => {
|
const agentParts = room.agents.map((a) => {
|
||||||
@@ -880,7 +897,11 @@ async function fetchClaudeUsage(): Promise<ClaudeUsageData | null> {
|
|||||||
// Back off for 10 minutes on rate limit
|
// Back off for 10 minutes on rate limit
|
||||||
usageApiBackoffUntil = Date.now() + 600_000;
|
usageApiBackoffUntil = Date.now() + 600_000;
|
||||||
logger.warn(
|
logger.warn(
|
||||||
{ status: 429, retryAfter: res.headers.get('retry-after'), body: body.slice(0, 200) },
|
{
|
||||||
|
status: 429,
|
||||||
|
retryAfter: res.headers.get('retry-after'),
|
||||||
|
body: body.slice(0, 200),
|
||||||
|
},
|
||||||
'Usage API rate limited (429), backing off 10min',
|
'Usage API rate limited (429), backing off 10min',
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -995,8 +1016,7 @@ async function buildUsageContent(): Promise<string> {
|
|||||||
(snapshot) =>
|
(snapshot) =>
|
||||||
snapshot.agentType === 'claude-code' &&
|
snapshot.agentType === 'claude-code' &&
|
||||||
snapshot.entries.some(
|
snapshot.entries.some(
|
||||||
(entry) =>
|
(entry) => entry.status === 'processing' || entry.status === 'waiting',
|
||||||
entry.status === 'processing' || entry.status === 'waiting',
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1208,7 +1228,9 @@ async function startStatusDashboard(): Promise<void> {
|
|||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
{ channelId: STATUS_CHANNEL_ID, isRenderer, agentType: SERVICE_AGENT_TYPE },
|
{ channelId: STATUS_CHANNEL_ID, isRenderer, agentType: SERVICE_AGENT_TYPE },
|
||||||
isRenderer ? 'Unified dashboard started' : 'Status snapshot updater started',
|
isRenderer
|
||||||
|
? 'Unified dashboard started'
|
||||||
|
: 'Status snapshot updater started',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1350,7 +1372,11 @@ async function startMessageLoop(): Promise<void> {
|
|||||||
lastAgentTimestamp[chatJid] || '',
|
lastAgentTimestamp[chatJid] || '',
|
||||||
ASSISTANT_NAME,
|
ASSISTANT_NAME,
|
||||||
);
|
);
|
||||||
const processablePending = getProcessableMessages(chatJid, allPending, channel);
|
const processablePending = getProcessableMessages(
|
||||||
|
chatJid,
|
||||||
|
allPending,
|
||||||
|
channel,
|
||||||
|
);
|
||||||
const messagesToSend =
|
const messagesToSend =
|
||||||
processablePending.length > 0
|
processablePending.length > 0
|
||||||
? processablePending
|
? processablePending
|
||||||
@@ -1392,9 +1418,17 @@ async function startMessageLoop(): Promise<void> {
|
|||||||
function recoverPendingMessages(): void {
|
function recoverPendingMessages(): void {
|
||||||
for (const [chatJid, group] of Object.entries(registeredGroups)) {
|
for (const [chatJid, group] of Object.entries(registeredGroups)) {
|
||||||
const sinceTimestamp = lastAgentTimestamp[chatJid] || '';
|
const sinceTimestamp = lastAgentTimestamp[chatJid] || '';
|
||||||
const rawPending = getMessagesSince(chatJid, sinceTimestamp, ASSISTANT_NAME);
|
const rawPending = getMessagesSince(
|
||||||
|
chatJid,
|
||||||
|
sinceTimestamp,
|
||||||
|
ASSISTANT_NAME,
|
||||||
|
);
|
||||||
const recoveryChannel = findChannel(channels, chatJid);
|
const recoveryChannel = findChannel(channels, chatJid);
|
||||||
const pending = getProcessableMessages(chatJid, rawPending, recoveryChannel ?? undefined);
|
const pending = getProcessableMessages(
|
||||||
|
chatJid,
|
||||||
|
rawPending,
|
||||||
|
recoveryChannel ?? undefined,
|
||||||
|
);
|
||||||
if (pending.length > 0) {
|
if (pending.length > 0) {
|
||||||
logger.info(
|
logger.info(
|
||||||
{ group: group.name, pendingCount: pending.length },
|
{ group: group.name, pendingCount: pending.length },
|
||||||
|
|||||||
@@ -49,7 +49,11 @@ export function readStatusSnapshots(maxAgeMs: number): StatusSnapshot[] {
|
|||||||
try {
|
try {
|
||||||
const raw = fs.readFileSync(snapshotPath, 'utf-8');
|
const raw = fs.readFileSync(snapshotPath, 'utf-8');
|
||||||
const parsed = JSON.parse(raw) as StatusSnapshot;
|
const parsed = JSON.parse(raw) as StatusSnapshot;
|
||||||
if (!parsed.updatedAt || !parsed.agentType || !Array.isArray(parsed.entries))
|
if (
|
||||||
|
!parsed.updatedAt ||
|
||||||
|
!parsed.agentType ||
|
||||||
|
!Array.isArray(parsed.entries)
|
||||||
|
)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const ageMs = now - new Date(parsed.updatedAt).getTime();
|
const ageMs = now - new Date(parsed.updatedAt).getTime();
|
||||||
|
|||||||
Reference in New Issue
Block a user