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
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  createAgentTransport,
5
5
  createSubagentTransport
6
- } from "./chunk-7WFE2JI5.js";
6
+ } from "./chunk-7B3GK5JQ.js";
7
7
  import "./chunk-PKHYCNTT.js";
8
8
  import "./chunk-RTL7HO3N.js";
9
9
  import "./chunk-MZWMYN4O.js";
@@ -16,4 +16,4 @@ export {
16
16
  createAgentTransport,
17
17
  createSubagentTransport
18
18
  };
19
- //# sourceMappingURL=agent-registry-PIS5XJHX.js.map
19
+ //# sourceMappingURL=agent-registry-ABPFQXNL.js.map
@@ -151,7 +151,7 @@ var SubagentRuntime = class {
151
151
  return true;
152
152
  }
153
153
  async createAgent(agent, sessionType) {
154
- const { createSubagentTransport } = await import("./agent-registry-PIS5XJHX.js");
154
+ const { createSubagentTransport } = await import("./agent-registry-ABPFQXNL.js");
155
155
  const role = AGENT_TO_ROLE[agent];
156
156
  const mainModel = this._mainTransport && "currentModel" in this._mainTransport ? this._mainTransport.currentModel : void 0;
157
157
  const { transport, model } = await createSubagentTransport(role, this._registry ?? void 0, mainModel);
@@ -180,4 +180,4 @@ var AGENT_TO_ROLE = {
180
180
  export {
181
181
  SubagentRuntime
182
182
  };
183
- //# sourceMappingURL=chunk-QSC6QZ44.js.map
183
+ //# sourceMappingURL=chunk-2SFN2VYD.js.map
@@ -28,6 +28,7 @@ var BOT_COMMANDS = [
28
28
  { name: "sleep", description: "Sleep status / resume / now" },
29
29
  { name: "whoami", description: "Your user info & clearance" },
30
30
  { name: "reasoning", description: "Reasoning effort & thinking display" },
31
+ { name: "continue", description: "Nudge model to continue after failure" },
31
32
  { name: "kanban", description: "Kanban board" },
32
33
  { name: "help", description: "Show all commands" }
33
34
  ];
@@ -255,4 +256,4 @@ export {
255
256
  emojiToScore,
256
257
  emojiToTag
257
258
  };
258
- //# sourceMappingURL=chunk-BBTQKKDO.js.map
259
+ //# sourceMappingURL=chunk-2W6JIHZ5.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/components/command-registry.ts", "../src/components/security-gate.ts", "../src/components/response-formatter.ts", "../src/utils/emoji-score.ts"],
4
+ "sourcesContent": ["/**\n * command-registry.ts \u2014 Shared bot command definitions for all platforms.\n * Both Telegram (setMyCommands) and Discord (application commands) import from here.\n */\n\nexport interface BotCommand {\n readonly name: string;\n readonly description: string;\n}\n\n/** All registered bot commands. Discord requires: name \u226432 chars lowercase, description \u2264100 chars. */\nexport const BOT_COMMANDS: readonly BotCommand[] = [\n { name: \"reset\", description: \"Fresh session + exit coding\" },\n { name: \"session\", description: \"Session management\" },\n { name: \"compact\", description: \"Compact context window\" },\n { name: \"status\", description: \"Operational health (PID, platforms, context)\" },\n { name: \"software\", description: \"Version, deploy info, rollback\" },\n { name: \"model\", description: \"Model configuration & switching\" },\n { name: \"doctor\", description: \"Deep healthcheck (probes all subsystems)\" },\n { name: \"mcp\", description: \"MCP server status\" },\n { name: \"hooks\", description: \"List configured hooks\" },\n { name: \"stop\", description: \"Stop current response\" },\n { name: \"wait\", description: \"Inject message mid-run (non-interrupting)\" },\n { name: \"update\", description: \"Pull & deploy latest code\" },\n { name: \"emergency\", description: \"Activate paid hailMary model\" },\n { name: \"heartbeat\", description: \"Heartbeat diagnostics\" },\n { name: \"memory\", description: \"Memory stats\" },\n { name: \"skills\", description: \"List active skills\" },\n { name: \"skill\", description: \"Reload skills catalog\" },\n { name: \"tasks\", description: \"Scheduled tasks\" },\n { name: \"facts\", description: \"Core knowledge\" },\n { name: \"nlm\", description: \"Knowledge base\" },\n { name: \"restart\", description: \"Restart bridge\" },\n { name: \"wakeup\", description: \"Wake Mac from sleep\" },\n { name: \"sleep\", description: \"Sleep status / resume / now\" },\n { name: \"whoami\", description: \"Your user info & clearance\" },\n { name: \"reasoning\", description: \"Reasoning effort & thinking display\" },\n { name: \"continue\", description: \"Nudge model to continue after failure\" },\n { name: \"kanban\", description: \"Kanban board\" },\n { name: \"help\", description: \"Show all commands\" },\n];\n", "/**\n * Fail-closed security gate that authorizes messages against the user registry.\n * Unauthorized messages are silently dropped \u2014 no response, no side effects.\n * Per-user channel gating via UserEntry.allowedChats.\n */\nimport type { UserEntry, UserRegistry } from \"./user-registry.js\";\n\nexport interface AuthResult {\n authorized: boolean;\n user?: UserEntry;\n}\n\nexport class SecurityGate {\n private readonly registry: UserRegistry;\n\n constructor(registry: UserRegistry) {\n if (registry.users.length === 0) {\n throw new Error(\"SecurityGate requires at least one user in registry\");\n }\n this.registry = registry;\n }\n\n /** Authorize a platform user. Checks allowedChats if set. */\n authorize(platformUserId: string, platform: string, channelId?: string): AuthResult {\n const key = `${platform}:${platformUserId}`;\n const user = this.registry.byPlatformId.get(key);\n if (!user) return { authorized: false };\n if (!this.chatAllowed(user, channelId)) return { authorized: false };\n return { authorized: true, user };\n }\n\n /** Authorize by platform user ID string (tries both platforms). */\n authorizeById(userId: string, channelId?: string): boolean {\n const tg = this.registry.byPlatformId.get(`telegram:${userId}`);\n const dc = this.registry.byPlatformId.get(`discord:${userId}`);\n const user = tg ?? dc;\n if (!user) return false;\n return this.chatAllowed(user, channelId);\n }\n\n private chatAllowed(user: UserEntry, channelId?: string): boolean {\n if (!user.allowedChats || user.allowedChats.length === 0) return true;\n if (!channelId) return true;\n return user.allowedChats.includes(channelId);\n }\n}\n", "import type { Platform } from \"../types/index.js\";\n\nconst TELEGRAM_MAX_LENGTH = 4096;\nconst DISCORD_MAX_LENGTH = 2000;\n\n/** Characters that must be escaped in Telegram MarkdownV2. */\nconst MARKDOWN_V2_ESCAPE = /([_*\\[\\]()~`>#+\\-=|{}.!\\\\])/g;\n\n/**\n * Collects streaming ACP response chunks and formats them\n * for Telegram delivery (chunking, Markdown conversion).\n */\nexport class ResponseFormatter {\n private buffers = new Map<string, string[]>();\n\n /** Accumulate a chunk for a session. */\n collectChunk(sessionId: string, chunk: string): void {\n const existing = this.buffers.get(sessionId);\n if (existing) {\n existing.push(chunk);\n } else {\n this.buffers.set(sessionId, [chunk]);\n }\n }\n\n /** Flush accumulated chunks for a session, returning Telegram-ready messages. */\n flush(sessionId: string): string[] {\n const chunks = this.buffers.get(sessionId);\n this.buffers.delete(sessionId);\n if (!chunks || chunks.length === 0) return [];\n const full = chunks.join(\"\");\n return this.chunkText(full);\n }\n\n /** Split text into chunks that fit Telegram's 4096-char limit. */\n chunkText(text: string): string[] {\n if (text.length <= TELEGRAM_MAX_LENGTH) {\n return [text];\n }\n\n const result: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= TELEGRAM_MAX_LENGTH) {\n result.push(remaining);\n break;\n }\n\n // Try to split at paragraph boundary\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", TELEGRAM_MAX_LENGTH);\n if (splitAt <= 0) {\n // Try single newline\n splitAt = remaining.lastIndexOf(\"\\n\", TELEGRAM_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n // Try space\n splitAt = remaining.lastIndexOf(\" \", TELEGRAM_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n // Hard split\n splitAt = TELEGRAM_MAX_LENGTH;\n }\n\n result.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return result;\n }\n\n /** Escape text for Telegram MarkdownV2 parse mode. */\n toTelegramMarkdown(markdown: string): string {\n // Preserve code blocks \u2014 don't escape inside them\n const parts = markdown.split(/(```[\\s\\S]*?```|`[^`]+`)/);\n return parts\n .map((part, i) => {\n // Odd indices are code blocks/inline code \u2014 leave as-is\n if (i % 2 === 1) return part;\n return part.replace(MARKDOWN_V2_ESCAPE, \"\\\\$1\");\n })\n .join(\"\");\n }\n\n /** Split text into chunks for Discord's 2000-char limit.\n * Respects paragraph and code block boundaries \u2014 never splits inside a fenced code block. */\n chunkTextForDiscord(text: string): string[] {\n if (text.length <= DISCORD_MAX_LENGTH) {\n return [text];\n }\n\n const result: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= DISCORD_MAX_LENGTH) {\n result.push(remaining);\n break;\n }\n\n // Check if there's an open code block in the window we're about to cut\n const window = remaining.slice(0, DISCORD_MAX_LENGTH);\n const fenceMatches = window.match(/```/g);\n const hasOpenCodeBlock = fenceMatches != null && fenceMatches.length % 2 !== 0;\n\n if (hasOpenCodeBlock) {\n // Find the start of the open code block (last unmatched ```)\n const lastFenceIdx = window.lastIndexOf(\"```\");\n // Try to split before the code block at a paragraph boundary\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", lastFenceIdx);\n if (splitAt <= 0) {\n splitAt = remaining.lastIndexOf(\"\\n\", lastFenceIdx);\n }\n if (splitAt <= 0) {\n // Can't avoid splitting inside the code block \u2014 close and reopen\n splitAt = remaining.lastIndexOf(\"\\n\", DISCORD_MAX_LENGTH - 4); // leave room for closing ```\n if (splitAt <= 0) {\n splitAt = DISCORD_MAX_LENGTH - 4;\n }\n // Find the code fence language specifier for reopening\n const fenceStart = remaining.lastIndexOf(\"```\", splitAt);\n const fenceLine = remaining.slice(fenceStart, remaining.indexOf(\"\\n\", fenceStart));\n result.push(remaining.slice(0, splitAt) + \"\\n```\");\n remaining = fenceLine + \"\\n\" + remaining.slice(splitAt).trimStart();\n continue;\n }\n result.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n continue;\n }\n\n // No open code block \u2014 split normally at paragraph/line boundaries\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", DISCORD_MAX_LENGTH);\n if (splitAt <= 0) {\n splitAt = remaining.lastIndexOf(\"\\n\", DISCORD_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n splitAt = remaining.lastIndexOf(\" \", DISCORD_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n splitAt = DISCORD_MAX_LENGTH;\n }\n\n result.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return result;\n }\n\n /** Split text for the appropriate platform. */\n chunkForPlatform(text: string, platform: Platform): string[] {\n if (platform === \"discord\") {\n return this.chunkTextForDiscord(text);\n }\n return this.chunkText(text);\n }\n\n /** Convert standard Markdown to Discord-compatible Markdown (mostly passthrough). */\n toDiscordMarkdown(text: string): string {\n return text;\n }\n\n /** Format a tool status update for the user. */\n formatToolStatus(toolName: string, status: \"start\" | \"done\" | \"error\"): string {\n switch (status) {\n case \"start\":\n return `\uD83D\uDD27 ${toolName}...`;\n case \"done\":\n return `\u2705 ${toolName}`;\n case \"error\":\n return `\u274C ${toolName} failed`;\n }\n }\n}\n", "/** Inline emoji-to-score map (avoids hard dep on abmind for adapters). */\nconst EMOJI_SCORES: Record<string, number> = {\n \"\u2764\uFE0F\": 4, \"\uD83D\uDD25\": 4, \"\uD83C\uDF89\": 3, \"\uD83D\uDC4F\": 4, \"\u2764\": 4,\n \"\uD83D\uDC4D\": 3, \"\uD83D\uDE02\": 3, \"\uD83E\uDD29\": 4, \"\uD83D\uDCAF\": 3, \"\u26A1\": 3,\n \"\uD83D\uDE0A\": 2, \"\uD83D\uDE4F\": 2, \"\uD83E\uDD14\": 1, \"\uD83D\uDE2E\": 1,\n \"\uD83D\uDC4E\": -3, \"\uD83D\uDE22\": -3, \"\uD83D\uDE21\": -4, \"\uD83E\uDD2E\": -4, \"\uD83D\uDCA9\": -5,\n};\n\nexport function emojiToScore(emoji: string): number {\n return EMOJI_SCORES[emoji] ?? 1;\n}\n\nconst EMOJI_TAGS: Record<string, string> = {\n \"\u2764\uFE0F\": \"love\", \"\u2764\": \"love\", \"\uD83D\uDD25\": \"excitement\", \"\uD83C\uDF89\": \"joy\",\n \"\uD83D\uDC4F\": \"pride\", \"\uD83D\uDC4D\": \"gratitude\", \"\uD83D\uDE02\": \"humor\", \"\uD83E\uDD29\": \"excitement\",\n \"\uD83D\uDCAF\": \"conviction\", \"\u26A1\": \"determination\", \"\uD83D\uDE0A\": \"joy\", \"\uD83D\uDE4F\": \"gratitude\",\n \"\uD83E\uDD14\": \"curiosity\", \"\uD83D\uDE2E\": \"surprise\",\n \"\uD83D\uDC4E\": \"frustration\", \"\uD83D\uDE22\": \"grief\", \"\uD83D\uDE21\": \"anger\", \"\uD83E\uDD2E\": \"anger\", \"\uD83D\uDCA9\": \"frustration\",\n};\n\nexport function emojiToTag(emoji: string): string {\n return EMOJI_TAGS[emoji] ?? \"gratitude\";\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["splitAt"]
7
+ }
@@ -2,7 +2,7 @@
2
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
3
  import {
4
4
  createAgentTransport
5
- } from "./chunk-7WFE2JI5.js";
5
+ } from "./chunk-7B3GK5JQ.js";
6
6
  import {
7
7
  loadUsers
8
8
  } from "./chunk-SRFEIZQT.js";
@@ -437,11 +437,24 @@ async function phaseTransport(ctx) {
437
437
  return "ran";
438
438
  }
439
439
  async function buildTransport(ctx) {
440
- const { config, memoryConfig } = ctx;
440
+ const { config } = ctx;
441
441
  let transport;
442
442
  const { resolveAgent, getEnvFallback, loadTransport, resolveHailMary, clearTransportCache, validateProviderReady } = await import("./transport-config-JIKHB7GT.js");
443
+ const { existsSync, renameSync } = await import("node:fs");
444
+ const { join: pathJoin } = await import("node:path");
443
445
  clearTransportCache();
444
- const tc = loadTransport();
446
+ let tc = loadTransport();
447
+ if (!tc) {
448
+ const configDir = pathJoin(getEnv().abtarsHome, "config");
449
+ const primary = pathJoin(configDir, "transport.json");
450
+ const old = pathJoin(configDir, "transport.old.json");
451
+ if (existsSync(old)) {
452
+ logDebug("main", "transport.json missing/corrupt \u2014 recovering from transport.old.json");
453
+ renameSync(old, primary);
454
+ clearTransportCache();
455
+ tc = loadTransport();
456
+ }
457
+ }
445
458
  const prof = tc ? resolveAgent("professor", tc) : null;
446
459
  const hm = resolveHailMary(tc);
447
460
  if (hm) {
@@ -454,29 +467,47 @@ async function buildTransport(ctx) {
454
467
  } else {
455
468
  ctx.hailMary = null;
456
469
  }
457
- let resolved = prof ?? (() => {
470
+ let resolved = null;
471
+ if (!tc) {
458
472
  const fb = getEnvFallback();
459
- logWarn("main", `\u26A0\uFE0F Using .env fallback: ${fb.model} via ${fb.providerName}`);
460
- return { model: fb.model, provider: fb.provider, providerName: fb.providerName, contextWindow: fb.contextWindow, maxOutput: fb.maxOutput, fallbacks: [] };
461
- })();
462
- const validation = validateProviderReady(resolved.providerName, resolved.provider, getEnv());
463
- if (!validation.ok) {
464
- const errMsg = `transport.json configures '${resolved.providerName}' but ${validation.reason}. Fix: ${validation.fix}`;
465
- if (ctx.transport) {
466
- logError("main", `${errMsg} \u2014 keeping existing transport up (skipping rebuild)`);
467
- return "ran";
473
+ const fbValidation = validateProviderReady(fb.providerName, fb.provider, getEnv());
474
+ if (!fbValidation.ok) {
475
+ throw new Error(`No transport.json, no backup, and .env emergency model also invalid: ${fbValidation.reason}`);
468
476
  }
469
- if (prof) {
470
- const fb = getEnvFallback();
471
- logError("main", `${errMsg} \u2014 falling back to .env config (${fb.model} via ${fb.providerName})`);
472
- resolved = { model: fb.model, provider: fb.provider, providerName: fb.providerName, contextWindow: fb.contextWindow, maxOutput: fb.maxOutput, fallbacks: [] };
473
- const fbValidation = validateProviderReady(resolved.providerName, resolved.provider, getEnv());
474
- if (!fbValidation.ok) {
475
- logError("main", `.env fallback '${resolved.providerName}' also invalid: ${fbValidation.reason}`);
476
- throw new Error(`${errMsg} (and .env fallback is also invalid: ${fbValidation.reason})`);
477
- }
477
+ logWarn("main", `\u26A0\uFE0F No transport.json \u2014 emergency mode: ${fb.model} via ${fb.providerName}`);
478
+ resolved = { model: fb.model, provider: fb.provider, providerName: fb.providerName, contextWindow: fb.contextWindow, maxOutput: fb.maxOutput, fallbacks: [] };
479
+ setTimeout(() => {
480
+ import("./notification-ULESRDHB.js").then(({ sendNotification }) => sendNotification(ctx, `\u26A0\uFE0F transport.json missing, no backup. Running emergency model: ${fb.model}. Fix: /update deploy`)).catch(() => {
481
+ });
482
+ }, 1e4);
483
+ } else {
484
+ const validation = validateProviderReady(prof.providerName, prof.provider, getEnv());
485
+ if (validation.ok) {
486
+ logDebug("main", `Model init OK: ${prof.model} via ${prof.providerName}`);
487
+ resolved = prof;
478
488
  } else {
479
- throw new Error(errMsg);
489
+ logDebug("main", `Model init failed: ${prof.model} \u2014 ${validation.reason}`);
490
+ logWarn("main", `${prof.model}: ${validation.reason} \u2014 trying fallbacks`);
491
+ for (const fb of prof.fallbacks) {
492
+ const fbResolved = resolveAgent("_fb", { ...tc, agents: { ...tc.agents, _fb: { model: fb.model, provider: fb.provider } } });
493
+ if (!fbResolved) continue;
494
+ const fbVal = validateProviderReady(fbResolved.providerName, fbResolved.provider, getEnv());
495
+ if (fbVal.ok) {
496
+ logDebug("main", `Fallback init OK: ${fbResolved.model} via ${fbResolved.providerName}`);
497
+ resolved = fbResolved;
498
+ break;
499
+ }
500
+ logDebug("main", `Fallback init failed: ${fbResolved.model} \u2014 ${fbVal.reason}`);
501
+ logWarn("main", `${fbResolved.model}: ${fbVal.reason} \u2014 trying next`);
502
+ }
503
+ }
504
+ if (!resolved) {
505
+ const tried = [prof.model, ...prof.fallbacks.map((f) => f.model)].join(", ");
506
+ if (ctx.transport) {
507
+ logError("main", `All models failed init (${tried}) \u2014 keeping existing transport up`);
508
+ return "ran";
509
+ }
510
+ throw new Error(`All configured models failed init (${tried}). Fix transport.json or use /emergency`);
480
511
  }
481
512
  }
482
513
  if (ctx.transport) {
@@ -496,7 +527,7 @@ async function buildTransport(ctx) {
496
527
  defaults?.maxWaitSec ?? config.transport.tmuxMaxWaitSec
497
528
  );
498
529
  } else if (resolved.provider.transport === "api") {
499
- const { DirectApiTransport } = await import("./direct-api-transport-QIWA5ES2.js");
530
+ const { DirectApiTransport } = await import("./direct-api-transport-BK72AP3I.js");
500
531
  const { ModelHealthRegistry } = await import("./model-health-registry-7ECZFCW4.js");
501
532
  const { FallbackPolicy } = await import("./fallback-policy-SR6ED5I3.js");
502
533
  const apiKey = getEnv().getApiKey(resolved.provider.apiKeyEnv ?? "API_KEY");
@@ -669,4 +700,4 @@ export {
669
700
  buildTransport,
670
701
  rebuildTransport
671
702
  };
672
- //# sourceMappingURL=chunk-3IPMKYYH.js.map
703
+ //# sourceMappingURL=chunk-6TSCOXF6.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/boot/phase-transport.ts", "../src/components/transport/tmux-client.ts", "../src/boot/ctx-start.ts"],
4
+ "sourcesContent": ["import { logAndSwallow } from \"../components/log-and-swallow.js\";\nimport { getEnv } from \"../components/env-schema.js\";\n/**\n * phase-transport \u2014 boot phase 3: select, initialize, and wrap the agent transport.\n *\n * Also exports buildTransport/rebuildTransport for /reset to pick up transport.json changes\n * (including provider switches that can't be live-patched).\n */\n\nimport { execSync } from \"node:child_process\";\nimport { TmuxClient } from \"../components/transport/tmux-client.js\";\nimport { createAgentTransport } from \"../components/agent-registry.js\";\nimport { logDebug, logInfo, logWarn, logError, isLogLevel } from \"../components/logger.js\";\nimport { loadUsers } from \"../components/user-registry.js\";\nimport { updateCtxStart } from \"./ctx-start.js\";\nimport type { BootCtx, PhaseResult } from \"./context.js\";\nimport type { IKiroTransport } from \"../components/transport/kiro-transport.js\";\n\nconst TAG = \"transport\";\n\nexport async function phaseTransport(ctx: BootCtx): Promise<PhaseResult> {\n const { memoryConfig } = ctx;\n\n await buildTransport(ctx);\n\n // Initialize context-window-start for all known users\n if (memoryConfig.memoryEnabled) {\n const reg = loadUsers();\n for (const user of reg.users) updateCtxStart(memoryConfig.memoryDir, user.userId, ctx.startedAt);\n }\n return \"ran\";\n}\n\n/**\n * Construct professor transport from current transport.json + env and attach to ctx.transport.\n * Idempotent: destroys any existing ctx.transport first.\n *\n * #367 \u2014 Validates the resolved provider BEFORE destroying the old transport.\n * If validation fails:\n * - During `/reset` (old transport exists): logs ERROR, keeps the old transport up\n * - At boot (no old transport): falls back to .env config if possible, or throws\n * - In either case: bridge stays alive in degraded mode rather than crash-looping\n */\nexport async function buildTransport(ctx: BootCtx): Promise<PhaseResult> {\n const { config } = ctx;\n\n let transport: IKiroTransport;\n\n const { resolveAgent, getEnvFallback, loadTransport, resolveHailMary, clearTransportCache, validateProviderReady } = await import(\"../components/transport-config.js\");\n const { existsSync, renameSync } = await import(\"node:fs\");\n const { join: pathJoin } = await import(\"node:path\");\n clearTransportCache(); // always re-read (picks up /models change writes)\n let tc = loadTransport();\n\n // Recovery: if transport.json missing/corrupt, try transport.old.json\n if (!tc) {\n const configDir = pathJoin(getEnv().abtarsHome, \"config\");\n const primary = pathJoin(configDir, \"transport.json\");\n const old = pathJoin(configDir, \"transport.old.json\");\n if (existsSync(old)) {\n logDebug(\"main\", \"transport.json missing/corrupt \u2014 recovering from transport.old.json\");\n renameSync(old, primary);\n clearTransportCache();\n tc = loadTransport();\n }\n }\n\n const prof = tc ? resolveAgent(\"professor\", tc) : null;\n\n const hm = resolveHailMary(tc);\n if (hm) {\n ctx.hailMary = {\n model: hm.model,\n endpoint: hm.endpoint,\n apiKey: hm.apiKeyEnv ? getEnv().getApiKey(hm.apiKeyEnv) : undefined,\n };\n logInfo(\"main\", `\uD83D\uDEA8 hailMary configured: ${hm.model} (manual /model emergency only)`);\n } else {\n ctx.hailMary = null;\n }\n\n let resolved: typeof prof = null;\n\n if (!tc) {\n // No transport.json and no .old.json \u2014 emergency mode from .env\n const fb = getEnvFallback();\n const fbValidation = validateProviderReady(fb.providerName, fb.provider, getEnv());\n if (!fbValidation.ok) {\n throw new Error(`No transport.json, no backup, and .env emergency model also invalid: ${fbValidation.reason}`);\n }\n logWarn(\"main\", `\u26A0\uFE0F No transport.json \u2014 emergency mode: ${fb.model} via ${fb.providerName}`);\n resolved = { model: fb.model, provider: fb.provider, providerName: fb.providerName, contextWindow: fb.contextWindow, maxOutput: fb.maxOutput, fallbacks: [] };\n // Notify user (deferred \u2014 transport not yet built)\n setTimeout(() => {\n import(\"../components/notification.js\").then(({ sendNotification }) =>\n sendNotification(ctx, `\u26A0\uFE0F transport.json missing, no backup. Running emergency model: ${fb.model}. Fix: /update deploy`))\n .catch(() => {});\n }, 10_000);\n } else {\n // transport.json valid \u2014 walk primary + fb chain\n const validation = validateProviderReady(prof!.providerName, prof!.provider, getEnv());\n if (validation.ok) {\n logDebug(\"main\", `Model init OK: ${prof!.model} via ${prof!.providerName}`);\n resolved = prof;\n } else {\n logDebug(\"main\", `Model init failed: ${prof!.model} \u2014 ${validation.reason}`);\n logWarn(\"main\", `${prof!.model}: ${validation.reason} \u2014 trying fallbacks`);\n // Walk fallback chain\n for (const fb of prof!.fallbacks) {\n const fbResolved = resolveAgent(\"_fb\", { ...tc!, agents: { ...tc!.agents, _fb: { model: fb.model, provider: fb.provider } } });\n if (!fbResolved) continue;\n const fbVal = validateProviderReady(fbResolved.providerName, fbResolved.provider, getEnv());\n if (fbVal.ok) {\n logDebug(\"main\", `Fallback init OK: ${fbResolved.model} via ${fbResolved.providerName}`);\n resolved = fbResolved;\n break;\n }\n logDebug(\"main\", `Fallback init failed: ${fbResolved.model} \u2014 ${fbVal.reason}`);\n logWarn(\"main\", `${fbResolved.model}: ${fbVal.reason} \u2014 trying next`);\n }\n }\n\n if (!resolved) {\n // ALL configured models failed \u2014 hard error (boot) or keep existing (reset)\n const tried = [prof!.model, ...prof!.fallbacks.map(f => f.model)].join(\", \");\n if (ctx.transport) {\n logError(\"main\", `All models failed init (${tried}) \u2014 keeping existing transport up`);\n return \"ran\";\n }\n throw new Error(`All configured models failed init (${tried}). Fix transport.json or use /emergency`);\n }\n }\n\n // #367 \u2014 if existing transport is up and new config rebuild needed, keep old on error\n // (This path is only hit via /reset rebuild, not boot)\n\n // Destroy old (if any) \u2014 now that we know the new config is valid\n if (ctx.transport) {\n try { await ctx.transport.destroy(); } catch (err) {\n logWarn(\"main\", `Old transport destroy failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n ctx.transport = null;\n }\n\n if (resolved.provider.transport === \"tmux\") {\n const defaults = tc?.transportDefaults?.tmux;\n logInfo(\"main\", `\uD83D\uDDA5\uFE0F tmux transport (${resolved.providerName})`);\n transport = new TmuxClient(\n defaults?.session ?? config.transport.tmuxSession,\n defaults?.captureDelaySec ?? config.transport.tmuxCaptureDelaySec,\n defaults?.maxWaitSec ?? config.transport.tmuxMaxWaitSec,\n );\n } else if (resolved.provider.transport === \"api\") {\n const { DirectApiTransport } = await import(\"../components/transport/direct-api-transport.js\");\n const { ModelHealthRegistry } = await import(\"../components/transport/model-health-registry.js\");\n const { FallbackPolicy } = await import(\"../components/transport/fallback-policy.js\");\n const apiKey = getEnv().getApiKey(resolved.provider.apiKeyEnv ?? \"API_KEY\");\n\n const candidates: Array<{ model: string; endpoint: string; apiKey?: string; maxContext: number }> = [\n { endpoint: resolved.provider.endpoint ?? \"http://localhost:11434/v1\", apiKey, model: resolved.model, maxContext: resolved.contextWindow },\n ];\n for (const fb of resolved.fallbacks) {\n const fbResolved = tc ? resolveAgent(\"_fallback\", { ...tc, agents: { ...tc.agents, _fallback: { model: fb.model, provider: fb.provider } } }) : null;\n candidates.push({\n endpoint: fbResolved?.provider.endpoint ?? resolved.provider.endpoint!,\n apiKey: fbResolved?.provider.apiKeyEnv ? getEnv().getApiKey(fbResolved.provider.apiKeyEnv) : apiKey,\n model: fb.model,\n maxContext: fbResolved?.contextWindow ?? resolved.contextWindow,\n });\n }\n\n if (!ctx.modelHealthRegistry) {\n ctx.modelHealthRegistry = new ModelHealthRegistry(tc?.healthPolicy);\n }\n // Wire auto-demotion\n if (!ctx.modelHealthRegistry.onDemote) {\n ctx.modelHealthRegistry.onDemote = (model, _endpoint, reason) => {\n import(\"../components/transport-config.js\").then(({ demoteModel }) => demoteModel(model, reason));\n import(\"../components/notification.js\").then(({ sendNotification }) =>\n sendNotification(ctx, `\u26A0\uFE0F ${model} demoted (${reason}). Next healthy model promoted.`)).catch(err => logAndSwallow(TAG, \"sendNotification model-demote\", err));\n };\n }\n const policy = new FallbackPolicy(candidates, ctx.modelHealthRegistry);\n\n transport = new DirectApiTransport({\n endpoint: resolved.provider.endpoint ?? \"http://localhost:11434/v1\",\n apiKey,\n model: resolved.model,\n maxContext: resolved.contextWindow,\n maxOutput: resolved.maxOutput,\n maxTurns: tc?.maxTurns ?? 50,\n apiFormat: resolved.provider.apiFormat,\n thinking: resolved.provider.thinking,\n }, policy);\n logInfo(\"main\", `\uD83D\uDD0C Direct API transport (${resolved.providerName}, model=${resolved.model}, ${candidates.length} candidates)`);\n } else {\n try { execSync(\"pkill -f 'kiro-cli.*acp.*professor' 2>/dev/null || true\", { timeout: 3000 }); } catch (err) { logAndSwallow(\"phase_transport\", \"op\", err); }\n logInfo(\"main\", `\uD83D\uDD0C ACP transport (${resolved.provider.cli ?? \"kiro-cli\"}, model=${resolved.model})`);\n transport = createAgentTransport(\"professor\", {\n cliPath: resolved.provider.cli ?? config.transport.agentCliPath,\n workingDir: config.transport.workingDir,\n agentCli: resolved.provider.cli ?? \"kiro-cli\",\n model: resolved.model,\n });\n }\n\n await transport.initialize();\n\n if (\"setSystemPrompt\" in transport && typeof (transport as { setSystemPrompt: unknown }).setSystemPrompt === \"function\") {\n const { loadSoulBundle } = await import(\"../components/soul-loader.js\");\n const soul = loadSoulBundle();\n if (soul) (transport as { setSystemPrompt: (p: string) => void }).setSystemPrompt(soul);\n }\n\n if (resolved.fallbacks.length > 0 && resolved.provider.transport !== \"api\") {\n logWarn(\"main\", `\u26A0\uFE0F Fallbacks configured for ${resolved.provider.transport} transport \u2014 only API transport supports model fallback`);\n }\n\n ctx.transport = transport;\n ctx.modelName = resolved.model;\n ctx.modelProvider = resolved.providerName;\n ctx.fallbackChain = resolved.fallbacks.map((f: { model: string }) => f.model);\n\n if (ctx.modelHealthRegistry) {\n ctx.runtime.setRegistry(ctx.modelHealthRegistry);\n }\n ctx.runtime.setMainTransport(transport);\n ctx.runtime.setSessionManager(ctx.sessionManager);\n\n // Wire async delegation tools (#570)\n if (getEnv().enableAsyncDelegation) {\n const { setDelegationDeps } = await import(\"../components/transport/delegation-tools.js\");\n setDelegationDeps(ctx.runtime, ctx.sessionManager);\n }\n\n logInfo(\"main\", \"\u2705 Transport ready\");\n\n // Wire ActionGate for auth-required commands\n const { join } = await import(\"node:path\");\n const { abtarsHome } = await import(\"../paths.js\");\n const { ActionGate } = await import(\"../components/action-gate.js\");\n const { setActionGate } = await import(\"../components/transport/tool-registry.js\");\n const authDir = join(abtarsHome(), \"auth\");\n ctx.actionGate = new ActionGate(authDir);\n setActionGate(ctx.actionGate);\n logDebug(\"main\", \"\uD83D\uDD12 ActionGate wired\");\n\n if (resolved.provider.transport === \"api\" && (ctx.memory as any)?.available) {\n const { setMemoryBackend } = await import(\"../components/transport/tool-registry.js\");\n // #860: Use the SAME MemoryManager instance \u2014 don't create a second SqliteBackend.\n // Two separate DB connections to the same WAL-mode file corrupt each other's handles.\n const mm = ctx.memory!;\n const backend = {\n initialize: async () => {},\n close: () => {},\n instantStore: (p: any) => mm.editor.instantStore(p),\n editMemory: (p: any) => mm.editor.editMemory(p),\n reclassifyMemory: (id: number, level: number, uo: boolean) => { mm.editor.reclassifyMemory(id, level, uo); return Promise.resolve(); },\n adjustRelevance: (id: number, delta: number) => { mm.editor.adjustRelevance(id, delta); return Promise.resolve(); },\n mergeMemories: (a: number, b: number) => mm.editor.mergeMemories(a, b),\n cascadeDelete: (ids: number[], uid: string) => mm.editor.cascadeDelete(ids, uid),\n recall: (p: any) => mm.recallSearch(p),\n rebuildFtsIndexes: () => mm.rebuildFtsIndexes(),\n };\n setMemoryBackend(backend as any);\n logInfo(\"main\", \"\uD83E\uDDE0 In-process memory wired to tool registry (shared handle)\");\n\n // #843: Wire memory to transport for session hydration on restart\n (transport as import(\"../components/transport/direct-api-transport.js\").DirectApiTransport).memoryBackend = ctx.memory!;\n\n // Wire context engine for automatic compaction\n const db = ctx.memory!.getDb?.() ?? ctx.memory!.getDatabase?.();\n if (db && resolved.contextWindow >= 128000) {\n const { ContextEngine } = await import(\"abmind\");\n const { createContextOrchestrator } = await import(\"../components/context/index.js\");\n const contextEngine = new ContextEngine(db);\n const orchestrator = createContextOrchestrator(\n contextEngine,\n async (systemPrompt: string, userPrompt: string) => {\n // Use the transport itself for summarization (same model, same endpoint)\n const { streamSingleCompletion } = await import(\"../components/transport/stream-single.js\");\n return streamSingleCompletion({\n endpoint: resolved.provider.endpoint ?? \"http://localhost:11434/v1\",\n apiKey: getEnv().getApiKey(resolved.provider.apiKeyEnv ?? \"API_KEY\") ?? undefined,\n model: resolved.model,\n systemPrompt,\n userPrompt,\n maxTokens: 4096,\n });\n },\n (_chatId: string) => {\n try { return ctx.memory?.getLastMessageTimestamp(true) ?? null; } catch (err) { logAndSwallow(TAG, \"getLastMessageTimestamp\", err); return null; }\n },\n );\n (transport as import(\"../components/transport/direct-api-transport.js\").DirectApiTransport).contextOrchestrator = orchestrator;\n logInfo(\"main\", \"\uD83D\uDCE6 Context engine wired (auto-compaction active)\");\n }\n }\n\n if (\"onFallback\" in transport) {\n let lastNotifiedModel: string | null = null;\n (transport as unknown as { onFallback: (model: string, ctxPct: number, reason?: string) => void }).onFallback = (model, ctxPct, reason) => {\n const reasonTag = reason ? ` (${reason})` : \"\";\n const msg = `\u26A1 Fallback${reasonTag}: ${model}${ctxPct >= 0 ? ` (ctx: ~${ctxPct}%)` : \"\"}`;\n logInfo(\"main\", msg);\n if (model !== lastNotifiedModel || isLogLevel(\"debug\")) {\n lastNotifiedModel = model;\n import(\"../components/notification.js\").then(({ sendNotification }) => sendNotification(ctx, msg)).catch(err => logAndSwallow(TAG, \"sendNotification fallback\", err));\n }\n };\n }\n return \"ran\";\n}\n\n/**\n * Rebuild professor transport in place (picks up transport.json changes).\n * Patches downstream references that captured the old transport (pipelineDeps, idleSave).\n */\nexport async function rebuildTransport(ctx: BootCtx): Promise<PhaseResult> {\n logInfo(\"main\", \"\uD83D\uDD04 Rebuilding transport...\");\n await buildTransport(ctx);\n if (ctx.pipelineDeps && ctx.transport) {\n (ctx.pipelineDeps as { transport: IKiroTransport }).transport = ctx.transport;\n }\n if (ctx.idleSave && ctx.transport) {\n (ctx.idleSave as unknown as { transport: IKiroTransport }).transport = ctx.transport;\n }\n logInfo(\"main\", \"\u2705 Transport rebuilt\");\n return \"ran\";\n}\n", "import { execSync } from \"node:child_process\";\nimport { writeFileSync, unlinkSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { IKiroTransport } from \"./kiro-transport.js\";\nimport { logInfo, logDebug, logWarn } from \"../logger.js\";\nimport { logAndSwallow } from \"../log-and-swallow.js\";\nimport { abtarsHome } from \"../../paths.js\";\n\nconst TAG = \"tmux\";\n\n// Kiro CLI prompt pattern: \"N% >\" or \"N% !>\" where N is a number (context usage percentage)\n// The \"!\" appears in trust-all-tools mode\nconst KIRO_PROMPT_RE = /^\\d+%\\s*!?>/;\n\n// Also match common shell prompts as fallback\nconst SHELL_PROMPT_RE = /[$\u276F%#]\\s*$/;\n\n/**\n * Communicates with kiro-cli running inside a tmux session.\n * Uses `tmux send-keys` to send prompts and `tmux capture-pane`\n * to read responses.\n */\nexport class TmuxClient implements IKiroTransport {\n private readonly sessionName: string;\n private readonly captureDelaySec: number;\n private readonly maxWaitSec: number;\n private ready = false;\n\n /** Optional callback for streaming intermediate responses before final prompt. */\n onIntermediateResponse?: (text: string) => void;\n\n /** Tracks the cumulative text delivered via intermediate chunks (for tail detection). */\n private lastIntermediateDelivered = \"\";\n\n constructor(sessionName: string, captureDelaySec: number, maxWaitSec: number) {\n this.sessionName = sessionName;\n this.captureDelaySec = captureDelaySec;\n this.maxWaitSec = maxWaitSec;\n }\n\n async initialize(): Promise<void> {\n if (!this.sessionExists()) {\n throw new Error(\n `tmux session \"${this.sessionName}\" not found. ` +\n `Run: scripts/tmux-session.sh to start it.`,\n );\n }\n this.ready = true;\n logInfo(\"tmux\", `Session \"${this.sessionName}\" found`);\n }\n\n get isReady(): boolean {\n return this.ready && this.sessionExists();\n }\n\n readonly transportCommands: string[] = [];\n\n async sendPrompt(_sessionKey: string, message: string): Promise<string> {\n if (!this.isReady) {\n throw new Error(\"tmux session not available\");\n }\n\n this.lastIntermediateDelivered = \"\";\n const maxAttempts = 2;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n // Snapshot pane content before sending\n const before = this.capturePaneRaw();\n if (attempt === 1) {\n logDebug(\"tmux\", `Sending: \"${message.slice(0, 80)}\"`);\n } else {\n logInfo(\"tmux\", `Retry #${attempt}: resending prompt`);\n }\n\n // Send the message \u2014 use temp file for long prompts to avoid tmux command length limit\n try {\n if (message.length > 4000) {\n const tmpDir = join(abtarsHome(), \"tmp\");\n mkdirSync(tmpDir, { recursive: true });\n const tmpFile = join(tmpDir, `prompt-${Date.now()}.txt`);\n writeFileSync(tmpFile, message);\n const readCmd = `My full message is in ${tmpFile} \u2014 please read it and respond.`;\n const escaped = readCmd.replace(/'/g, \"'\\\\''\");\n this.exec(`tmux send-keys -t ${this.sessionName} '${escaped}' Enter`);\n setTimeout(() => { try { unlinkSync(tmpFile); } catch (err) { logAndSwallow(TAG, \"unlink tmpFile\", err); } }, 120_000);\n } else {\n const escaped = message.replace(/'/g, \"'\\\\''\");\n this.exec(`tmux send-keys -t ${this.sessionName} '${escaped}' Enter`);\n }\n } catch (err) {\n logWarn(\"tmux\", `send-keys failed: ${err instanceof Error ? err.message : String(err)}`);\n return \"\u26A0\uFE0F Failed to send message to Kiro session. The tmux session may be in copy mode or unresponsive. Try /reset.\";\n }\n\n // Wait for initial processing\n await sleep(this.captureDelaySec * 1000);\n\n // Poll until Kiro finishes\n const response = await this.pollForResponse(before);\n\n // Check for Kiro transient error \u2014 retry once\n if (response.startsWith(\"Kiro is having trouble\") && attempt < maxAttempts) {\n logInfo(\"tmux\", `Kiro trouble detected, will retry in 5s...`);\n await sleep(5000);\n continue;\n }\n\n logDebug(\"tmux\", `Got response (${response.length} chars)`);\n return response;\n }\n\n // Should not reach here, but just in case\n return \"\u26A0\uFE0F Kiro is having trouble responding. Try again or /reset.\";\n }\n\n async resetSession(_sessionKey: string): Promise<void> {\n if (!this.sessionExists()) return;\n this.exec(`tmux send-keys -t ${this.sessionName} C-c`);\n await sleep(1000);\n this.exec(`tmux send-keys -t ${this.sessionName} '/clear' Enter`);\n await sleep(2000);\n // Kiro asks \"Are you sure? [y/n]:\" \u2014 confirm with 'y'\n this.exec(`tmux send-keys -t ${this.sessionName} 'y' Enter`);\n await sleep(1000);\n }\n\n async restartSession(workingDir: string, kiroModel?: string): Promise<void> {\n // Kill existing tmux session and start fresh\n if (this.sessionExists()) {\n this.exec(`tmux kill-session -t ${this.sessionName}`);\n await sleep(1000);\n }\n let cmd = `kiro-cli chat --trust-all-tools`;\n if (kiroModel) cmd += ` --model ${kiroModel}`;\n this.exec(`tmux new-session -d -s ${this.sessionName} -c '${workingDir}' '${cmd}'`);\n this.exec(`tmux set-option -t ${this.sessionName} history-limit 5000`);\n await sleep(3000);\n // Enable thinking tool\n this.exec(`tmux send-keys -t ${this.sessionName} '/settings chat.enableThinking true' Enter`);\n await sleep(2000);\n this.ready = this.sessionExists();\n logInfo(\"tmux\", `Session restarted (ready=${this.ready})`);\n }\n\n async sendInterrupt(): Promise<void> {\n if (!this.sessionExists()) return;\n logInfo(\"tmux\", \"Sending Ctrl+C interrupt\");\n this.exec(`tmux send-keys -t ${this.sessionName} C-c`);\n }\n\n destroy(): void {\n this.ready = false;\n }\n\n /**\n * Poll capture-pane until Kiro's prompt reappears (N% >).\n * Delivers intermediate purple-line responses via onIntermediateResponse callback\n * so the user sees partial answers while Kiro continues with tools.\n * Only returns when the actual Kiro prompt appears or timeout.\n */\n private async pollForResponse(beforeSnapshot: string): Promise<string> {\n const startTime = Date.now();\n const maxWaitMs = this.maxWaitSec * 1000;\n let lastCapture = \"\";\n let stableCount = 0;\n let lastDeliveredAnswer = \"\";\n\n while (Date.now() - startTime < maxWaitMs) {\n const capture = this.capturePaneRaw();\n\n // Get only the NEW content (diff from before)\n const newContent = this.diffOutput(beforeSnapshot, capture);\n\n if (newContent.length === 0) {\n await sleep(2000);\n continue;\n }\n\n // Check if the last non-empty line is a Kiro prompt (N% >)\n const lines = capture.split(\"\\n\");\n const lastNonEmpty = this.getLastNonEmptyLine(lines);\n const lastClean = this.stripAnsi(lastNonEmpty);\n\n if (KIRO_PROMPT_RE.test(lastClean)) {\n const pctMatch = lastClean.match(/^(\\d+)%/);\n if (pctMatch) {\n this.lastContextPercent = parseInt(pctMatch[1]!, 10);\n logDebug(\"tmux\", `Context window: ${this.lastContextPercent}%`);\n }\n logDebug(\"tmux\", `Detected Kiro prompt: \"${lastClean}\"`);\n return this.extractResponse(newContent);\n }\n\n // Check for shell prompt as fallback\n if (SHELL_PROMPT_RE.test(lastClean) && newContent.length > 10) {\n logDebug(\"tmux\", `Detected shell prompt: \"${lastClean}\"`);\n return this.extractResponse(newContent);\n }\n\n // No prompt yet \u2014 deliver intermediate answer if we have new purple lines\n if (this.onIntermediateResponse && capture !== lastCapture) {\n const intermediateAnswer = this.extractAnswerOnly(newContent);\n if (intermediateAnswer && intermediateAnswer !== lastDeliveredAnswer) {\n const newPart = intermediateAnswer.startsWith(lastDeliveredAnswer)\n ? intermediateAnswer.slice(lastDeliveredAnswer.length).trim()\n : intermediateAnswer;\n if (newPart) {\n logDebug(\"tmux\", `Delivering intermediate chunk (${newPart.length} chars)`);\n this.onIntermediateResponse(newPart);\n lastDeliveredAnswer = intermediateAnswer;\n this.lastIntermediateDelivered = intermediateAnswer;\n }\n }\n }\n\n // Track stabilization but do NOT return on it \u2014 only N% > ends the poll\n if (capture === lastCapture) {\n stableCount++;\n } else {\n stableCount = 0;\n lastCapture = capture;\n }\n\n await sleep(2000);\n }\n\n // Timeout\n const finalCapture = this.capturePaneRaw();\n const finalNew = this.diffOutput(beforeSnapshot, finalCapture);\n if (finalNew.length > 0) {\n return this.extractResponse(finalNew) + \"\\n\\n\u23F1\uFE0F (response may be incomplete \u2014 timed out)\";\n }\n return \"\u23F1\uFE0F Kiro is still processing. Check the tmux session directly.\";\n }\n\n /**\n * Extract the meaningful response from the diff.\n * Removes the echoed user input line and Kiro's prompt lines.\n * Stores the \"answer only\" portion (lines that were \"> \" prefixed)\n * separately for TTS use.\n *\n * Kiro output format:\n * N% > <echoed user input>\n * > <response line 1>\n * > <response line 2>\n * \u25B8 Time: Ns\n * M% >\n */\n private lastAnswerOnly = \"\";\n private lastContextPercent = -1;\n\n /** Get just the Kiro answer lines (\"> \" prefixed) from the last response \u2014 for TTS. */\n get answerOnly(): string {\n return this.lastAnswerOnly;\n }\n get toolCallsSucceeded(): number { return 0; }\n\n /** Get the context window usage percentage from the last Kiro prompt (e.g. 10 for \"10% >\"). Returns -1 if unknown. */\n get contextPercent(): number {\n return this.lastContextPercent;\n }\n /** Get the cumulative text that was delivered via intermediate streaming. */\n get intermediateDeliveredText(): string {\n return this.lastIntermediateDelivered;\n }\n\n /** Extract just the purple \"> \" answer lines from raw tmux output (no side effects). */\n private extractAnswerOnly(raw: string): string {\n const PURPLE_PREFIX = /\\x1b\\[38;5;141m>\\s/;\n const lines = raw.split(\"\\n\");\n\n // Find last contiguous block of purple lines\n let blockStart = -1;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (PURPLE_PREFIX.test(lines[i]!)) {\n blockStart = i;\n while (blockStart > 0 && PURPLE_PREFIX.test(lines[blockStart - 1]!)) blockStart--;\n break;\n }\n }\n if (blockStart < 0) return \"\";\n\n const answerLines: string[] = [];\n for (let i = blockStart; i < lines.length; i++) {\n const clean = this.stripAnsi(lines[i]!).trim();\n if (KIRO_PROMPT_RE.test(clean)) break;\n if (clean.startsWith(\"\u25B8 Time:\")) break;\n if (clean.startsWith(\"> \")) answerLines.push(clean.slice(2));\n else if (clean === \">\") answerLines.push(\"\");\n else if (clean === \"\") answerLines.push(\"\");\n else answerLines.push(clean);\n }\n return answerLines.join(\"\\n\").trim();\n }\n\n private extractResponse(raw: string): string {\n // ANSI color 141 (light purple) marks the \"> \" prefix on actual LLM response lines.\n // We detect these BEFORE stripping ANSI to reliably distinguish LLM output from\n // injected context (gray, color 245) and other noise.\n const PURPLE_PREFIX = /\\x1b\\[38;5;141m>\\s/;\n\n const lines = raw.split(\"\\n\");\n\n // First pass: identify lines that are genuine LLM responses (purple \"> \" prefix)\n const answerLines: string[] = [];\n let lastPurpleBlockStart = -1;\n\n for (let i = 0; i < lines.length; i++) {\n if (PURPLE_PREFIX.test(lines[i]!)) {\n if (lastPurpleBlockStart === -1) lastPurpleBlockStart = i;\n }\n }\n\n // Find the LAST contiguous block of purple \"> \" lines \u2014 that's the real answer.\n // Walk backwards to find the start of the last block.\n let blockStart = -1;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (PURPLE_PREFIX.test(lines[i]!)) {\n blockStart = i;\n // Keep walking back through contiguous purple lines and continuation lines\n while (blockStart > 0) {\n const prev = lines[blockStart - 1]!;\n if (PURPLE_PREFIX.test(prev) || (!KIRO_PROMPT_RE.test(this.stripAnsi(prev).trim()) && !prev.includes(\"\u25B8 Time:\") && this.stripAnsi(prev).trim() !== \"\" && !PURPLE_PREFIX.test(prev) && blockStart === i)) {\n // Only extend back through purple lines\n if (PURPLE_PREFIX.test(prev)) {\n blockStart--;\n } else {\n break;\n }\n } else {\n break;\n }\n }\n break;\n }\n }\n\n if (blockStart >= 0) {\n // Extract from the last purple block to the end, stripping ANSI and \"> \" prefix\n for (let i = blockStart; i < lines.length; i++) {\n const line = lines[i]!;\n const clean = this.stripAnsi(line).trim();\n // Stop at Kiro prompt or Time summary\n if (KIRO_PROMPT_RE.test(clean)) break;\n if (clean.startsWith(\"\u25B8 Time:\") || clean.startsWith(\"\u25B8 Time:\")) break;\n if (clean === \"\") {\n answerLines.push(\"\");\n continue;\n }\n // Strip \"> \" prefix\n if (clean.startsWith(\"> \")) {\n answerLines.push(clean.slice(2));\n } else if (clean === \">\") {\n answerLines.push(\"\");\n } else {\n answerLines.push(clean);\n }\n }\n this.lastAnswerOnly = answerLines.join(\"\\n\").trim();\n } else {\n this.lastAnswerOnly = \"\";\n }\n\n // Full response: strip ANSI, then remove prompt lines and noise (legacy behavior)\n const cleaned = this.stripAnsi(raw);\n const allLines = cleaned.split(\"\\n\");\n const result: string[] = [];\n\n for (const line of allLines) {\n const trimmed = line.trim();\n if (result.length === 0 && trimmed === \"\") continue;\n if (KIRO_PROMPT_RE.test(trimmed)) continue;\n if (trimmed.startsWith(\"\u25B8 Time:\") || trimmed.startsWith(\"\u25B8 Time:\")) continue;\n if (/^-{4,}$/.test(trimmed)) continue;\n result.push(line);\n }\n\n const stripped = result.map((line) => {\n const trimmed = line.trimStart();\n if (trimmed.startsWith(\"> \")) return trimmed.slice(2);\n if (trimmed === \">\") return \"\";\n return line;\n });\n\n const final = stripped.join(\"\\n\").trim();\n logDebug(\"tmux\", `extractResponse: ${result.length} lines \u2192 \"${final.slice(0, 120)}\"`);\n if (this.lastAnswerOnly) {\n logDebug(\"tmux\", `answerOnly (${this.lastAnswerOnly.length} chars): \"${this.lastAnswerOnly.slice(0, 120)}\"`);\n }\n return final;\n }\n\n /** Get new content by diffing before/after snapshots. */\n private diffOutput(before: string, after: string): string {\n const beforeLines = before.split(\"\\n\");\n const afterLines = after.split(\"\\n\");\n\n // Find where the new content starts\n let commonPrefix = 0;\n while (\n commonPrefix < beforeLines.length &&\n commonPrefix < afterLines.length &&\n beforeLines[commonPrefix] === afterLines[commonPrefix]\n ) {\n commonPrefix++;\n }\n\n return afterLines.slice(commonPrefix).join(\"\\n\").trim();\n }\n\n /** Get the last non-empty line from an array. */\n private getLastNonEmptyLine(lines: string[]): string {\n for (let i = lines.length - 1; i >= 0; i--) {\n const trimmed = lines[i]!.trim();\n if (trimmed.length > 0) return trimmed;\n }\n return \"\";\n }\n\n /** Strip ANSI escape codes. */\n private stripAnsi(text: string): string {\n // eslint-disable-next-line no-control-regex\n return text.replace(/\\x1B\\[[0-9;]*[a-zA-Z]/g, \"\")\n .replace(/\\x1B\\][^\\x07]*\\x07/g, \"\"); // OSC sequences\n }\n\n private capturePaneRaw(): string {\n try {\n return this.exec(`tmux capture-pane -t ${this.sessionName} -p -e -S -2000`);\n } catch (err) {\n logAndSwallow(TAG, \"capturePaneRaw\", err);\n return \"\";\n }\n }\n\n private sessionExists(): boolean {\n try {\n this.exec(`tmux has-session -t ${this.sessionName}`);\n return true;\n } catch (err) {\n logAndSwallow(TAG, \"sessionExists check\", err);\n return false;\n }\n }\n\n private exec(command: string): string {\n return execSync(command, {\n encoding: \"utf-8\",\n timeout: 15_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim();\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n", "/**\n * Context-window-start persistence \u2014 per-user timestamps tracking when the\n * current context window began. Used by recall fallback stages.\n *\n * Called from phase-transport (initialize at boot), phase-sleep-cycle (reset\n * after sleep), and message-pipeline (update on session turn).\n */\n\nimport { logAndSwallow } from \"../components/log-and-swallow.js\";\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/** Update context-window-start timestamp for a chat. */\nexport function updateCtxStart(memoryDir: string, userId: string, ts = Date.now()): void {\n const p = join(memoryDir, \"context-window-start.json\");\n let data: Record<string, number> = {};\n try { data = JSON.parse(readFileSync(p, \"utf-8\")); } catch (err) { logAndSwallow(\"ctx_start\", \"op\", err); }\n data[userId] = ts;\n writeFileSync(p, JSON.stringify(data), \"utf-8\");\n}\n\n/** Set all context-window-start entries to now (called after sleep). */\nexport function resetAllCtxStarts(memoryDir: string): void {\n const p = join(memoryDir, \"context-window-start.json\");\n let data: Record<string, number> = {};\n try { data = JSON.parse(readFileSync(p, \"utf-8\")); } catch (err) { logAndSwallow(\"ctx_start\", \"read ctx-start json\", err); return; }\n const now = Date.now();\n for (const key of Object.keys(data)) data[key] = now;\n writeFileSync(p, JSON.stringify(data), \"utf-8\");\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["execSync", "writeFileSync", "join", "TAG", "execSync", "join", "abtarsHome"]
7
+ }
@@ -70,7 +70,7 @@ async function createSubagentTransport(role, registry, currentModel) {
70
70
  return { model: fb.model, provider: fb.provider, providerName: fb.providerName, contextWindow: fb.contextWindow, maxOutput: fb.maxOutput, fallbacks: [] };
71
71
  })();
72
72
  if (agent.provider.transport === "api") {
73
- const { DirectApiTransport } = await import("./direct-api-transport-QIWA5ES2.js");
73
+ const { DirectApiTransport } = await import("./direct-api-transport-BK72AP3I.js");
74
74
  const { FallbackPolicy } = await import("./fallback-policy-SR6ED5I3.js");
75
75
  const apiKey = getEnv().getApiKey(agent.provider.apiKeyEnv ?? "API_KEY");
76
76
  const startModel = currentModel ?? agent.model;
@@ -186,4 +186,4 @@ export {
186
186
  createAgentTransport,
187
187
  createSubagentTransport
188
188
  };
189
- //# sourceMappingURL=chunk-7WFE2JI5.js.map
189
+ //# sourceMappingURL=chunk-7B3GK5JQ.js.map
@@ -128,7 +128,6 @@ async function reconcilePathLink(binDir, userBinDir, name, force, dryRun) {
128
128
  }
129
129
  async function writeWrapper(binDir, name, currentLink, dryRun) {
130
130
  const bundleFile = name === "abtars" ? "abtars-cli.js" : `${name}.js`;
131
- const home = currentLink.replace(/\/current$/, "");
132
131
  let content;
133
132
  if (name === "abmind") {
134
133
  content = `#!/usr/bin/env bash
@@ -428,4 +427,4 @@ export {
428
427
  writeWrapper,
429
428
  install
430
429
  };
431
- //# sourceMappingURL=chunk-SMZQDMSZ.js.map
430
+ //# sourceMappingURL=chunk-ENXQMPV3.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/cli/commands/install.ts"],
4
+ "sourcesContent": ["/**\n * `abtars install [--force]` \u2014 first-time setup.\n *\n * - No existing ~/.abtars: create dirs, seed config/ from .env.example,\n * create PATH symlinks. Does NOT run onboard (Phase 3).\n * - Existing ~/.abtars: refuse unless --force (which\n * re-seeds missing config and reconciles symlinks, no code changes).\n */\n\nimport { mkdir, readFile, stat, symlink, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync, readdirSync, copyFileSync, mkdirSync } from 'node:fs';\nimport { hostname, homedir as _homedir } from 'node:os';\nimport { execSync } from 'node:child_process';\nimport { basename, dirname, join } from 'node:path';\nimport { emptyManifest, packagePaths, readManifest, resolveUserBinDir, writeManifest } from '../deploy-lib-import.js';\n\n/** Resolve real user home even under sudo. */\nfunction homedir(): string {\n const sudoUser = process.env['SUDO_USER'];\n if (sudoUser) {\n try { return execSync(`getent passwd ${sudoUser}`, { encoding: 'utf-8' }).split(':')[5]!.trim(); }\n catch { /* fall through */ }\n }\n return _homedir();\n}\n\nexport interface InstallOptions {\n readonly restore?: string;\n readonly force: boolean;\n readonly dryRun: boolean;\n readonly mode?: \"simple\" | \"supervised\";\n}\n\n// CLI wrappers are read from install-manifest.json at runtime.\n// Each is a thin wrapper that invokes `node current/dist/cli/<name>.js \"$@\"`.\n// Regenerated on every install / flat-to-releases migration.\n\nasync function exists(p: string): Promise<boolean> {\n try {\n await stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * True if `p` exists as any filesystem entry \u2014 regular file, directory,\n * symlink (including dangling). Use this for collision checks in\n * reconcilePathLink, where a dangling symlink still occupies the inode\n * and would cause EEXIST on symlink(). `exists()` above uses stat() which\n * follows symlinks and returns false on dangling ones; that's wrong for\n * collision detection.\n */\nasync function existsAny(p: string): Promise<boolean> {\n try {\n const { lstat } = await import('node:fs/promises');\n await lstat(p);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isSymlink(p: string): Promise<boolean> {\n try {\n const { lstat } = await import('node:fs/promises');\n const s = await lstat(p);\n return s.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nasync function createSkeleton(home: string, dryRun: boolean): Promise<void> {\n const { loadManifest } = await import('../install-manifest.js');\n const manifest = loadManifest();\n const dirs = manifest.directories.map(d => join(home, d.path));\n if (dryRun) {\n process.stdout.write(`[dry-run] mkdir -p:\\n ${dirs.join('\\n ')}\\n`);\n return;\n }\n for (const d of manifest.directories) {\n await mkdir(join(home, d.path), { recursive: true, mode: d.mode ? parseInt(d.mode, 8) : undefined });\n }\n}\n\nasync function seedConfig(repoRoot: string, _configDir: string, dryRun: boolean, home: string): Promise<readonly string[]> {\n const { loadManifest } = await import('../install-manifest.js');\n const manifest = loadManifest(repoRoot);\n const seeded: string[] = [];\n for (const seed of manifest.configSeeds) {\n const src = join(repoRoot, seed.source);\n const dst = join(home, seed.dest);\n if (!(await exists(src))) continue;\n if (await exists(dst)) continue;\n if (dryRun) {\n seeded.push(`[dry-run] cp ${src} ${dst}`);\n continue;\n }\n const content = await readFile(src, 'utf-8');\n await mkdir(dirname(dst), { recursive: true });\n await writeFile(dst, content, { mode: seed.mode ? parseInt(seed.mode, 8) : 0o644 });\n seeded.push(basename(dst));\n }\n return seeded;\n}\n\n/**\n * Reconcile a single PATH symlink at ~/.local/bin/<name>.\n * Policy (plan \u00A7\"PATH symlink collision\"):\n * - Missing \u2192 create\n * - Symlink pointing into our own ~/.abtars/bin/ \u2192 overwrite\n * - Anything else \u2192 refuse with message, unless force\n */\nasync function reconcilePathLink(\n binDir: string,\n userBinDir: string,\n name: string,\n force: boolean,\n dryRun: boolean,\n): Promise<{ action: string; message?: string }> {\n const linkPath = join(userBinDir, name);\n const targetPath = join(binDir, name);\n const linkExists = await existsAny(linkPath);\n if (!linkExists) {\n if (dryRun) return { action: `[dry-run] ln -s ${targetPath} ${linkPath}` };\n await symlink(targetPath, linkPath);\n return { action: `created ${linkPath}` };\n }\n if (await isSymlink(linkPath)) {\n const { readlink, unlink } = await import('node:fs/promises');\n const current = await readlink(linkPath);\n // \"We own it\" means: points at THIS install's bin dir, not a fuzzy match\n // on any path containing /.abtars/bin/. A smoke-test install at\n // ABTARS_HOME=~/.cache/ab-smoke-.../ must not clobber the real\n // ~/.abtars symlinks. Compare absolute paths directly.\n const ownsIt = current === targetPath;\n if (ownsIt) {\n if (dryRun) return { action: `[dry-run] overwrite ${linkPath} (we own it)` };\n await unlink(linkPath);\n await symlink(targetPath, linkPath);\n return { action: `updated ${linkPath}` };\n }\n if (force) {\n if (dryRun) return { action: `[dry-run] --force overwrite ${linkPath} (currently -> ${current})` };\n await unlink(linkPath);\n await symlink(targetPath, linkPath);\n return { action: `forced overwrite ${linkPath} (was -> ${current})` };\n }\n return {\n action: 'refused',\n message: `${linkPath} is a symlink to ${current} (not ours). Pass --force to overwrite.`,\n };\n }\n if (force) {\n if (dryRun) return { action: `[dry-run] --force overwrite ${linkPath} (regular file)` };\n const { unlink } = await import('node:fs/promises');\n await unlink(linkPath);\n await symlink(targetPath, linkPath);\n return { action: `forced overwrite ${linkPath} (was regular file)` };\n }\n return {\n action: 'refused',\n message: `${linkPath} exists as a regular file (not our symlink). Pass --force to overwrite.`,\n };\n}\n\nexport async function writeWrapper(binDir: string, name: string, currentLink: string, dryRun: boolean): Promise<void> {\n const bundleFile = name === 'abtars' ? 'abtars-cli.js' : `${name}.js`;\n let content: string;\n\n if (name === 'abmind') {\n // #863: abmind resolves from bundle, source, or npm global \u2014 no current/ symlink\n content = `#!/usr/bin/env bash\n# Resolve abmind CLI \u2014 no ~/.abmind/current dependency (#863)\nBUNDLE_CLI=\"$HOME/.abtars/app/bundle/node_modules/abmind/dist/cli/abmind.js\"\nSRC_CLI=\"$HOME/.abtars/src/abmind/dist/cli/abmind.js\"\nGLOBAL_CLI=\"$(npm root -g 2>/dev/null)/abmind/dist/cli/abmind.js\"\nif [ -f \"$BUNDLE_CLI\" ]; then\n exec node \"$BUNDLE_CLI\" \"$@\"\nelif [ -f \"$SRC_CLI\" ]; then\n exec node \"$SRC_CLI\" \"$@\"\nelif [ -f \"$GLOBAL_CLI\" ]; then\n exec node \"$GLOBAL_CLI\" \"$@\"\nelse\n echo \"abmind: not found. Install via npm or deploy via abtars update.\" >&2\n exit 1\nfi\n`;\n } else {\n const target = join(currentLink, 'bundle', bundleFile);\n const distFile = name === 'abtars' ? 'abtars.js' : `${name}.js`;\n const fallback = join(currentLink, 'dist', 'cli', distFile);\n content = `#!/usr/bin/env bash\nif [ -f \"${target}\" ]; then\n exec node \"${target}\" \"$@\"\nelif [ -f \"${fallback}\" ]; then\n exec node \"${fallback}\" \"$@\"\nelse\n GLOBAL_BIN=\"$(npm root -g 2>/dev/null)/abtars/bundle/${bundleFile}\"\n if [ -f \"$GLOBAL_BIN\" ]; then\n exec node \"$GLOBAL_BIN\" \"$@\"\n fi\n echo \"abtars: no release staged. Run 'abtars install' first.\" >&2\n exit 1\nfi\n`;\n }\n const path = join(binDir, name);\n if (dryRun) {\n process.stdout.write(`[dry-run] write wrapper ${path}\\n`);\n return;\n }\n await writeFile(path, content, { mode: 0o755 });\n}\n\nfunction isPathOnPATH(userBinDir: string): boolean {\n const PATH = process.env['PATH'] ?? '';\n return PATH.split(':').some((p) => p === userBinDir);\n}\n\nexport async function install(opts: InstallOptions): Promise<number> {\n const paths = packagePaths('abtars');\n const home = paths.home;\n const userBinDir = resolveUserBinDir();\n const repoRoot = process.cwd();\n\n // Install log (#718)\n const { initInstallLog, logInstall, logInstallHeader } = await import(\"../install-log.js\");\n initInstallLog(home);\n logInstallHeader(\"install\");\n const _origWrite = process.stdout.write.bind(process.stdout);\n process.stdout.write = ((chunk: any, ...args: any[]) => {\n if (typeof chunk === \"string\" && (chunk.startsWith(\"\u2713\") || chunk.startsWith(\"\u26A0\"))) logInstall(chunk.trimEnd());\n return _origWrite(chunk, ...args);\n }) as typeof process.stdout.write;\n\n const homeExists = await exists(home);\n const manifest = homeExists ? await readManifest(paths.manifest) : null;\n\n if (homeExists && manifest && !opts.force && !opts.restore) {\n process.stderr.write(\n `~/.abtars already installed at version ${manifest.version || '(unset)'}.\\nUse 'abtars update' to upgrade, or --force to re-seed missing config.\\n`,\n );\n return 2;\n }\n\n // Kill stale daemon/watchdog from previous install (#771)\n try {\n const { execSync } = await import(\"node:child_process\");\n execSync(\"systemctl is-active abtars 2>/dev/null\", { stdio: \"ignore\" });\n execSync(\"sudo -n systemctl stop abtars 2>/dev/null\", { stdio: \"ignore\" });\n execSync(\"sudo -n systemctl disable abtars 2>/dev/null\", { stdio: \"ignore\" });\n } catch { /* not running or no sudo \u2014 fine */ }\n try {\n const { execSync } = await import(\"node:child_process\");\n execSync(\"pkill -f 'watchdog.sh' 2>/dev/null\", { stdio: \"ignore\" });\n } catch { /* no watchdog \u2014 fine */ }\n\n // Create skeleton (idempotent)\n await createSkeleton(home, opts.dryRun);\n process.stdout.write(`\u2713 skeleton at ${home}\\n`);\n\n // Core templates: abmind seeds its own on first boot (#427 ensureInitialized).\n // No longer seeded by abtars install.\n\n // Create kiro-cli agent config \u2014 ACP transport needs ~/.kiro/agents/professor.json\n const kiroAgentsDir = join(homedir(), '.kiro', 'agents');\n const professorJson = join(kiroAgentsDir, 'professor.json');\n if (!opts.dryRun) {\n await mkdir(kiroAgentsDir, { recursive: true });\n if (!(await exists(professorJson))) {\n await writeFile(professorJson, JSON.stringify({\n name: \"professor\",\n description: \"Abtars bridge agent\",\n tools: [\"*\"],\n allowedTools: [\"@builtin\"],\n toolsSettings: { shell: { autoAllowReadonly: true } },\n includeMcpJson: true,\n }, null, 2) + '\\n');\n process.stdout.write(`\u2713 kiro agent: ${professorJson}\\n`);\n }\n } else {\n process.stdout.write(`[dry-run] create ${professorJson}\\n`);\n }\n\n // Generate Ed25519 identity keypair (skip if already exists)\n const identityKey = join(paths.config, 'identity.key');\n const identityPub = join(paths.config, 'identity.pub');\n if (!opts.dryRun && !(await exists(identityKey))) {\n const { generateKeyPairSync } = await import('node:crypto');\n const { privateKey, publicKey } = generateKeyPairSync('ed25519');\n await writeFile(identityKey, privateKey.export({ format: 'der', type: 'pkcs8' }).toString('base64'));\n await writeFile(identityPub, publicKey.export({ format: 'der', type: 'spki' }).toString('base64'));\n const { chmodSync } = await import('node:fs');\n chmodSync(identityKey, 0o600);\n process.stdout.write(`\u2713 identity keypair generated\\n`);\n }\n\n // Generate self-signed Ed25519 TLS certificate (skip if already exists)\n const identityCrt = join(paths.config, 'identity.crt');\n const identityTlsKey = join(paths.config, 'identity.tls.key');\n if (!opts.dryRun && !(await exists(identityCrt))) {\n const { execSync } = await import('node:child_process');\n const { chmodSync } = await import('node:fs');\n const agentName = hostname();\n try {\n execSync(`openssl req -x509 -newkey ed25519 -keyout identity.tls.key -out identity.crt -days 3650 -nodes -subj \"/CN=${agentName}\"`, { cwd: paths.config, stdio: 'ignore' });\n chmodSync(identityTlsKey, 0o600);\n process.stdout.write(`\u2713 TLS certificate generated (Ed25519, 10yr)\\n`);\n } catch (err) {\n process.stderr.write(`\u26A0 TLS cert generation failed (openssl not found?). Agent-api will start without TLS.\\n`);\n }\n }\n\n // Seed config from examples (only missing ones)\n const seeded = await seedConfig(repoRoot, paths.config, opts.dryRun, home);\n if (seeded.length > 0) {\n process.stdout.write(`\u2713 seeded config: ${seeded.join(', ')}\\n`);\n }\n\n // Write wrappers (always overwrite \u2014 they're regenerable thin shims)\n const { loadManifest: loadInstallManifest } = await import('../install-manifest.js');\n const installManifest = loadInstallManifest(repoRoot);\n if (!opts.dryRun) {\n await mkdir(paths.bin, { recursive: true });\n }\n for (const name of installManifest.cliWrappers) {\n await writeWrapper(paths.bin, name, paths.current, opts.dryRun);\n }\n process.stdout.write(`\u2713 wrappers in ${paths.bin}\\n`);\n\n // Reconcile PATH symlinks\n if (!opts.dryRun) await mkdir(userBinDir, { recursive: true });\n const refused: string[] = [];\n for (const name of installManifest.cliWrappers) {\n const r = await reconcilePathLink(paths.bin, userBinDir, name, opts.force, opts.dryRun);\n if (r.action === 'refused') {\n refused.push(r.message ?? name);\n }\n }\n if (refused.length > 0) {\n process.stderr.write(`\\nPATH symlink conflicts:\\n ${refused.join('\\n ')}\\n`);\n } else {\n process.stdout.write(`\u2713 PATH symlinks in ${userBinDir}\\n`);\n }\n\n // Warn if ~/.local/bin not on PATH\n if (!isPathOnPATH(userBinDir)) {\n process.stderr.write(\n `\\nWarning: ${userBinDir} is not on $PATH. Add to your shell config:\\n export PATH=\"${userBinDir}:$PATH\"\\n`,\n );\n }\n\n // Initialize manifest if brand-new install AND migration didn't write one.\n // (Migration 003 writes a manifest mid-flow with version + migration record;\n // we must not clobber it here.)\n const manifestAfter = await readManifest(paths.manifest);\n if (manifestAfter === null && !opts.dryRun) {\n await writeManifest(paths.manifest, {\n ...emptyManifest('abtars', hostname()),\n version: '',\n });\n process.stdout.write(`\u2713 manifest initialized at ${paths.manifest}\\n`);\n }\n\n // Write install mode to manifest. Priority:\n // 1. --mode flag (explicit) \u2014 always wins\n // 2. existing manifest installMode \u2014 preserved (don't clobber on --force)\n // 3. default: supervised\n const manifestForMode = await readManifest(paths.manifest);\n const existingMode = manifestForMode?.installMode;\n const mode = opts.mode ?? existingMode ?? \"supervised\";\n if (manifestForMode) {\n await writeManifest(paths.manifest, { ...manifestForMode, installMode: mode });\n }\n process.stdout.write(`\u2713 install mode: ${mode}\\n`);\n\n // Release staging is handled by `abtars update` (auto-detects npm vs git source)\n\n // Restore from backup zip\n if (opts.restore) {\n const { spawnSync } = await import('node:child_process');\n const { existsSync: fileExists } = await import('node:fs');\n const zipPath = opts.restore;\n if (!fileExists(zipPath)) {\n process.stderr.write(`error: backup file not found: ${zipPath}\\n`);\n return 1;\n }\n // Extract to temp dir\n const tmpDir = join(process.env['TMPDIR'] ?? '/tmp', `abtars-restore-${Date.now()}`);\n const is7z = zipPath.endsWith('.7z');\n const extractCmd = is7z\n ? spawnSync('7z', ['x', zipPath, `-o${tmpDir}`, '-y'], { encoding: 'utf-8' })\n : spawnSync('unzip', ['-o', zipPath, '-d', tmpDir], { encoding: 'utf-8' });\n if (extractCmd.status !== 0) {\n process.stderr.write(`error: extract failed: ${extractCmd.stderr}\\n`);\n return 1;\n }\n // Copy abtars files \u2014 overwrite everything EXCEPT binaries (releases/, current, bin/)\n const abSrc = join(tmpDir, 'abtars');\n if (fileExists(abSrc)) {\n const skipSet = new Set(['releases', 'current', 'bin']);\n for (const f of readdirSync(abSrc)) {\n if (skipSet.has(f)) continue;\n spawnSync('cp', ['-r', join(abSrc, f), home], { stdio: 'inherit' });\n }\n process.stdout.write(`\u2713 restored abtars data\\n`);\n }\n // Copy abmind files\n const abmindHome = process.env['ABMIND_HOME'] ?? join(dirname(home), '.abmind');\n const abmindSrc = join(tmpDir, 'abmind');\n if (fileExists(abmindSrc)) {\n spawnSync('cp', ['-r', ...readdirSync(abmindSrc).map(f => join(abmindSrc, f)), abmindHome], { stdio: 'inherit' });\n process.stdout.write(`\u2713 restored abmind data\\n`);\n }\n // Cleanup + resync\n spawnSync('rm', ['-rf', tmpDir]);\n process.stdout.write(`\\n\u2713 Restore complete. Run 'abtars update' to resync.\\n`);\n return 0;\n }\n\n // --- supervised: load user-scope watchdog (LaunchAgent / systemd user) ---\n if (mode === 'supervised') {\n const { execSync } = await import('node:child_process');\n if (process.platform === 'darwin') {\n const plistSrc = join(home, 'scripts', 'com.abtars.watchdog.plist');\n const plistDst = join(homedir(), 'Library', 'LaunchAgents', 'com.abtars.watchdog.plist');\n if (existsSync(plistSrc)) {\n const content = readFileSync(plistSrc, 'utf-8').replaceAll('{{HOME}}', homedir());\n const { writeFileSync } = await import('node:fs');\n writeFileSync(plistDst, content);\n try { execSync(`launchctl load \"${plistDst}\"`, { stdio: 'ignore' }); } catch { /* already loaded */ }\n process.stdout.write(`\u2713 watchdog LaunchAgent loaded\\n`);\n }\n } else if (process.platform === 'linux') {\n const unitSrc = join(home, 'scripts', 'abtars-watchdog.service');\n const unitDir = join(homedir(), '.config', 'systemd', 'user');\n if (existsSync(unitSrc)) {\n mkdirSync(unitDir, { recursive: true });\n copyFileSync(unitSrc, join(unitDir, 'abtars-watchdog.service'));\n try { execSync('systemctl --user daemon-reload && systemctl --user enable --now abtars-watchdog', { stdio: 'ignore' }); } catch { /* may fail in chroot */ }\n process.stdout.write(`\u2713 watchdog systemd user service enabled\\n`);\n }\n }\n }\n\n process.stdout.write(`\\nInstall complete.\\n`);\n if (!manifestAfter || manifestAfter.version === '') {\n process.stdout.write(`Next: 'abtars update' to build and activate the first release.\\n`);\n } else {\n process.stdout.write(`\\n\u2500\u2500 Next steps \u2500\u2500\\n`);\n process.stdout.write(` 1. Run 'abtars onboard' to configure Telegram token + model provider\\n`);\n process.stdout.write(` 2. (Optional) Install Ollama for memory embeddings: curl -fsSL https://ollama.com/install.sh | sh\\n`);\n process.stdout.write(` 3. Start the bridge: 'abtars restart' or use the watchdog\\n\\n`);\n }\n\n const { printHealthSummary } = await import('./health-check.js');\n printHealthSummary(paths.home);\n\n // #334: Post-install healthcheck \u2014 validate operator channel exists (only on --restore)\n if (!opts.dryRun && opts.restore) {\n const { validateMinimumViability, formatValidationError } = await import('./install-validate.js');\n const validation = validateMinimumViability(paths.config);\n if (!validation.ok) {\n const invocation = `abtars install --restore ${opts.restore}`;\n process.stderr.write(\"\\n\" + formatValidationError(validation, invocation) + \"\\n\");\n return 1;\n }\n }\n\n return 0;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["execSync"]
7
+ }
@@ -211,4 +211,4 @@ export {
211
211
  register,
212
212
  sleep_exports
213
213
  };
214
- //# sourceMappingURL=chunk-N24ROESF.js.map
214
+ //# sourceMappingURL=chunk-HFPXN6NM.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/capabilities/sleep/index.ts"],
4
+ "sourcesContent": ["import { logAndSwallow } from \"../../components/log-and-swallow.js\";\nimport { getEnv } from \"../../components/env-schema.js\";\nimport type { CapabilityApi } from \"../capability.js\";\n/**\n * Sleep capability \u2014 spawn nightly sleep cycle via tick system.\n * One path: BED_TIME + quiet ticks \u2192 Dreamy \u2192 quiet ticks \u2192 hardware sleep.\n * Parses PROGRESS:<pct>:<label> from stdout for visibility.\n */\n\nimport { execSync } from \"node:child_process\";\nimport { writeSleepStatus, readAndClearForceSleep } from \"../../components/transport/bridge-lock-transport.js\";\nimport { join } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport type { Level } from \"abmind\";\nimport { abmind } from \"../../utils/abmind-lazy.js\";\nimport type { SleepRuntime } from \"abmind\";\nimport { logInfo, logWarn, logDebug } from \"../../components/logger.js\";\nimport { readEnv, readEnvWithDefault } from \"../../components/env.js\";\n\nexport interface SleepOpts {\n sleepHour: number;\n sleepAuditDir: string;\n memoryEnabled: boolean;\n memoryDir?: string;\n /** LLM runtime adapter \u2014 bridge wraps its SubagentRuntime.complete(\"dreamy\", ...). */\n runtime: SleepRuntime;\n onComplete: () => void;\n getLastMsgTs?: () => number;\n sendSystemMessage?: (prompt: string) => Promise<void>;\n killWakeInhibit?: () => void;\n}\n\nexport interface SleepProgress {\n percent: number;\n step: string;\n}\n\nexport interface SleepHandle {\n /** True while a sleep cycle is running in-process. */\n readonly isActive: boolean;\n readonly progress: SleepProgress | null;\n readonly awaitingHwSleep: boolean;\n spawn(): void;\n /** Called by tick system to check if hardware sleep should fire. */\n checkHwSleep(): void;\n}\n\nconst MAX_RETRIES = 3;\nconst RETRY_MS = 5 * 60 * 1000;\n\nexport function createSleepHandle(opts: SleepOpts): SleepHandle {\n let running = false;\n let attempts = 0;\n let progress: SleepProgress | null = null;\n let _awaitingHwSleep = false;\n // Post-Dreamy hw-sleep quiet-tick tracking (internal to this closure \u2014 decoupled from\n // daily-cycle.quietTickCount which freezes once hasSleepAuditToday returns true).\n // Both reset when _awaitingHwSleep flips to true (see the onComplete handler below).\n let postSleepQuietTicks = 0;\n let lastMsgTsSeenByHwCheck = 0;\n\n function buildDreamReport(): string {\n let dreamReport = \"Dreamy finished nightly maintenance.\";\n try {\n const sleepDir = join(opts.memoryDir ?? \"\", \"sleep\");\n const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, \"\");\n const lockPath = join(sleepDir, `sleep_${dateStr}.lock`);\n if (existsSync(lockPath)) {\n const lockData = JSON.parse(readFileSync(lockPath, \"utf-8\")) as { steps: Record<string, { status: string }>; llmCalls?: number };\n const ok = Object.entries(lockData.steps).filter(([, s]) => s.status === \"ok\").map(([k]) => k);\n const skipped = Object.entries(lockData.steps).filter(([, s]) => s.status === \"skipped\").map(([k]) => k);\n const failed = Object.entries(lockData.steps).filter(([, s]) => s.status === \"failed\" || s.status === \"timeout\").map(([k]) => k);\n dreamReport = `Dreamy finished nightly maintenance (${lockData.llmCalls ?? \"?\"} LLM calls). Completed: ${ok.join(\", \") || \"none\"}.`;\n if (skipped.length > 0) dreamReport += ` Skipped: ${skipped.join(\", \")}.`;\n if (failed.length > 0) dreamReport += ` \u26A0\uFE0F FAILED: ${failed.join(\", \")}. Please review.`;\n }\n } catch (err) { logAndSwallow(\"index\", \"op\", err); }\n return dreamReport;\n }\n\n function spawnSleep(): void {\n const forceSleep = readAndClearForceSleep();\n const forced = forceSleep !== null;\n if (forced) {\n logInfo(\"sleep\", `\u26A1 forceSleep=${forceSleep} \u2014 bypassing time-window + audit-today guards`);\n }\n\n if (!forced) {\n const hour = new Date().getHours();\n const WAKE_HOUR = parseInt(readEnvWithDefault(\"WAKE_TIME\", \"7\", \"wake hour\").split(\":\")[0] ?? \"7\", 10);\n if (opts.sleepHour <= WAKE_HOUR) {\n if (hour < opts.sleepHour || hour >= WAKE_HOUR) {\n logDebug(\"sleep\", `\uD83D\uDE34 Outside sleep window (${opts.sleepHour}:00-${WAKE_HOUR}:00) \u2014 skip`);\n return;\n }\n } else {\n if (hour < opts.sleepHour && hour >= WAKE_HOUR) {\n logDebug(\"sleep\", `\uD83D\uDE34 Outside sleep window (${opts.sleepHour}:00-${WAKE_HOUR}:00) \u2014 skip`);\n return;\n }\n }\n if (abmind()?.hasSleepAuditToday(opts.sleepAuditDir)) {\n logDebug(\"sleep\", \"\uD83D\uDE34 Sleep already done today \u2014 skip\");\n return;\n }\n }\n if (running) return;\n attempts++;\n progress = null;\n running = true;\n writeSleepStatus(\"sleeping\");\n logInfo(\"sleep\", `\uD83D\uDE34 Sleep started in-process (attempt ${attempts}, model=dreamy)`);\n\n const level = (() => {\n if (forced && forceSleep?.includes(\"fresh\")) return \"ultimate\" as Level;\n const raw = getEnv().sleepQuality;\n if (!raw) return abmind()!.DEFAULT_LEVEL;\n try { return abmind()!.parseLevel(raw); }\n catch (err) { logWarn(\"sleep\", `Invalid SLEEP_QUALITY='${raw}', using ${abmind()!.DEFAULT_LEVEL}: ${err instanceof Error ? err.message : String(err)}`); return abmind()!.DEFAULT_LEVEL; }\n })();\n\n abmind()!.runSleepCycle({ runtime: opts.runtime, level })\n .then(async (result: { ok: boolean; failCount: number }) => {\n running = false;\n progress = null;\n logInfo(\"sleep\", `\uD83D\uDE34 Sleep finished (ok=${result.ok}, failCount=${result.failCount}, attempt ${attempts})`);\n writeSleepStatus(\"awake\");\n if (!result.ok) {\n if (attempts < MAX_RETRIES) {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep had ${result.failCount} failures (attempt ${attempts}/${MAX_RETRIES}) \u2014 retry in 5min`);\n setTimeout(spawnSleep, RETRY_MS);\n } else {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep failures persist \u2014 exhausted ${MAX_RETRIES} attempts`);\n }\n return;\n }\n\n if (opts.memoryEnabled) opts.onComplete();\n\n // Force-sleep runs are explicit test/verify triggers \u2014 skip hw-sleep even if env enabled.\n const hwEnabled = !forced && readEnv(\"HARDWARE_SLEEP_AFTER_DREAMY\", \"hardware sleep after Dreamy disabled\") === \"true\";\n const quietTicks = Math.ceil(getEnv().bedQuietMin * 60 / parseInt(readEnvWithDefault(\"HEARTBEAT_INTERVAL_SEC\", \"60\", \"hb\"), 10));\n const hbInterval = parseInt(readEnvWithDefault(\"HEARTBEAT_INTERVAL_SEC\", \"60\", \"heartbeat tick interval\"), 10);\n const hwSleepMin = Math.round(quietTicks * hbInterval / 60);\n\n const dreamReport = buildDreamReport();\n const sleepNote = hwEnabled ? ` Hardware sleep in ~${hwSleepMin} minutes if no activity.` : \"\";\n\n // #844: buffer silently \u2014 don't trigger model response\n const { bufferSystemEvent } = await import(\"../../components/system-event-buffer.js\");\n bufferSystemEvent(`${dreamReport}${sleepNote}`);\n\n if (hwEnabled) {\n _awaitingHwSleep = true;\n // Reset hw-check counters \u2014 prevents stale state from a prior cycle (crash, force-sleep\n // re-run) from poisoning this one, and avoids burning the first tick on a spurious\n // reset when the very first checkHwSleep() sees currentMsgTs > 0.\n postSleepQuietTicks = 0;\n lastMsgTsSeenByHwCheck = opts.getLastMsgTs?.() ?? 0;\n logInfo(\"sleep\", `\uD83D\uDCA4 Awaiting hardware sleep \u2014 ${quietTicks} quiet ticks (${hwSleepMin} min) required`);\n }\n })\n .catch((err: unknown) => {\n running = false;\n progress = null;\n writeSleepStatus(\"awake\");\n const msg = err instanceof Error ? err.message : String(err);\n if (attempts < MAX_RETRIES) {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep threw (attempt ${attempts}/${MAX_RETRIES}): ${msg} \u2014 retry in 5min`);\n setTimeout(spawnSleep, RETRY_MS);\n } else {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep threw \u2014 exhausted ${MAX_RETRIES} attempts: ${msg}`);\n }\n });\n }\n\n function checkHwSleep(): void {\n if (!_awaitingHwSleep) return;\n\n // Sleep-window cutoff \u2014 give up if we've crossed out of the window. Next night retries.\n // Mirrors spawnSleep()'s window logic for consistency.\n const WAKE_HOUR = parseInt(readEnvWithDefault(\"WAKE_TIME\", \"7\", \"wake hour\").split(\":\")[0] ?? \"7\", 10);\n const BED_HOUR = opts.sleepHour;\n const hour = new Date().getHours();\n const inSleepWindow = (BED_HOUR < WAKE_HOUR)\n ? (hour >= BED_HOUR && hour < WAKE_HOUR) // normal: BED=00:30, WAKE=07:00 \u2192 sleep 00-06\n : (hour >= BED_HOUR || hour < WAKE_HOUR); // overnight: BED=23:00, WAKE=07:00 \u2192 sleep 23-06\n if (!inSleepWindow) {\n logInfo(\"sleep\", `\u23F0 Past sleep window (now ${hour}:00, window ${BED_HOUR}:00-${WAKE_HOUR}:00) \u2014 abandoning hw-sleep attempt`);\n _awaitingHwSleep = false;\n postSleepQuietTicks = 0;\n return;\n }\n\n // User messaged since last check \u2014 postpone and reset\n const currentMsgTs = opts.getLastMsgTs?.() ?? 0;\n if (currentMsgTs > lastMsgTsSeenByHwCheck) {\n lastMsgTsSeenByHwCheck = currentMsgTs;\n postSleepQuietTicks = 0;\n logInfo(\"sleep\", \"\uD83D\uDCA4 Hardware sleep postponed \u2014 user messaged (will retry after quiet period)\");\n return;\n }\n\n // Quiet tick \u2014 increment\n const requiredTicks = Math.ceil(getEnv().bedQuietMin * 60 / parseInt(process.env[\"HEARTBEAT_INTERVAL_SEC\"] ?? \"60\", 10));\n postSleepQuietTicks++;\n if (postSleepQuietTicks < requiredTicks) return;\n\n // Threshold reached \u2014 sleep\n _awaitingHwSleep = false;\n postSleepQuietTicks = 0;\n // Kill any wake inhibitor from /wakeup before sleeping\n opts.killWakeInhibit?.();\n const sleepCmd = process.platform === \"darwin\" ? \"pmset sleepnow\" : \"systemctl suspend\";\n logInfo(\"sleep\", `\uD83D\uDCA4 Putting hardware to sleep (${sleepCmd})...`);\n writeSleepStatus(\"hw_sleep\");\n try { execSync(sleepCmd, { timeout: 5000 }); }\n catch (err) {\n writeSleepStatus(\"awake\"); // recover \u2014 don't leave \"hw_sleep\" if pmset failed\n logWarn(\"sleep\", `\uD83D\uDCA4 Hardware sleep failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n get isActive() { return running; },\n get progress() { return progress; },\n get awaitingHwSleep() { return _awaitingHwSleep; },\n spawn: spawnSleep,\n checkHwSleep,\n };\n}\n\n/** Capability registration \u2014 called by discoverCapabilities(). */\nexport function register(_api: CapabilityApi): void {\n // Sleep registration is a no-op here \u2014 the actual SleepHandle is created\n // in phase-sleep.ts because it needs ctx.sendSystemMessage + memory deps\n // that aren't available at capability discovery time.\n // This manifest exists so sleep appears in discoverCapabilities() and\n // can be disabled via DISABLED_CAPABILITIES=sleep.\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }