abtars 0.2.2 → 0.2.3-alpha.0

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.
Files changed (113) hide show
  1. package/bundle/{_registry.generated-KYX63MGY.js → _registry.generated-KM6LXTNJ.js} +2 -2
  2. package/bundle/abtars-cli.js +6 -3
  3. package/bundle/abtars-cli.js.map +2 -2
  4. package/bundle/abtars.js +29 -28
  5. package/bundle/abtars.js.map +3 -3
  6. package/bundle/{agent-registry-PIS5XJHX.js → agent-registry-ABPFQXNL.js} +2 -2
  7. package/bundle/{chunk-QSC6QZ44.js → chunk-2SFN2VYD.js} +2 -2
  8. package/bundle/{chunk-BBTQKKDO.js → chunk-2W6JIHZ5.js} +2 -1
  9. package/bundle/chunk-2W6JIHZ5.js.map +7 -0
  10. package/bundle/{chunk-3IPMKYYH.js → chunk-6TSCOXF6.js} +56 -25
  11. package/bundle/chunk-6TSCOXF6.js.map +7 -0
  12. package/bundle/{chunk-7WFE2JI5.js → chunk-7B3GK5JQ.js} +2 -2
  13. package/bundle/{chunk-SMZQDMSZ.js → chunk-ENXQMPV3.js} +1 -2
  14. package/bundle/chunk-ENXQMPV3.js.map +7 -0
  15. package/bundle/{chunk-N24ROESF.js → chunk-HFPXN6NM.js} +1 -1
  16. package/bundle/chunk-HFPXN6NM.js.map +7 -0
  17. package/bundle/{chunk-Y2XBDQP3.js → chunk-SEXVA3GK.js} +144 -37
  18. package/bundle/chunk-SEXVA3GK.js.map +7 -0
  19. package/bundle/{commands-LAWVNQTO.js → commands-L6VIMPCR.js} +2 -2
  20. package/bundle/{direct-api-transport-QIWA5ES2.js → direct-api-transport-BK72AP3I.js} +1 -1
  21. package/bundle/{direct-api-transport-QIWA5ES2.js.map → direct-api-transport-BK72AP3I.js.map} +2 -2
  22. package/bundle/{discord-adapter-W6L5KJ6T.js → discord-adapter-DWIQRNDI.js} +3 -3
  23. package/bundle/{doctor-PIPSGI3H.js → doctor-WHTVSUOF.js} +36 -26
  24. package/bundle/doctor-WHTVSUOF.js.map +7 -0
  25. package/bundle/{install-I3CXVW52.js → install-Q4XNCPG7.js} +2 -2
  26. package/bundle/{message-pipeline-4CTBJ6K2.js → message-pipeline-GCSZCQWO.js} +2 -2
  27. package/bundle/meta.json +298 -279
  28. package/bundle/{phase-transport-INFD6ELA.js → phase-transport-F7GQRRYE.js} +3 -3
  29. package/bundle/{sleep-ENFZFUJJ.js → sleep-MYOZ73IU.js} +2 -2
  30. package/bundle/{subagent-runtime-5AYOXOU2.js → subagent-runtime-QA4LVU4C.js} +2 -2
  31. package/bundle/{system-status-7K2QTH3J.js → system-status-KMKPAC5Z.js} +4 -2
  32. package/bundle/system-status-KMKPAC5Z.js.map +7 -0
  33. package/bundle/{telegram-adapter-4KI4CJPG.js → telegram-adapter-TRMCC634.js} +7 -4
  34. package/bundle/telegram-adapter-TRMCC634.js.map +7 -0
  35. package/config/transport.default.json +2 -1
  36. package/install-manifest.json +0 -3
  37. package/package.json +1 -1
  38. package/scripts/abtars-daemon.service +0 -4
  39. package/scripts/abtars@.service +0 -4
  40. package/scripts/build-and-deploy.sh +15 -27
  41. package/bundle/agent-registry-5VL5KI6U.js +0 -19
  42. package/bundle/chunk-3IPMKYYH.js.map +0 -7
  43. package/bundle/chunk-4WKWPU6U.js +0 -1089
  44. package/bundle/chunk-4WKWPU6U.js.map +0 -7
  45. package/bundle/chunk-5WFIAUQC.js +0 -672
  46. package/bundle/chunk-5WFIAUQC.js.map +0 -7
  47. package/bundle/chunk-B52YRWR6.js +0 -257
  48. package/bundle/chunk-B52YRWR6.js.map +0 -7
  49. package/bundle/chunk-BBTQKKDO.js.map +0 -7
  50. package/bundle/chunk-HAS5NEK7.js +0 -189
  51. package/bundle/chunk-HAS5NEK7.js.map +0 -7
  52. package/bundle/chunk-HB54S5OY.js +0 -4036
  53. package/bundle/chunk-HB54S5OY.js.map +0 -7
  54. package/bundle/chunk-N24ROESF.js.map +0 -7
  55. package/bundle/chunk-N7UG4FID.js +0 -4036
  56. package/bundle/chunk-N7UG4FID.js.map +0 -7
  57. package/bundle/chunk-PUDGA4RR.js +0 -183
  58. package/bundle/chunk-QSC6QZ44.js.map +0 -7
  59. package/bundle/chunk-SMZQDMSZ.js.map +0 -7
  60. package/bundle/chunk-VY2BUO6L.js +0 -4035
  61. package/bundle/chunk-VY2BUO6L.js.map +0 -7
  62. package/bundle/chunk-Y2XBDQP3.js.map +0 -7
  63. package/bundle/chunk-YMGX6HNP.js +0 -131
  64. package/bundle/chunk-YMGX6HNP.js.map +0 -7
  65. package/bundle/commands-IGRSOSK6.js +0 -34
  66. package/bundle/commands-RBWY7YXB.js +0 -34
  67. package/bundle/commands-XFZNMZN6.js +0 -34
  68. package/bundle/direct-api-transport-OZICXTWQ.js +0 -889
  69. package/bundle/direct-api-transport-OZICXTWQ.js.map +0 -7
  70. package/bundle/discord-adapter-JFIIVG34.js +0 -589
  71. package/bundle/discord-adapter-U3FA5OTY.js +0 -589
  72. package/bundle/discord-adapter-U3FA5OTY.js.map +0 -7
  73. package/bundle/discord-adapter-W6L5KJ6T.js.map +0 -7
  74. package/bundle/discord-adapter-WWM6ROTW.js +0 -589
  75. package/bundle/discord-adapter-WWM6ROTW.js.map +0 -7
  76. package/bundle/doctor-PIPSGI3H.js.map +0 -7
  77. package/bundle/kanban-board-6Q5E5GEB.js +0 -31
  78. package/bundle/kanban-board-6Q5E5GEB.js.map +0 -7
  79. package/bundle/message-pipeline-4CTBJ6K2.js.map +0 -7
  80. package/bundle/message-pipeline-4KL7OWUH.js +0 -38
  81. package/bundle/message-pipeline-4KL7OWUH.js.map +0 -7
  82. package/bundle/message-pipeline-GFKSHRFU.js +0 -38
  83. package/bundle/message-pipeline-GFKSHRFU.js.map +0 -7
  84. package/bundle/message-pipeline-TGI2WJJM.js +0 -38
  85. package/bundle/message-pipeline-TGI2WJJM.js.map +0 -7
  86. package/bundle/phase-transport-INFD6ELA.js.map +0 -7
  87. package/bundle/phase-transport-KXFZ5BVF.js +0 -23
  88. package/bundle/phase-transport-KXFZ5BVF.js.map +0 -7
  89. package/bundle/sleep-ENFZFUJJ.js.map +0 -7
  90. package/bundle/subagent-runtime-5AYOXOU2.js.map +0 -7
  91. package/bundle/subagent-runtime-VKTX6Q2M.js +0 -13
  92. package/bundle/subagent-runtime-VKTX6Q2M.js.map +0 -7
  93. package/bundle/system-status-7K2QTH3J.js.map +0 -7
  94. package/bundle/telegram-adapter-4KI4CJPG.js.map +0 -7
  95. package/bundle/telegram-adapter-76B4JRJJ.js +0 -1080
  96. package/bundle/telegram-adapter-76B4JRJJ.js.map +0 -7
  97. package/bundle/telegram-adapter-VZA74EMT.js +0 -1080
  98. package/bundle/telegram-adapter-VZA74EMT.js.map +0 -7
  99. package/bundle/telegram-adapter-ZO2CLU22.js +0 -1080
  100. package/bundle/telegram-adapter-ZO2CLU22.js.map +0 -7
  101. package/bundle/tool-registry-TGNU5AMG.js +0 -43
  102. package/bundle/tool-registry-TGNU5AMG.js.map +0 -7
  103. /package/bundle/{_registry.generated-KYX63MGY.js.map → _registry.generated-KM6LXTNJ.js.map} +0 -0
  104. /package/bundle/{agent-registry-5VL5KI6U.js.map → agent-registry-ABPFQXNL.js.map} +0 -0
  105. /package/bundle/{chunk-PUDGA4RR.js.map → chunk-2SFN2VYD.js.map} +0 -0
  106. /package/bundle/{chunk-7WFE2JI5.js.map → chunk-7B3GK5JQ.js.map} +0 -0
  107. /package/bundle/{agent-registry-PIS5XJHX.js.map → commands-L6VIMPCR.js.map} +0 -0
  108. /package/bundle/{discord-adapter-JFIIVG34.js.map → discord-adapter-DWIQRNDI.js.map} +0 -0
  109. /package/bundle/{commands-IGRSOSK6.js.map → install-Q4XNCPG7.js.map} +0 -0
  110. /package/bundle/{commands-LAWVNQTO.js.map → message-pipeline-GCSZCQWO.js.map} +0 -0
  111. /package/bundle/{commands-RBWY7YXB.js.map → phase-transport-F7GQRRYE.js.map} +0 -0
  112. /package/bundle/{commands-XFZNMZN6.js.map → sleep-MYOZ73IU.js.map} +0 -0
  113. /package/bundle/{install-I3CXVW52.js.map → subagent-runtime-QA4LVU4C.js.map} +0 -0
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/platforms/discord/discord-api.ts", "../src/platforms/discord/discord-poller.ts", "../src/platforms/discord/discord-adapter.ts"],
4
- "sourcesContent": ["import { logAndSwallow } from \"../../components/log-and-swallow.js\";\nimport {\n Client,\n GatewayIntentBits,\n Partials,\n type Message,\n type MessageReaction,\n type User,\n type TextChannel,\n} from \"discord.js\";\nimport { logInfo, logError, logDebug, logWarn } from \"../../components/logger.js\";\n\nconst TAG = \"DiscordApi\";\n\n/**\n * Thin wrapper around discord.js Client.\n * Provides typed methods for Gateway connection, message listening, and sending.\n */\nexport class DiscordApi {\n private readonly client: Client;\n private readonly token: string;\n private ready = false;\n\n constructor(botToken: string) {\n this.token = botToken;\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.GuildMessageReactions,\n GatewayIntentBits.DirectMessages,\n GatewayIntentBits.MessageContent,\n ],\n partials: [Partials.Channel, Partials.Message, Partials.Reaction],\n });\n\n this.client.on(\"clientReady\", () => {\n this.ready = true;\n logInfo(TAG, `Connected as ${this.client.user?.tag ?? \"unknown\"}`);\n });\n\n this.client.on(\"error\", (err) => {\n logError(TAG, \"Client error\", err);\n });\n }\n\n /** Connect to the Discord Gateway. Resolves when the client is ready. */\n async connect(): Promise<void> {\n logInfo(TAG, \"Connecting to Discord Gateway\u2026\");\n return new Promise<void>((resolve, reject) => {\n const onReady = () => {\n cleanup();\n resolve();\n };\n const onError = (err: Error) => {\n cleanup();\n reject(err);\n };\n const cleanup = () => {\n this.client.removeListener(\"clientReady\", onReady);\n this.client.removeListener(\"error\", onError);\n };\n\n this.client.once(\"clientReady\", onReady);\n this.client.once(\"error\", onError);\n\n this.client.login(this.token).catch((err: unknown) => {\n cleanup();\n reject(err instanceof Error ? err : new Error(String(err)));\n });\n });\n }\n\n /** Register a handler for MESSAGE_CREATE events. */\n onMessage(handler: (message: Message) => void | Promise<void>): void {\n this.client.on(\"messageCreate\", (message) => {\n logDebug(TAG, `Message from ${message.author.tag} in #${message.channel.id}`);\n try {\n const result = handler(message);\n if (result instanceof Promise) {\n result.catch((err: unknown) => {\n logError(TAG, \"Message handler error\", err);\n });\n }\n } catch (err) {\n logError(TAG, \"Message handler error\", err);\n }\n });\n }\n\n /** Register a handler for MESSAGE_REACTION_ADD events. */\n onReaction(handler: (reaction: MessageReaction, user: User) => void | Promise<void>): void {\n this.client.on(\"messageReactionAdd\", async (reaction, user) => {\n if (user.bot) return;\n try {\n if (reaction.partial) await reaction.fetch();\n if (user.partial) await user.fetch();\n } catch (err) { logAndSwallow(TAG, \"fetch reaction/user partial\", err); return; }\n try {\n const result = handler(reaction as MessageReaction, user as User);\n if (result instanceof Promise) result.catch((err: unknown) => logError(TAG, \"Reaction handler error\", err));\n } catch (err) { logError(TAG, \"Reaction handler error\", err); }\n });\n }\n\n /** Register a handler for slash command interactions. */\n onInteraction(handler: (interaction: import(\"discord.js\").ChatInputCommandInteraction) => void | Promise<void>): void {\n this.client.on(\"interactionCreate\", async (interaction) => {\n if (interaction.isChatInputCommand()) {\n try {\n const result = handler(interaction);\n if (result instanceof Promise) result.catch((err: unknown) => logError(TAG, \"Interaction handler error\", err));\n } catch (err) { logError(TAG, \"Interaction handler error\", err); }\n }\n if (interaction.isStringSelectMenu()) {\n this.selectMenuHandlers.get(interaction.customId)?.(interaction);\n }\n });\n }\n\n private selectMenuHandlers = new Map<string, (i: import(\"discord.js\").StringSelectMenuInteraction) => void | Promise<void>>();\n\n onSelectMenu(customId: string, handler: (interaction: import(\"discord.js\").StringSelectMenuInteraction) => void | Promise<void>): void {\n this.selectMenuHandlers.set(customId, handler);\n }\n\n /** Register global application commands. Idempotent \u2014 Discord diffs and updates. */\n async registerCommands(commands: Array<{ name: string; description: string }>): Promise<void> {\n if (!this.client.application) {\n logWarn(TAG, \"Cannot register commands \u2014 application not available\");\n return;\n }\n await this.client.application.commands.set(commands.map(c => ({ name: c.name, description: c.description, type: 1 as const })));\n logInfo(TAG, `Registered ${commands.length} slash commands`);\n }\n\n /** Send a text message to a channel. Returns the sent message ID. */\n async sendMessage(channelId: string, text: string): Promise<string> {\n const channel = await this.client.channels.fetch(channelId);\n if (!channel?.isTextBased()) {\n throw new Error(`Channel ${channelId} is not a text channel`);\n }\n const sent = await (channel as TextChannel).send(text);\n logDebug(TAG, `Sent message ${sent.id} to channel ${channelId}`);\n return sent.id;\n }\n\n /** Send typing indicator to a channel. */\n async sendTyping(channelId: string): Promise<void> {\n try {\n const channel = await this.client.channels.fetch(channelId);\n if (channel?.isTextBased()) await (channel as TextChannel).sendTyping();\n } catch (err) { logAndSwallow(\"discord_api\", \"op\", err); }\n }\n\n /** Add or remove a reaction on a message. Empty emoji = remove bot's reactions. */\n async setReaction(channelId: string, messageId: string, emoji: string): Promise<void> {\n try {\n const channel = await this.client.channels.fetch(channelId);\n if (!channel?.isTextBased()) return;\n const message = await (channel as TextChannel).messages.fetch(messageId);\n if (!emoji) {\n // Remove bot's reactions\n const botId = this.client.user?.id;\n if (botId) {\n for (const reaction of message.reactions.cache.values()) {\n await reaction.users.remove(botId).catch(err => logAndSwallow(TAG, \"remove bot reaction\", err));\n }\n }\n } else {\n await message.react(emoji);\n }\n } catch (err) { logAndSwallow(\"discord_api\", \"op\", err); }\n }\n\n /** Edit a previously sent message. */\n async editMessage(channelId: string, messageId: string, text: string): Promise<void> {\n try {\n const channel = await this.client.channels.fetch(channelId);\n if (!channel?.isTextBased()) return;\n const message = await (channel as TextChannel).messages.fetch(messageId);\n await message.edit(text);\n } catch (err) { logAndSwallow(\"discord_api\", \"op\", err); }\n }\n\n /** Gracefully close the Gateway connection. */\n async disconnect(): Promise<void> {\n logInfo(TAG, \"Disconnecting from Discord Gateway\u2026\");\n this.ready = false;\n this.client.destroy();\n }\n\n /** Whether the client is connected and ready. */\n get isReady(): boolean {\n return this.ready;\n }\n\n /** Get the bot's own user ID (for filtering self-messages). */\n get botUserId(): string | null {\n return this.client.user?.id ?? null;\n }\n\n /** Fetch a specific message by channel + message ID. Returns null on failure. (#388) */\n async fetchMessage(channelId: string, messageId: string): Promise<{ authorId: string } | null> {\n try {\n const channel = await this.client.channels.fetch(channelId);\n if (!channel?.isTextBased()) return null;\n const msg = await (channel as TextChannel).messages.fetch(messageId);\n return msg ? { authorId: msg.author.id } : null;\n } catch (err) { logAndSwallow(TAG, \"fetchMessage\", err); return null; }\n }\n}\n", "import type { Message } from \"discord.js\";\nimport type { DiscordInboundMessage } from \"../../types/discord.js\";\nimport type { DiscordApi } from \"./discord-api.js\";\nimport { logInfo, logDebug, logWarn } from \"../../components/logger.js\";\n\nconst TAG = \"DiscordPoller\";\n\n/**\n * Event-driven listener for Discord messages via the Gateway WebSocket.\n * Mirrors TelegramPoller in lifecycle (start/stop) but uses discord.js\n * event handlers instead of long-polling. Reconnection and heartbeat\n * are handled by discord.js internally.\n */\nexport class DiscordPoller {\n private readonly api: DiscordApi;\n private readonly appId: string;\n private readonly onMessage: (message: DiscordInboundMessage) => void | Promise<void>;\n private started = false;\n\n constructor(\n api: DiscordApi,\n appId: string,\n onMessage: (message: DiscordInboundMessage) => void | Promise<void>,\n ) {\n this.api = api;\n this.appId = appId;\n this.onMessage = onMessage;\n }\n\n /** Connect to Gateway and start listening. */\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n await this.api.connect();\n\n this.api.onMessage((raw: Message) => {\n // Filter out self-messages (use appId from config, fallback to client user id)\n const selfId = this.api.botUserId ?? this.appId;\n if (raw.author.id === selfId) {\n logDebug(TAG, `Ignoring self-message ${raw.id}`);\n return;\n }\n\n const inbound = toDiscordInboundMessage(raw, this.appId);\n logDebug(TAG, `Dispatching message ${inbound.id} from ${inbound.authorUsername}`);\n\n try {\n const result = this.onMessage(inbound);\n if (result instanceof Promise) {\n result.catch((err: unknown) => {\n logWarn(TAG, `Error in message callback: ${err instanceof Error ? err.message : String(err)}`);\n });\n }\n } catch (err) {\n logWarn(TAG, `Error in message callback: ${err instanceof Error ? err.message : String(err)}`);\n }\n });\n\n logInfo(TAG, \"Started \u2014 listening for Discord messages\");\n }\n\n /** Disconnect from Gateway cleanly. */\n stop(): void {\n if (!this.started) return;\n this.started = false;\n this.api.disconnect();\n logInfo(TAG, \"Stopped\");\n }\n}\n\n/** Convert a raw discord.js Message to a DiscordInboundMessage. */\nfunction toDiscordInboundMessage(raw: Message, botId: string | null): DiscordInboundMessage {\n const parentId = \"parentId\" in raw.channel ? (raw.channel.parentId ?? null) : null;\n const channelName = \"name\" in raw.channel ? (raw.channel.name ?? null) : null;\n // Check both discord.js parsed mentions AND raw content for the bot's mention tag\n const mentionsBotId = botId\n ? (raw.mentions.users.has(botId) || new RegExp(`<@!?${botId}>`).test(raw.content))\n : false;\n\n // #388 \u2014 role-mention detection. Look up the bot's own guild member and check\n // if any of its role IDs appear in raw.mentions.roles. If the bot's member isn't\n // cached yet (cold start, first message in a guild), stay safe by returning false \u2014\n // a missed role-mention is better than an accidental always-respond.\n const botMember = raw.guild?.members.me ?? null;\n const botRoleIds = botMember ? new Set([...botMember.roles.cache.keys()]) : new Set<string>();\n const mentionsBotRole = botMember\n ? [...raw.mentions.roles.keys()].some(rid => botRoleIds.has(rid))\n : false;\n\n logDebug(TAG, `mentionsBotId=${mentionsBotId} mentionsBotRole=${mentionsBotRole} (appId=${botId}, mentions=${[...raw.mentions.users.keys()].join(\",\")}, content=${raw.content.slice(0, 60)})`);\n return {\n id: raw.id,\n channelId: raw.channelId,\n parentChannelId: parentId,\n channelName,\n isDM: !raw.guildId,\n authorId: raw.author.id,\n authorUsername: raw.author.username,\n authorIsBot: raw.author.bot ?? false,\n content: raw.content,\n timestamp: raw.createdTimestamp,\n mentionsBotId,\n mentionsBotRole,\n mentionsEveryone: raw.mentions.everyone,\n hasUserMentions: raw.mentions.users.size > 0,\n replyReferenceMessageId: raw.reference?.messageId ?? null,\n attachments: raw.attachments.size > 0\n ? [...raw.attachments.values()].map(a => ({ url: a.url, filename: a.name ?? \"file\", contentType: a.contentType ?? undefined, size: a.size }))\n : undefined,\n };\n}\n", "/**\n * Discord platform adapter \u2014 wraps DiscordApi, DiscordPoller, DiscordSecurityGate.\n * Handles Discord-specific pre-processing (mention stripping, A2A routing, sender prefix)\n * then delegates to the shared message pipeline.\n */\n\nimport { DiscordApi } from \"./discord-api.js\";\nimport { DiscordPoller } from \"./discord-poller.js\";\nimport { SecurityGate } from \"../../components/security-gate.js\";\nimport { loadUsers } from \"../../components/user-registry.js\";\nimport { BOT_COMMANDS } from \"../../components/command-registry.js\";\nimport { ResponseFormatter } from \"../../components/response-formatter.js\";\nimport { formatReactionSignal } from \"../../components/reactions.js\";\n\nexport const DISCORD_CAPABILITIES: PlatformCapabilities = { voice: false, reactions: true, typing: true, threads: true };\nimport { emojiToScore, emojiToTag } from \"../../utils/emoji-score.js\";\nimport { logInfo, logWarn, logDebug } from \"../../components/logger.js\";\nimport { logAndSwallow } from \"../../components/log-and-swallow.js\";\nimport { getEnv } from \"../../components/env-schema.js\";\nimport { handleInboundMessage, type PipelineDeps } from \"../../components/message-pipeline.js\";\nimport type { PlatformAdapter, PlatformCapabilities, InboundMessage, SendOpts } from \"../../types/platform.js\";\nimport type { DiscordInboundMessage } from \"../../types/index.js\";\nimport type { IKiroTransport } from \"../../components/transport/kiro-transport.js\";\nimport type { IMemorySystem } from \"abmind\";\nimport type { ConversationBuffer } from \"../../components/conversation-buffer.js\";\n\nconst TAG = \"discord\";\n\nexport interface DiscordAdapterConfig {\n botToken: string;\n appId: string;\n allowedUserIds: Set<string>;\n}\n\nexport interface DiscordAdapterDeps {\n pipeline: PipelineDeps;\n transport: IKiroTransport;\n memory: IMemorySystem | null;\n conversationBuffer: ConversationBuffer;\n}\n\nexport class DiscordAdapter implements PlatformAdapter {\n readonly name = \"discord\" as const;\n readonly capabilities: PlatformCapabilities = DISCORD_CAPABILITIES;\n\n private readonly api: DiscordApi;\n private readonly securityGate: SecurityGate;\n private readonly formatter = new ResponseFormatter();\n private readonly config: DiscordAdapterConfig;\n private readonly deps: DiscordAdapterDeps;\n private poller: DiscordPoller | null = null;\n\n constructor(config: DiscordAdapterConfig, deps: DiscordAdapterDeps) {\n this.api = new DiscordApi(config.botToken);\n this.securityGate = new SecurityGate(loadUsers());\n this.config = config;\n this.deps = deps;\n }\n\n async start(): Promise<void> {\n this.poller = new DiscordPoller(this.api, this.config.appId, (m) => this.handleMessage(m));\n this.api.onReaction((reaction, user) => this.handleReaction(reaction, user));\n this.api.onInteraction((interaction) => this.handleInteraction(interaction));\n await this.poller.start();\n\n // Register slash commands (idempotent)\n await this.api.registerCommands([...BOT_COMMANDS]).catch(err =>\n logWarn(TAG, `Slash command registration failed: ${err instanceof Error ? err.message : String(err)}`),\n );\n }\n\n /** Handle Discord slash command interactions. */\n private async handleInteraction(interaction: import(\"discord.js\").ChatInputCommandInteraction): Promise<void> {\n // Interactive model picker for /model and /models\n if (interaction.commandName === \"model\" || interaction.commandName === \"models\") {\n await this.handleModelPicker(interaction);\n return;\n }\n\n await interaction.deferReply();\n\n const registry = loadUsers();\n const userEntry = registry.byPlatformId.get(`discord:${interaction.user.id}`);\n if (!this.securityGate.authorizeById(interaction.user.id, interaction.channelId)) {\n await interaction.editReply(\"\u26D4 Unauthorized.\");\n return;\n }\n\n const commandText = `/${interaction.commandName}`;\n const userId = userEntry?.userId ?? \"unknown\";\n const channelId = interaction.channelId;\n\n // Wrap adapter so pipeline responses route through the interaction reply\n let initialReplied = false;\n const interactionAdapter: PlatformAdapter = {\n ...this,\n sendMessage: async (_ch: string, text: string): Promise<string | undefined> => {\n if (!text?.trim()) return undefined;\n const chunks = text.length <= 2000 ? [text] : text.match(/.{1,2000}/gs) ?? [text];\n let lastId: string | undefined;\n for (const chunk of chunks) {\n if (!initialReplied) {\n initialReplied = true;\n const sent = await interaction.editReply(chunk);\n lastId = sent.id;\n } else {\n const sent = await interaction.followUp(chunk);\n lastId = sent.id;\n }\n }\n return lastId;\n },\n editMessage: async (_ch: string, _messageId: number | string, text: string): Promise<void> => {\n // For interaction replies, editReply edits the initial deferred response\n await interaction.editReply(text);\n },\n };\n\n const msg: InboundMessage = {\n text: commandText,\n channelId,\n userId,\n senderId: interaction.user.id,\n senderName: interaction.user.username ?? \"unknown\",\n platform: \"discord\",\n timestamp: Date.now(),\n isGroup: !!interaction.guildId,\n isVoice: false,\n };\n\n await handleInboundMessage(msg, interactionAdapter, this.deps.pipeline);\n }\n\n /** Interactive model picker \u2014 ephemeral select menus. */\n private async handleModelPicker(interaction: import(\"discord.js\").ChatInputCommandInteraction): Promise<void> {\n const { ActionRowBuilder, StringSelectMenuBuilder } = await import(\"discord.js\");\n const { loadTransport } = await import(\"../../components/transport-config.js\");\n const tc = loadTransport();\n if (!tc) { await interaction.reply({ content: \"No transport config.\", ephemeral: true }); return; }\n\n const providers = Object.entries(tc.providers).map(([id, p]) => ({ id, name: (p as any).name ?? id }));\n if (providers.length === 0) {\n await interaction.reply({ content: \"No providers configured.\", ephemeral: true });\n return;\n }\n\n const menu = new StringSelectMenuBuilder()\n .setCustomId(\"model_picker_provider\")\n .setPlaceholder(\"Select provider\")\n .addOptions(providers.slice(0, 25).map(p => ({ label: p.name, value: p.id })));\n\n const row = new ActionRowBuilder<import(\"discord.js\").StringSelectMenuBuilder>().addComponents(menu);\n await interaction.reply({ content: \"\uD83D\uDD27 Select provider:\", components: [row], ephemeral: true });\n\n // Handle provider selection \u2192 show models\n this.api.onSelectMenu(\"model_picker_provider\", async (selectInteraction) => {\n const providerId = selectInteraction.values[0]!;\n const provider = tc.providers[providerId];\n if (!provider) { await selectInteraction.update({ content: \"Provider not found.\", components: [] }); return; }\n\n const { getModelsForProvider } = await import(\"../../components/transport-config.js\");\n const models = getModelsForProvider(providerId).filter((m) => m.entry.status === \"alive\" || !m.entry.status).slice(0, 25);\n if (models.length === 0) { await selectInteraction.update({ content: `No models for ${providerId}.`, components: [] }); return; }\n\n const modelMenu = new StringSelectMenuBuilder()\n .setCustomId(\"model_picker_model\")\n .setPlaceholder(\"Select model\")\n .addOptions(models.map((m) => ({ label: m.id, value: m.id })));\n\n const modelRow = new ActionRowBuilder<import(\"discord.js\").StringSelectMenuBuilder>().addComponents(modelMenu);\n await selectInteraction.update({ content: `Provider: **${providerId}**\\nSelect model:`, components: [modelRow] });\n\n // Handle model selection \u2192 apply\n this.api.onSelectMenu(\"model_picker_model\", async (modelInteraction) => {\n const modelId = modelInteraction.values[0]!;\n // Route through command handler as /model <provider> <model>\n await modelInteraction.update({ content: `\u2705 Switching to **${providerId}/${modelId}**...`, components: [] });\n\n // Trigger the actual switch via the command pipeline\n const msg: InboundMessage = {\n text: `/model ${providerId} ${modelId}`,\n channelId: modelInteraction.channelId,\n userId: interaction.user.id,\n senderId: interaction.user.id,\n senderName: interaction.user.username ?? \"unknown\",\n platform: \"discord\",\n timestamp: Date.now(),\n isGroup: !!interaction.guildId,\n isVoice: false,\n };\n await handleInboundMessage(msg, this, this.deps.pipeline);\n });\n });\n }\n\n stop(): void {\n this.poller?.stop();\n this.poller = null;\n }\n\n authorize(msg: InboundMessage): boolean {\n // Discord security uses string IDs + channel check\n return this.securityGate.authorizeById(msg.senderId, msg.channelId);\n }\n\n async sendMessage(channelId: string, text: string, _opts?: SendOpts): Promise<string | undefined> {\n const id = await this.api.sendMessage(channelId, text);\n return id || undefined;\n }\n\n async sendTyping(channelId: string): Promise<void> {\n await this.api.sendTyping(channelId);\n }\n\n async setReaction(channelId: string, messageId: number | string, emoji: string): Promise<void> {\n await this.api.setReaction(channelId, String(messageId), emoji);\n }\n\n async editMessage(channelId: string, messageId: number | string, text: string): Promise<void> {\n await this.api.editMessage(channelId, String(messageId), text);\n }\n\n chunkResponse(text: string): string[] {\n return this.formatter.chunkForPlatform(text, \"discord\");\n }\n\n injectMessage(msg: InboundMessage): void {\n // Discord doesn't support synthetic injection the same way.\n // For sleep replay, we call handleInboundMessage directly.\n handleInboundMessage(msg, this, this.deps.pipeline).catch((err) => {\n logWarn(TAG, `Failed to replay queued message: ${err instanceof Error ? err.message : String(err)}`);\n });\n }\n\n // --- Internal: Discord message handler ---\n\n private async handleMessage(message: DiscordInboundMessage): Promise<void> {\n logDebug(TAG, `Message from ${message.authorUsername} in ${message.channelId}`);\n\n const effectiveChannelId = message.parentChannelId ?? message.channelId;\n\n if (!this.securityGate.authorizeById(message.authorId, effectiveChannelId)) {\n logDebug(TAG, `Unauthorized user=${message.authorId} channel=${effectiveChannelId}`);\n return;\n }\n\n const rawText = message.content.trim();\n if (!rawText && !message.attachments?.length) return;\n\n // Strip bot's own mention\n let text = rawText.replace(new RegExp(`<@!?${this.config.appId}>`, \"g\"), \"\").replace(/\\s{2,}/g, \" \").trim();\n\n // Download attachments\n let mediaPath: string | undefined;\n if (message.attachments?.length) {\n try {\n const { saveInboundMedia } = await import(\"../../components/media-utils.js\");\n const att = message.attachments[0]!; // handle first attachment\n const res = await fetch(att.url);\n if (res.ok) {\n const buf = Buffer.from(await res.arrayBuffer());\n const extHint = att.filename ? \".\" + (att.filename.split(\".\").pop() ?? \"\") : undefined;\n const saved = await saveInboundMedia(buf, message.channelId, { extHint, claimedMime: att.contentType });\n if (saved) {\n mediaPath = saved.path;\n if (!text) text = `User sent a ${saved.isImage ? \"photo\" : \"file\"}.`;\n }\n }\n } catch (err) {\n logWarn(TAG, `Attachment download failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n if (!text) return;\n\n // Mention filter: in non-DM channels, check DISCORD_GROUP_MENTIONS mode.\n const isDM = message.isDM;\n if (!isDM) {\n const mentionMode = getEnv().discordGroupMentions; // \"required\" | \"optional\"\n\n if (mentionMode === \"optional\") {\n // Skip messages that mention someone else (not us, not @everyone)\n if (message.hasUserMentions && !message.mentionsBotId && !message.mentionsBotRole && !message.mentionsEveryone) {\n logDebug(TAG, `Skipped \u2014 mentions another user (optional mode, channel=${effectiveChannelId})`);\n return;\n }\n } else {\n // Required mode: must be explicitly addressed\n let isReplyToBot = false;\n if (message.replyReferenceMessageId && this.config.appId) {\n try {\n const referenced = await this.api.fetchMessage(message.channelId, message.replyReferenceMessageId);\n isReplyToBot = referenced?.authorId === this.config.appId;\n } catch (err) { logAndSwallow(TAG, \"fetchMessage reply ref\", err); }\n }\n\n const addressed = message.mentionsBotId || message.mentionsBotRole || isReplyToBot;\n if (!addressed) {\n logDebug(TAG, `Skipped \u2014 not addressed (channel=${effectiveChannelId})`);\n return;\n }\n }\n }\n\n const channelLabel = message.parentChannelId ? message.channelName ?? \"thread\" : message.channelName ?? \"DM\";\n const senderPrefix = isDM ? \"\" : `[${message.authorUsername}${message.authorIsBot ? \" (bot)\" : \"\"}] in #${channelLabel}: `;\n\n const inbound: InboundMessage = {\n platform: \"discord\",\n channelId: message.channelId,\n userId: loadUsers().byPlatformId.get(\"discord:\" + message.authorId)?.userId ?? \"unknown\",\n senderId: message.authorId,\n senderName: message.authorUsername,\n text: senderPrefix + text,\n timestamp: message.timestamp,\n isGroup: !isDM,\n isVoice: false,\n mediaPath,\n rawPlatformData: message,\n };\n\n // #512: commands bypass sequential await\n if (text.startsWith(\"/\") && !text.startsWith(\"//\")) {\n handleInboundMessage(inbound, this, this.deps.pipeline).catch(err => logAndSwallow(TAG, \"handleInboundMessage command\", err));\n return;\n }\n\n await handleInboundMessage(inbound, this, this.deps.pipeline);\n }\n\n private async handleReaction(\n reaction: import(\"discord.js\").MessageReaction,\n user: import(\"discord.js\").User,\n ): Promise<void> {\n const channelId = reaction.message.channelId;\n const messageId = Number(reaction.message.id);\n const emoji = reaction.emoji.name ?? \"\";\n if (!emoji) return;\n\n const isAuthorized = this.securityGate.authorizeById(user.id, channelId);\n const senderName = user.username || `id:${user.id}`;\n logInfo(TAG, `Reaction ${emoji} from ${senderName} on msg ${reaction.message.id}`);\n\n // Emotion scoring on authorized reactions\n if (isAuthorized && this.deps.memory) {\n const score = emojiToScore(emoji);\n const tag = emojiToTag(emoji);\n const resolvedUserId = loadUsers().byPlatformId.get(\"discord:\" + user.id)?.userId ?? \"unknown\";\n const updated = this.deps.memory.updateEmotionByPlatformId(resolvedUserId, messageId, score, tag);\n if (updated) logDebug(TAG, `Emotion score ${score} set on msg ${reaction.message.id}`);\n }\n\n if (!isAuthorized) {\n logDebug(TAG, `Unauthorized reaction from ${user.id}, discarding`);\n return;\n }\n\n // Buffer reaction signal for next message context\n const signal = formatReactionSignal(senderName, [emoji]);\n const bufKey = `discord:${channelId}`;\n this.deps.conversationBuffer.push(bufKey, senderName, signal);\n logDebug(TAG, `Buffered reaction signal for channel ${channelId}`);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["TAG", "TAG"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/components/doctor/index.ts"],
4
- "sourcesContent": ["/**\n * doctor \u2014 deep runtime healthcheck. Probes every subsystem in parallel.\n * Shared cache (60s) prevents token-burning spam.\n */\n\nimport { logInfo } from \"../logger.js\";\nimport { logAndSwallow } from \"../log-and-swallow.js\";\n\nconst TAG = \"doctor\";\n\nexport interface ProbeResult {\n name: string;\n status: \"ok\" | \"failed\" | \"skipped\";\n latencyMs: number;\n detail?: string;\n}\n\nexport interface DoctorReport {\n results: ProbeResult[];\n totalMs: number;\n cached: boolean;\n cacheAgeMs?: number;\n}\n\nexport interface DoctorCtx {\n memory?: { getStats: () => any; getCronInfo: () => any } | null;\n transport?: { sendPrompt: (key: string, msg: string) => Promise<string> } | null;\n telegramRunning?: boolean;\n discordRunning?: boolean;\n config?: { webPort?: number } | null;\n phaseHealth?: Map<string, { status: \"ok\" | \"failed\" | \"skipped\"; error?: string }>;\n}\n\ntype ProbeFn = (ctx: DoctorCtx) => Promise<ProbeResult>;\n\nfunction withTimeout(probe: ProbeFn, timeoutMs: number): ProbeFn {\n return async (ctx) => {\n const start = Date.now();\n try {\n const result = await Promise.race([\n probe(ctx),\n new Promise<ProbeResult>((_, reject) => setTimeout(() => reject(new Error(\"timeout\")), timeoutMs)),\n ]);\n return result;\n } catch (err) {\n return { name: \"unknown\", status: \"failed\", latencyMs: Date.now() - start, detail: `timeout after ${timeoutMs}ms` };\n }\n };\n}\n\n// \u2500\u2500 Probes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst probeMemory: ProbeFn = async (ctx) => {\n const start = Date.now();\n if (!ctx.memory) return { name: \"memory\", status: \"skipped\", latencyMs: 0, detail: \"not configured\" };\n try {\n ctx.memory.getStats();\n return { name: \"memory\", status: \"ok\", latencyMs: Date.now() - start };\n } catch (err) {\n return { name: \"memory\", status: \"failed\", latencyMs: Date.now() - start, detail: String(err) };\n }\n};\n\nconst probeTelegram: ProbeFn = async (ctx) => {\n const start = Date.now();\n if (!ctx.telegramRunning) return { name: \"telegram\", status: \"skipped\", latencyMs: 0, detail: \"not configured\" };\n return { name: \"telegram\", status: \"ok\", latencyMs: Date.now() - start, detail: \"running\" };\n};\n\nconst probeDiscord: ProbeFn = async (ctx) => {\n const start = Date.now();\n if (!ctx.discordRunning) return { name: \"discord\", status: \"skipped\", latencyMs: 0, detail: \"not configured\" };\n return { name: \"discord\", status: \"ok\", latencyMs: Date.now() - start, detail: \"running\" };\n};\n\nconst probeHeartbeat: ProbeFn = async (ctx) => {\n const start = Date.now();\n if (!ctx.memory || typeof ctx.memory.getCronInfo !== \"function\") return { name: \"heartbeat\", status: \"skipped\", latencyMs: 0 };\n try {\n const info = ctx.memory.getCronInfo();\n const running = info.heartbeatRunning;\n return { name: \"heartbeat\", status: running ? \"ok\" : \"failed\", latencyMs: Date.now() - start, detail: running ? `interval ${info.intervalMs}ms` : \"not running\" };\n } catch (err) {\n logAndSwallow(TAG, \"probe heartbeat\", err);\n return { name: \"heartbeat\", status: \"failed\", latencyMs: Date.now() - start };\n }\n};\n\nconst probeTransport: ProbeFn = async (ctx) => {\n const start = Date.now();\n if (!ctx.transport) return { name: \"transport\", status: \"skipped\", latencyMs: 0, detail: \"not configured\" };\n try {\n await ctx.transport.sendPrompt(\"__doctor_probe__\", \"hi\");\n return { name: \"transport\", status: \"ok\", latencyMs: Date.now() - start };\n } catch (err) {\n return { name: \"transport\", status: \"failed\", latencyMs: Date.now() - start, detail: (err as Error).message?.slice(0, 80) };\n }\n};\n\nconst probeDashboard: ProbeFn = async (ctx) => {\n const start = Date.now();\n const port = (ctx as any).config?.webPort ?? 3000;\n try {\n const res = await fetch(`http://localhost:${port}/`, { signal: AbortSignal.timeout(5000) });\n return { name: \"dashboard\", status: res.ok ? \"ok\" : \"failed\", latencyMs: Date.now() - start };\n } catch (err) {\n logAndSwallow(TAG, \"probe dashboard\", err);\n return { name: \"dashboard\", status: \"skipped\", latencyMs: Date.now() - start, detail: \"not running\" };\n }\n};\n\nconst probeOllama: ProbeFn = async (_ctx) => {\n const start = Date.now();\n try {\n const res = await fetch(\"http://localhost:11434/api/tags\", { signal: AbortSignal.timeout(5000) });\n return { name: \"ollama\", status: res.ok ? \"ok\" : \"failed\", latencyMs: Date.now() - start };\n } catch (err) {\n logAndSwallow(TAG, \"probe ollama\", err);\n return { name: \"ollama\", status: \"skipped\", latencyMs: Date.now() - start, detail: \"not reachable\" };\n }\n};\n\nconst probeCoreFiles: ProbeFn = async (_ctx) => {\n const { existsSync } = await import(\"node:fs\");\n const { join } = await import(\"node:path\");\n const { homedir } = await import(\"node:os\");\n const start = Date.now();\n const memDir = process.env[\"ABMIND_MEMORY_DIR\"] || join(homedir(), \".abmind\", \"memory\");\n const abmindCore = join(memDir, \"core\");\n const required = [\"SOUL.md\", \"user_profile.md\", \"agent_notes.md\", \"memory-tools.md\", \"core_facts.md\"];\n const missing = required.filter(f => !existsSync(join(abmindCore, f)));\n if (missing.length === 0) return { name: \"core-files\", status: \"ok\", latencyMs: Date.now() - start };\n return { name: \"core-files\", status: \"failed\", latencyMs: Date.now() - start, detail: `missing: ${missing.join(\", \")}` };\n};\n\nconst probeTlsIdentity: ProbeFn = async (_ctx) => {\n const { existsSync } = await import(\"node:fs\");\n const { execSync } = await import(\"node:child_process\");\n const { join } = await import(\"node:path\");\n const { abtarsHome } = await import(\"../../paths.js\");\n const start = Date.now();\n const issues: string[] = [];\n try { execSync(\"which openssl\", { stdio: \"ignore\" }); } catch { issues.push(\"openssl not found\"); }\n const configDir = join(abtarsHome(), \"config\");\n if (!existsSync(join(configDir, \"identity.crt\"))) issues.push(\"identity.crt missing\");\n if (!existsSync(join(configDir, \"identity.tls.key\"))) issues.push(\"identity.tls.key missing\");\n if (issues.length === 0) return { name: \"tls-identity\", status: \"ok\", latencyMs: Date.now() - start };\n return { name: \"tls-identity\", status: \"failed\", latencyMs: Date.now() - start, detail: issues.join(\", \") };\n};\n\nconst probeSecretPerms: ProbeFn = async (_ctx) => {\n const { readdirSync, statSync } = await import(\"node:fs\");\n const { join } = await import(\"node:path\");\n const { abtarsHome } = await import(\"../../paths.js\");\n const start = Date.now();\n const secretDir = join(abtarsHome(), \"secret\");\n let files: string[];\n try { files = readdirSync(secretDir); } catch (err) { logAndSwallow(TAG, \"readdirSync secret dir\", err); return { name: \"secret-perms\", status: \"skipped\", latencyMs: 0, detail: \"no secret/ dir\" }; }\n const bad: string[] = [];\n for (const f of files) {\n const st = statSync(join(secretDir, f));\n if (!st.isFile()) continue;\n const mode = st.mode & 0o777;\n if (mode !== 0o600) bad.push(`${f} (${mode.toString(8)})`);\n }\n if (bad.length === 0) return { name: \"secret-perms\", status: \"ok\", latencyMs: Date.now() - start, detail: `${files.filter(f => statSync(join(secretDir, f)).isFile()).length} files, all 600` };\n return { name: \"secret-perms\", status: \"failed\", latencyMs: Date.now() - start, detail: `not 600: ${bad.join(\", \")}` };\n};\n\n// \u2500\u2500 Collector \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst probeFtsIntegrity: ProbeFn = async (_ctx) => {\n const { join } = await import(\"node:path\");\n const { homedir } = await import(\"node:os\");\n const { execSync } = await import(\"node:child_process\");\n const start = Date.now();\n try {\n const dbPath = join(process.env[\"ABMIND_MEMORY_DIR\"] || join(homedir(), \".abmind\", \"memory\"), \"memory.db\");\n const tables = [\"extracted_memories_fts\", \"content_en_trigram\", \"content_original_trigram\"];\n const rebuilt: string[] = [];\n for (const t of tables) {\n try {\n execSync(`sqlite3 \"${dbPath}\" \"INSERT INTO ${t}(${t}) VALUES('integrity-check')\"`, { stdio: \"pipe\", timeout: 2000 });\n } catch {\n try {\n execSync(`sqlite3 \"${dbPath}\" \"INSERT INTO ${t}(${t}) VALUES('rebuild')\"`, { stdio: \"pipe\", timeout: 5000 });\n rebuilt.push(t);\n } catch { /* table may not exist */ }\n }\n }\n if (rebuilt.length > 0) return { name: \"fts-integrity\", status: \"ok\", latencyMs: Date.now() - start, detail: `rebuilt: ${rebuilt.join(\", \")}` };\n return { name: \"fts-integrity\", status: \"ok\", latencyMs: Date.now() - start };\n } catch (err) {\n return { name: \"fts-integrity\", status: \"failed\", latencyMs: Date.now() - start, detail: err instanceof Error ? err.message : String(err) };\n }\n};\n\nconst probeAbmindCli: ProbeFn = async (_ctx) => {\n const { spawnSync } = await import(\"node:child_process\");\n const start = Date.now();\n const result = spawnSync(\"abmind\", [\"--version\"], { encoding: \"utf-8\", timeout: 3000 });\n if (result.status === 0) {\n const ver = result.stdout?.trim() || \"ok\";\n return { name: \"abmind-cli\", status: \"ok\", latencyMs: Date.now() - start, detail: `v${ver}` };\n }\n return { name: \"abmind-cli\", status: \"failed\", latencyMs: Date.now() - start, detail: \"not on PATH \u2014 run: npm install -g abmind\" };\n};\n\nconst PROBES: Array<{ fn: ProbeFn; timeout: number }> = [\n { fn: probeCoreFiles, timeout: 1000 },\n { fn: probeFtsIntegrity, timeout: 3000 },\n { fn: probeSecretPerms, timeout: 1000 },\n { fn: probeTlsIdentity, timeout: 2000 },\n { fn: probeAbmindCli, timeout: 3000 },\n { fn: probeMemory, timeout: 5000 },\n { fn: probeTelegram, timeout: 5000 },\n { fn: probeDiscord, timeout: 5000 },\n { fn: probeHeartbeat, timeout: 2000 },\n { fn: probeDashboard, timeout: 5000 },\n { fn: probeOllama, timeout: 5000 },\n { fn: probeTransport, timeout: 10000 }, // last \u2014 most expensive\n];\n\nlet lastReport: { report: DoctorReport; generatedAt: number } | null = null;\nconst CACHE_TTL_MS = 60_000;\n\nexport async function getDoctorReport(ctx: DoctorCtx, opts?: { force?: boolean }): Promise<DoctorReport> {\n const now = Date.now();\n if (!opts?.force && lastReport && now - lastReport.generatedAt < CACHE_TTL_MS) {\n return { ...lastReport.report, cached: true, cacheAgeMs: now - lastReport.generatedAt };\n }\n\n const start = Date.now();\n const results = await Promise.all(\n PROBES.map(p => withTimeout(p.fn, p.timeout)(ctx).then(r => {\n // withTimeout may return name=\"unknown\" \u2014 fix it\n if (r.name === \"unknown\") r.name = \"probe\";\n return r;\n }))\n );\n\n // Add boot phases not covered by active probes\n const probedNames = new Set(results.map(r => r.name));\n if (ctx.phaseHealth) {\n for (const [name, h] of ctx.phaseHealth) {\n const short = name.replace(\"phase\", \"\").replace(/([A-Z])/g, \" $1\").trim().toLowerCase();\n if (!probedNames.has(short) && !probedNames.has(short.replace(\" \", \"\"))) {\n results.push({ name: short, status: h.status === \"ok\" ? \"ok\" : h.status === \"skipped\" ? \"skipped\" : \"failed\", latencyMs: 0, detail: h.error ?? (h.status === \"ok\" ? \"boot ok\" : undefined) });\n }\n }\n }\n\n const totalMs = Date.now() - start;\n\n // #440 \u2014 version staleness check\n try {\n const { checkForUpdate } = await import(\"../update-check.js\");\n const { readlinkSync } = await import(\"node:fs\");\n const { join } = await import(\"node:path\");\n const { homedir } = await import(\"node:os\");\n const target = readlinkSync(join(homedir(), \".abtars\", \"current\")).split(\"/\").pop() ?? \"\";\n const dash = target.lastIndexOf(\"-\");\n const version = dash > 0 ? target.slice(0, dash) : \"unknown\";\n const result = checkForUpdate(\"abtars\", version);\n if (result?.updateAvailable) {\n results.push({ name: \"update-available\", status: \"failed\", latencyMs: 0, detail: `update: ${result.current} \u2192 ${result.latest} available` });\n } else if (result) {\n results.push({ name: \"version\", status: \"ok\", latencyMs: 0, detail: `${result.current} (latest)` });\n }\n } catch (err) { logAndSwallow(TAG, \"version check\", err); }\n\n const report: DoctorReport = { results, totalMs, cached: false };\n lastReport = { report, generatedAt: now };\n logInfo(\"doctor\", `Probes complete: ${results.filter(r => r.status === \"ok\").length}/${results.length} ok (${totalMs}ms)`);\n return report;\n}\n\nexport function renderDoctorText(report: DoctorReport): string {\n const icon = (s: ProbeResult[\"status\"]): string => s === \"ok\" ? \"\u2713\" : s === \"failed\" ? \"\u2717\" : \"\u23ED\";\n const lines = report.results.map(r => {\n const detail = r.detail ? ` \u2014 ${r.detail}` : \"\";\n const ms = r.latencyMs > 0 ? ` (${r.latencyMs}ms)` : \"\";\n return ` ${icon(r.status)} ${r.name}${ms}${detail}`;\n });\n const tag = report.cached ? `[cached ${Math.round((report.cacheAgeMs ?? 0) / 1000)}s ago]` : \"[fresh]\";\n return `\uD83E\uDE7A Doctor Report (${(report.totalMs / 1000).toFixed(1)}s) ${tag}\\n${lines.join(\"\\n\")}`;\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,31 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
3
- import {
4
- kanbanCleanup,
5
- kanbanComplete,
6
- kanbanDeliveryFailed,
7
- kanbanEnqueue,
8
- kanbanFail,
9
- kanbanList,
10
- kanbanMarkDelivered,
11
- kanbanPending,
12
- kanbanRunning,
13
- kanbanSetDelivering,
14
- kanbanUpdate
15
- } from "./chunk-YMGX6HNP.js";
16
- import "./chunk-WW5F2DCO.js";
17
- import "./chunk-7K2YZTLD.js";
18
- export {
19
- kanbanCleanup,
20
- kanbanComplete,
21
- kanbanDeliveryFailed,
22
- kanbanEnqueue,
23
- kanbanFail,
24
- kanbanList,
25
- kanbanMarkDelivered,
26
- kanbanPending,
27
- kanbanRunning,
28
- kanbanSetDelivering,
29
- kanbanUpdate
30
- };
31
- //# sourceMappingURL=kanban-board-6Q5E5GEB.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
3
- import {
4
- SessionRegistry,
5
- getRecalledIdsForMessage,
6
- handleInboundMessage,
7
- resetAndPrepare,
8
- resetIdleCompactFlag,
9
- setIdleCompactReset,
10
- startSession
11
- } from "./chunk-N7UG4FID.js";
12
- import "./chunk-NIRYBWUW.js";
13
- import "./chunk-L33WNMCP.js";
14
- import "./chunk-SA6YEFNG.js";
15
- import "./chunk-PKHYCNTT.js";
16
- import "./chunk-HJQZP5CK.js";
17
- import "./chunk-YWZPKBO6.js";
18
- import "./chunk-JAJ3DUQ2.js";
19
- import "./chunk-DO4INSXE.js";
20
- import "./chunk-RTL7HO3N.js";
21
- import "./chunk-SRFEIZQT.js";
22
- import "./chunk-H7RX7UCR.js";
23
- import "./chunk-MZWMYN4O.js";
24
- import "./chunk-3OXQWII3.js";
25
- import "./chunk-CYSGXNBY.js";
26
- import "./chunk-GUTRAMK3.js";
27
- import "./chunk-WW5F2DCO.js";
28
- import "./chunk-7K2YZTLD.js";
29
- export {
30
- SessionRegistry,
31
- getRecalledIdsForMessage,
32
- handleInboundMessage,
33
- resetAndPrepare,
34
- resetIdleCompactFlag,
35
- setIdleCompactReset,
36
- startSession
37
- };
38
- //# sourceMappingURL=message-pipeline-4KL7OWUH.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
3
- import {
4
- SessionRegistry,
5
- getRecalledIdsForMessage,
6
- handleInboundMessage,
7
- resetAndPrepare,
8
- resetIdleCompactFlag,
9
- setIdleCompactReset,
10
- startSession
11
- } from "./chunk-HB54S5OY.js";
12
- import "./chunk-NIRYBWUW.js";
13
- import "./chunk-L33WNMCP.js";
14
- import "./chunk-SA6YEFNG.js";
15
- import "./chunk-PKHYCNTT.js";
16
- import "./chunk-HJQZP5CK.js";
17
- import "./chunk-YWZPKBO6.js";
18
- import "./chunk-JAJ3DUQ2.js";
19
- import "./chunk-DO4INSXE.js";
20
- import "./chunk-RTL7HO3N.js";
21
- import "./chunk-SRFEIZQT.js";
22
- import "./chunk-H7RX7UCR.js";
23
- import "./chunk-MZWMYN4O.js";
24
- import "./chunk-3OXQWII3.js";
25
- import "./chunk-CYSGXNBY.js";
26
- import "./chunk-GUTRAMK3.js";
27
- import "./chunk-WW5F2DCO.js";
28
- import "./chunk-7K2YZTLD.js";
29
- export {
30
- SessionRegistry,
31
- getRecalledIdsForMessage,
32
- handleInboundMessage,
33
- resetAndPrepare,
34
- resetIdleCompactFlag,
35
- setIdleCompactReset,
36
- startSession
37
- };
38
- //# sourceMappingURL=message-pipeline-GFKSHRFU.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
3
- import {
4
- SessionRegistry,
5
- getRecalledIdsForMessage,
6
- handleInboundMessage,
7
- resetAndPrepare,
8
- resetIdleCompactFlag,
9
- setIdleCompactReset,
10
- startSession
11
- } from "./chunk-VY2BUO6L.js";
12
- import "./chunk-NIRYBWUW.js";
13
- import "./chunk-L33WNMCP.js";
14
- import "./chunk-SA6YEFNG.js";
15
- import "./chunk-PKHYCNTT.js";
16
- import "./chunk-HJQZP5CK.js";
17
- import "./chunk-YWZPKBO6.js";
18
- import "./chunk-JAJ3DUQ2.js";
19
- import "./chunk-DO4INSXE.js";
20
- import "./chunk-RTL7HO3N.js";
21
- import "./chunk-SRFEIZQT.js";
22
- import "./chunk-H7RX7UCR.js";
23
- import "./chunk-MZWMYN4O.js";
24
- import "./chunk-3OXQWII3.js";
25
- import "./chunk-CYSGXNBY.js";
26
- import "./chunk-GUTRAMK3.js";
27
- import "./chunk-WW5F2DCO.js";
28
- import "./chunk-7K2YZTLD.js";
29
- export {
30
- SessionRegistry,
31
- getRecalledIdsForMessage,
32
- handleInboundMessage,
33
- resetAndPrepare,
34
- resetIdleCompactFlag,
35
- setIdleCompactReset,
36
- startSession
37
- };
38
- //# sourceMappingURL=message-pipeline-TGI2WJJM.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
3
- import {
4
- buildTransport,
5
- phaseTransport,
6
- rebuildTransport
7
- } from "./chunk-3IPMKYYH.js";
8
- import "./chunk-7WFE2JI5.js";
9
- import "./chunk-PKHYCNTT.js";
10
- import "./chunk-RTL7HO3N.js";
11
- import "./chunk-SRFEIZQT.js";
12
- import "./chunk-MZWMYN4O.js";
13
- import "./chunk-3OXQWII3.js";
14
- import "./chunk-CYSGXNBY.js";
15
- import "./chunk-GUTRAMK3.js";
16
- import "./chunk-WW5F2DCO.js";
17
- import "./chunk-7K2YZTLD.js";
18
- export {
19
- buildTransport,
20
- phaseTransport,
21
- rebuildTransport
22
- };
23
- //# sourceMappingURL=phase-transport-KXFZ5BVF.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
3
- import {
4
- SubagentRuntime
5
- } from "./chunk-PUDGA4RR.js";
6
- import "./chunk-CYSGXNBY.js";
7
- import "./chunk-GUTRAMK3.js";
8
- import "./chunk-WW5F2DCO.js";
9
- import "./chunk-7K2YZTLD.js";
10
- export {
11
- SubagentRuntime
12
- };
13
- //# sourceMappingURL=subagent-runtime-VKTX6Q2M.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/components/system-status.ts"],
4
- "sourcesContent": ["/**\n * system-status.ts \u2014 Single source of truth for bridge status.\n * One collector, many renderers. Used by /status (text), dashboard (HTML), future API (JSON).\n */\n\nimport { logAndSwallow } from \"./log-and-swallow.js\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { ServiceState } from \"./service-registry.js\";\n\nconst TAG = \"system_status\";\n\nexport interface SubsystemHealth {\n name: string;\n status: \"ok\" | \"failed\" | \"skipped\" | \"stopped\" | \"retrying\";\n detail?: string;\n}\n\nexport interface SystemStatus {\n version: string;\n commit: string;\n model: string;\n transportType: string;\n transportProvider: string;\n transportReady: boolean;\n uptimeMs: number;\n contextPercent: number;\n sleepStatus: string | null;\n subsystems: SubsystemHealth[];\n tasks: { recurring: number; pending: number; paused: number };\n lastBackup: string | null;\n}\n\nexport interface StatusContext {\n phaseHealth: Map<string, { status: \"ok\" | \"failed\" | \"skipped\"; error?: string }>;\n registry: { getStates(): Record<string, ServiceState> };\n transport: { isReady: boolean } | null;\n startedAt: number;\n bridgeLockPath: string;\n heartbeat: { intervalMs: number } | null;\n}\n\nexport async function getSystemStatus(ctx: StatusContext): Promise<SystemStatus> {\n // Version + commit from manifest.json (single source of truth)\n const { getDeployedVersion } = await import(\"../paths.js\");\n const deployed = getDeployedVersion();\n const version = deployed.version;\n const commit = deployed.commit || \"?\";\n\n // Model + transport\n let model = \"unknown\";\n let transportType = \"unknown\";\n let transportProvider = \"unknown\";\n try {\n const { loadTransport, resolveAgent } = await import(\"./transport-config.js\");\n const tc = loadTransport();\n const prof = tc ? resolveAgent(\"professor\", tc) : null;\n if (prof) {\n model = prof.model;\n transportType = (prof.provider.transport ?? \"acp\").toUpperCase();\n transportProvider = prof.providerName ?? \"unknown\";\n }\n } catch (err) { logAndSwallow(\"system_status\", \"op\", err); }\n\n // Subsystem health: merge phaseHealth + ServiceRegistry live state\n const serviceStates = ctx.registry.getStates();\n const subsystems: SubsystemHealth[] = [];\n\n for (const [name, health] of ctx.phaseHealth) {\n const entry: SubsystemHealth = { name, status: health.status };\n\n // For platform services, override with live ServiceRegistry state\n const svcName = phaseToService(name);\n if (svcName && serviceStates[svcName]) {\n const svc = serviceStates[svcName] as ServiceState;\n if (health.status === \"ok\" && !svc.running) {\n entry.status = svc.retrying ? \"retrying\" : \"stopped\";\n }\n if (svc.retrying) {\n entry.detail = `retry #${svc.retrying.attempt}`;\n }\n }\n\n // Add contextual detail for specific phases\n if (name === \"phaseTransport\" && health.status === \"ok\" && ctx.transport) {\n entry.detail = `${transportType} (${transportProvider}), ${ctx.transport.isReady ? \"ready\" : \"not ready\"}`;\n }\n if (name === \"phaseHeartbeat\" && health.status === \"ok\" && ctx.heartbeat) {\n try {\n const lock = JSON.parse(readFileSync(ctx.bridgeLockPath, \"utf-8\"));\n const ago = Math.round((Date.now() - (lock.lastHeartbeat || 0)) / 60000);\n entry.detail = `${Math.round(ctx.heartbeat.intervalMs / 1000)}s, last tick ${ago}m ago`;\n } catch (err) { logAndSwallow(\"system_status\", \"op\", err); }\n }\n if (name === \"phaseDashboard\" && health.status === \"ok\") {\n entry.detail = `:${process.env[\"WEB_PORT\"] || \"3000\"}`;\n }\n\n subsystems.push(entry);\n }\n\n // Tasks\n let tasks = { recurring: 0, pending: 0, paused: 0 };\n try {\n const { readEntries } = await import(\"./tasks/task-store.js\");\n const entries = readEntries();\n tasks = {\n recurring: entries.filter((e: any) => e.schedule && !e.paused).length,\n pending: entries.filter((e: any) => !e.fired && !e.schedule).length,\n paused: entries.filter((e: any) => e.paused).length,\n };\n } catch (err) { logAndSwallow(\"system_status\", \"op\", err); }\n\n // Last backup\n let lastBackup: string | null = null;\n try {\n const { readdirSync } = await import(\"node:fs\");\n const bd = join(homedir(), \".backup-abtars\");\n const bk = readdirSync(bd).filter((f: string) => f.startsWith(\"abtars-\")).sort();\n if (bk.length > 0) lastBackup = bk[bk.length - 1] ?? null;\n } catch (err) { logAndSwallow(\"system_status\", \"op\", err); }\n\n // Context percent from bridge.lock\n let contextPercent = -1;\n try {\n const lock = JSON.parse(readFileSync(ctx.bridgeLockPath, \"utf-8\"));\n if (typeof lock.contextPercent === \"number\") contextPercent = lock.contextPercent;\n } catch { /* ignore */ }\n\n // Sleep status\n let sleepStatus: string | null = null;\n try {\n const lock = JSON.parse(readFileSync(ctx.bridgeLockPath, \"utf-8\"));\n sleepStatus = lock.sleepStatus ?? null;\n } catch { /* ignore */ }\n\n return {\n version,\n commit,\n model,\n transportType,\n transportProvider,\n transportReady: ctx.transport?.isReady ?? false,\n uptimeMs: Date.now() - ctx.startedAt,\n contextPercent,\n sleepStatus,\n subsystems,\n tasks,\n lastBackup,\n };\n}\n\n/** Map phase names to ServiceRegistry service names (for live state merge). */\nfunction phaseToService(phaseName: string): string | null {\n switch (phaseName) {\n case \"phasePlatforms\": return null; // platforms registers telegram + discord separately\n case \"phaseDashboard\": return null;\n case \"phaseAgentApi\": return \"agent-api\";\n default: return null;\n }\n}\n\n/** Render SystemStatus as plain text for Telegram/Discord /status command. */\nexport function renderStatusText(status: SystemStatus): string {\n const uptime = formatUptime(status.uptimeMs);\n const name = process.env[\"AGENT_NAME\"] ?? process.env[\"BOT_NAME\"] ?? \"abtars\";\n const lines: string[] = [\n `\uD83D\uDE0A ${name} \u2014 online`,\n ` PID ${process.pid} (up ${uptime})`,\n ];\n\n // Watchdog\n try {\n const { execFileSync } = require(\"node:child_process\") as typeof import(\"node:child_process\");\n const wdPid = execFileSync(\"pgrep\", [\"-f\", \"watchdog.sh\"], { encoding: \"utf-8\", timeout: 2000 }).trim().split(\"\\n\")[0];\n if (wdPid) lines.push(` Watchdog: PID ${wdPid} (bash)`);\n else lines.push(\" Watchdog: not running\");\n } catch { lines.push(\" Watchdog: not detected\"); }\n\n // Platforms\n const platforms = status.subsystems.find(s => s.name === \"phasePlatforms\");\n if (platforms?.detail) lines.push(` Platforms: ${platforms.detail}`);\n\n // Model + context\n lines.push(` Model: ${status.model.split(\"/\").pop() ?? status.model}`);\n if (status.contextPercent >= 0) lines.push(` Context: ${status.contextPercent}%`);\n\n // Last prompt\n try {\n const lock = JSON.parse(readFileSync(join(homedir(), \".abtars\", \"bridge.lock\"), \"utf-8\"));\n if (lock.lastPromptAt) {\n const ago = Math.round((Date.now() - lock.lastPromptAt) / 1000);\n lines.push(` Last prompt: ${ago < 60 ? `${ago}s ago` : `${Math.round(ago / 60)}m ago`}`);\n }\n } catch { /* no lock */ }\n\n // Sleep\n if (status.sleepStatus) lines.push(` Sleep: ${status.sleepStatus}`);\n\n // Skills\n try {\n const { getSkillCache } = require(\"../capabilities/hotskills/index.js\") as typeof import(\"../capabilities/hotskills/index.js\");\n const skills = getSkillCache();\n if (skills.length > 0) {\n const active = skills.filter(s => !s.skipped).length;\n lines.push(` Skills: ${active} active`);\n }\n } catch { /* hotskills not loaded */ }\n\n lines.push(\"\", \"\uD83C\uDFE5 Subsystems:\");\n\n for (const s of status.subsystems) {\n const icon = s.status === \"ok\" ? \"\u2713\" : s.status === \"skipped\" ? \"\u25CB\" : \"\u2717\";\n const label = s.name.replace(\"phase\", \"\").replace(/([A-Z])/g, \" $1\").trim().toLowerCase();\n const detail = s.detail ? ` \u2014 ${s.detail}` : \"\";\n lines.push(` ${icon} ${label}${detail}`);\n }\n\n lines.push(\"\");\n lines.push(`\u23F0 Tasks: ${status.tasks.recurring} recurring, ${status.tasks.pending} pending${status.tasks.paused ? `, ${status.tasks.paused} paused` : \"\"}`);\n if (status.lastBackup) lines.push(`\uD83D\uDCBE Last backup: ${status.lastBackup}`);\n\n return lines.join(\"\\n\");\n}\n\nfunction formatUptime(ms: number): string {\n const s = Math.floor(ms / 1000);\n const m = Math.floor(s / 60) % 60;\n const h = Math.floor(s / 3600) % 24;\n const d = Math.floor(s / 86400);\n if (d > 0) return `${d}d ${h}h ${m}m`;\n if (h > 0) return `${h}h ${m}m`;\n return `${m}m`;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAKA;AACA,SAAS,oBAAgC;AACzC,SAAS,YAAY;AACrB,SAAS,eAAe;AAmCxB,eAAsB,gBAAgB,KAA2C;AAE/E,QAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,qBAAa;AACzD,QAAM,WAAW,mBAAmB;AACpC,QAAM,UAAU,SAAS;AACzB,QAAM,SAAS,SAAS,UAAU;AAGlC,MAAI,QAAQ;AACZ,MAAI,gBAAgB;AACpB,MAAI,oBAAoB;AACxB,MAAI;AACF,UAAM,EAAE,eAAe,aAAa,IAAI,MAAM,OAAO,gCAAuB;AAC5E,UAAM,KAAK,cAAc;AACzB,UAAM,OAAO,KAAK,aAAa,aAAa,EAAE,IAAI;AAClD,QAAI,MAAM;AACR,cAAQ,KAAK;AACb,uBAAiB,KAAK,SAAS,aAAa,OAAO,YAAY;AAC/D,0BAAoB,KAAK,gBAAgB;AAAA,IAC3C;AAAA,EACF,SAAS,KAAK;AAAE,kBAAc,iBAAiB,MAAM,GAAG;AAAA,EAAG;AAG3D,QAAM,gBAAgB,IAAI,SAAS,UAAU;AAC7C,QAAM,aAAgC,CAAC;AAEvC,aAAW,CAAC,MAAM,MAAM,KAAK,IAAI,aAAa;AAC5C,UAAM,QAAyB,EAAE,MAAM,QAAQ,OAAO,OAAO;AAG7D,UAAM,UAAU,eAAe,IAAI;AACnC,QAAI,WAAW,cAAc,OAAO,GAAG;AACrC,YAAM,MAAM,cAAc,OAAO;AACjC,UAAI,OAAO,WAAW,QAAQ,CAAC,IAAI,SAAS;AAC1C,cAAM,SAAS,IAAI,WAAW,aAAa;AAAA,MAC7C;AACA,UAAI,IAAI,UAAU;AAChB,cAAM,SAAS,UAAU,IAAI,SAAS,OAAO;AAAA,MAC/C;AAAA,IACF;AAGA,QAAI,SAAS,oBAAoB,OAAO,WAAW,QAAQ,IAAI,WAAW;AACxE,YAAM,SAAS,GAAG,aAAa,KAAK,iBAAiB,MAAM,IAAI,UAAU,UAAU,UAAU,WAAW;AAAA,IAC1G;AACA,QAAI,SAAS,oBAAoB,OAAO,WAAW,QAAQ,IAAI,WAAW;AACxE,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,aAAa,IAAI,gBAAgB,OAAO,CAAC;AACjE,cAAM,MAAM,KAAK,OAAO,KAAK,IAAI,KAAK,KAAK,iBAAiB,MAAM,GAAK;AACvE,cAAM,SAAS,GAAG,KAAK,MAAM,IAAI,UAAU,aAAa,GAAI,CAAC,gBAAgB,GAAG;AAAA,MAClF,SAAS,KAAK;AAAE,sBAAc,iBAAiB,MAAM,GAAG;AAAA,MAAG;AAAA,IAC7D;AACA,QAAI,SAAS,oBAAoB,OAAO,WAAW,MAAM;AACvD,YAAM,SAAS,IAAI,QAAQ,IAAI,UAAU,KAAK,MAAM;AAAA,IACtD;AAEA,eAAW,KAAK,KAAK;AAAA,EACvB;AAGA,MAAI,QAAQ,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,EAAE;AAClD,MAAI;AACF,UAAM,EAAE,YAAY,IAAI,MAAM,OAAO,0BAAuB;AAC5D,UAAM,UAAU,YAAY;AAC5B,YAAQ;AAAA,MACN,WAAW,QAAQ,OAAO,CAAC,MAAW,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;AAAA,MAC/D,SAAS,QAAQ,OAAO,CAAC,MAAW,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE;AAAA,MAC7D,QAAQ,QAAQ,OAAO,CAAC,MAAW,EAAE,MAAM,EAAE;AAAA,IAC/C;AAAA,EACF,SAAS,KAAK;AAAE,kBAAc,iBAAiB,MAAM,GAAG;AAAA,EAAG;AAG3D,MAAI,aAA4B;AAChC,MAAI;AACF,UAAM,EAAE,YAAY,IAAI,MAAM,OAAO,SAAS;AAC9C,UAAM,KAAK,KAAK,QAAQ,GAAG,gBAAgB;AAC3C,UAAM,KAAK,YAAY,EAAE,EAAE,OAAO,CAAC,MAAc,EAAE,WAAW,SAAS,CAAC,EAAE,KAAK;AAC/E,QAAI,GAAG,SAAS,EAAG,cAAa,GAAG,GAAG,SAAS,CAAC,KAAK;AAAA,EACvD,SAAS,KAAK;AAAE,kBAAc,iBAAiB,MAAM,GAAG;AAAA,EAAG;AAG3D,MAAI,iBAAiB;AACrB,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,aAAa,IAAI,gBAAgB,OAAO,CAAC;AACjE,QAAI,OAAO,KAAK,mBAAmB,SAAU,kBAAiB,KAAK;AAAA,EACrE,QAAQ;AAAA,EAAe;AAGvB,MAAI,cAA6B;AACjC,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,aAAa,IAAI,gBAAgB,OAAO,CAAC;AACjE,kBAAc,KAAK,eAAe;AAAA,EACpC,QAAQ;AAAA,EAAe;AAEvB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,IAAI,WAAW,WAAW;AAAA,IAC1C,UAAU,KAAK,IAAI,IAAI,IAAI;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAGA,SAAS,eAAe,WAAkC;AACxD,UAAQ,WAAW;AAAA,IACjB,KAAK;AAAkB,aAAO;AAAA;AAAA,IAC9B,KAAK;AAAkB,aAAO;AAAA,IAC9B,KAAK;AAAiB,aAAO;AAAA,IAC7B;AAAS,aAAO;AAAA,EAClB;AACF;AAGO,SAAS,iBAAiB,QAA8B;AAC7D,QAAM,SAAS,aAAa,OAAO,QAAQ;AAC3C,QAAM,OAAO,QAAQ,IAAI,YAAY,KAAK,QAAQ,IAAI,UAAU,KAAK;AACrE,QAAM,QAAkB;AAAA,IACtB,aAAM,IAAI;AAAA,IACV,SAAS,QAAQ,GAAG,QAAQ,MAAM;AAAA,EACpC;AAGA,MAAI;AACF,UAAM,EAAE,aAAa,IAAI,UAAQ,oBAAoB;AACrD,UAAM,QAAQ,aAAa,SAAS,CAAC,MAAM,aAAa,GAAG,EAAE,UAAU,SAAS,SAAS,IAAK,CAAC,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC;AACrH,QAAI,MAAO,OAAM,KAAK,mBAAmB,KAAK,SAAS;AAAA,QAClD,OAAM,KAAK,yBAAyB;AAAA,EAC3C,QAAQ;AAAE,UAAM,KAAK,0BAA0B;AAAA,EAAG;AAGlD,QAAM,YAAY,OAAO,WAAW,KAAK,OAAK,EAAE,SAAS,gBAAgB;AACzE,MAAI,WAAW,OAAQ,OAAM,KAAK,gBAAgB,UAAU,MAAM,EAAE;AAGpE,QAAM,KAAK,YAAY,OAAO,MAAM,MAAM,GAAG,EAAE,IAAI,KAAK,OAAO,KAAK,EAAE;AACtE,MAAI,OAAO,kBAAkB,EAAG,OAAM,KAAK,cAAc,OAAO,cAAc,GAAG;AAGjF,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,aAAa,KAAK,QAAQ,GAAG,WAAW,aAAa,GAAG,OAAO,CAAC;AACxF,QAAI,KAAK,cAAc;AACrB,YAAM,MAAM,KAAK,OAAO,KAAK,IAAI,IAAI,KAAK,gBAAgB,GAAI;AAC9D,YAAM,KAAK,kBAAkB,MAAM,KAAK,GAAG,GAAG,UAAU,GAAG,KAAK,MAAM,MAAM,EAAE,CAAC,OAAO,EAAE;AAAA,IAC1F;AAAA,EACF,QAAQ;AAAA,EAAgB;AAGxB,MAAI,OAAO,YAAa,OAAM,KAAK,YAAY,OAAO,WAAW,EAAE;AAGnE,MAAI;AACF,UAAM,EAAE,cAAc,IAAI;AAC1B,UAAM,SAAS,cAAc;AAC7B,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,SAAS,OAAO,OAAO,OAAK,CAAC,EAAE,OAAO,EAAE;AAC9C,YAAM,KAAK,aAAa,MAAM,SAAS;AAAA,IACzC;AAAA,EACF,QAAQ;AAAA,EAA6B;AAErC,QAAM,KAAK,IAAI,uBAAgB;AAE/B,aAAW,KAAK,OAAO,YAAY;AACjC,UAAM,OAAO,EAAE,WAAW,OAAO,WAAM,EAAE,WAAW,YAAY,WAAM;AACtE,UAAM,QAAQ,EAAE,KAAK,QAAQ,SAAS,EAAE,EAAE,QAAQ,YAAY,KAAK,EAAE,KAAK,EAAE,YAAY;AACxF,UAAM,SAAS,EAAE,SAAS,WAAM,EAAE,MAAM,KAAK;AAC7C,UAAM,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,MAAM,EAAE;AAAA,EAC1C;AAEA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,iBAAY,OAAO,MAAM,SAAS,eAAe,OAAO,MAAM,OAAO,WAAW,OAAO,MAAM,SAAS,KAAK,OAAO,MAAM,MAAM,YAAY,EAAE,EAAE;AACzJ,MAAI,OAAO,WAAY,OAAM,KAAK,0BAAmB,OAAO,UAAU,EAAE;AAExE,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,aAAa,IAAoB;AACxC,QAAM,IAAI,KAAK,MAAM,KAAK,GAAI;AAC9B,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE,IAAI;AAC/B,QAAM,IAAI,KAAK,MAAM,IAAI,IAAI,IAAI;AACjC,QAAM,IAAI,KAAK,MAAM,IAAI,KAAK;AAC9B,MAAI,IAAI,EAAG,QAAO,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAClC,MAAI,IAAI,EAAG,QAAO,GAAG,CAAC,KAAK,CAAC;AAC5B,SAAO,GAAG,CAAC;AACb;",
6
- "names": []
7
- }