@loompad/cli 0.1.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 (177) hide show
  1. package/ARCHITECTURE.md +211 -0
  2. package/CHANGELOG.md +470 -0
  3. package/LICENSE +21 -0
  4. package/README.md +630 -0
  5. package/dist/adapters/base.d.ts +71 -0
  6. package/dist/adapters/base.js +187 -0
  7. package/dist/adapters/base.js.map +1 -0
  8. package/dist/adapters/bridges/antigravity.d.ts +53 -0
  9. package/dist/adapters/bridges/antigravity.js +106 -0
  10. package/dist/adapters/bridges/antigravity.js.map +1 -0
  11. package/dist/adapters/bridges/cdp.d.ts +82 -0
  12. package/dist/adapters/bridges/cdp.js +222 -0
  13. package/dist/adapters/bridges/cdp.js.map +1 -0
  14. package/dist/adapters/bridges/gui-chat.d.ts +113 -0
  15. package/dist/adapters/bridges/gui-chat.js +498 -0
  16. package/dist/adapters/bridges/gui-chat.js.map +1 -0
  17. package/dist/adapters/bridges/kiro.d.ts +19 -0
  18. package/dist/adapters/bridges/kiro.js +22 -0
  19. package/dist/adapters/bridges/kiro.js.map +1 -0
  20. package/dist/adapters/bridges/profiles.d.ts +82 -0
  21. package/dist/adapters/bridges/profiles.js +125 -0
  22. package/dist/adapters/bridges/profiles.js.map +1 -0
  23. package/dist/adapters/claude-code.d.ts +26 -0
  24. package/dist/adapters/claude-code.js +209 -0
  25. package/dist/adapters/claude-code.js.map +1 -0
  26. package/dist/adapters/codex.d.ts +51 -0
  27. package/dist/adapters/codex.js +291 -0
  28. package/dist/adapters/codex.js.map +1 -0
  29. package/dist/adapters/echo.d.ts +20 -0
  30. package/dist/adapters/echo.js +79 -0
  31. package/dist/adapters/echo.js.map +1 -0
  32. package/dist/adapters/grok.d.ts +61 -0
  33. package/dist/adapters/grok.js +217 -0
  34. package/dist/adapters/grok.js.map +1 -0
  35. package/dist/adapters/index.d.ts +9 -0
  36. package/dist/adapters/index.js +33 -0
  37. package/dist/adapters/index.js.map +1 -0
  38. package/dist/adapters/opencode.d.ts +64 -0
  39. package/dist/adapters/opencode.js +426 -0
  40. package/dist/adapters/opencode.js.map +1 -0
  41. package/dist/cli/common.d.ts +11 -0
  42. package/dist/cli/common.js +40 -0
  43. package/dist/cli/common.js.map +1 -0
  44. package/dist/cli/doctor.d.ts +12 -0
  45. package/dist/cli/doctor.js +181 -0
  46. package/dist/cli/doctor.js.map +1 -0
  47. package/dist/cli/index.d.ts +8 -0
  48. package/dist/cli/index.js +641 -0
  49. package/dist/cli/index.js.map +1 -0
  50. package/dist/cli/tui-model.d.ts +73 -0
  51. package/dist/cli/tui-model.js +312 -0
  52. package/dist/cli/tui-model.js.map +1 -0
  53. package/dist/cli/tui.d.ts +15 -0
  54. package/dist/cli/tui.js +451 -0
  55. package/dist/cli/tui.js.map +1 -0
  56. package/dist/cli/ui.d.ts +10 -0
  57. package/dist/cli/ui.js +135 -0
  58. package/dist/cli/ui.js.map +1 -0
  59. package/dist/core/ades.d.ts +79 -0
  60. package/dist/core/ades.js +130 -0
  61. package/dist/core/ades.js.map +1 -0
  62. package/dist/core/baton.d.ts +37 -0
  63. package/dist/core/baton.js +92 -0
  64. package/dist/core/baton.js.map +1 -0
  65. package/dist/core/brain-extract.d.ts +111 -0
  66. package/dist/core/brain-extract.js +248 -0
  67. package/dist/core/brain-extract.js.map +1 -0
  68. package/dist/core/brain-index.d.ts +128 -0
  69. package/dist/core/brain-index.js +338 -0
  70. package/dist/core/brain-index.js.map +1 -0
  71. package/dist/core/brain.d.ts +214 -0
  72. package/dist/core/brain.js +425 -0
  73. package/dist/core/brain.js.map +1 -0
  74. package/dist/core/claude-cli.d.ts +12 -0
  75. package/dist/core/claude-cli.js +47 -0
  76. package/dist/core/claude-cli.js.map +1 -0
  77. package/dist/core/distill.d.ts +19 -0
  78. package/dist/core/distill.js +88 -0
  79. package/dist/core/distill.js.map +1 -0
  80. package/dist/core/eventlog.d.ts +43 -0
  81. package/dist/core/eventlog.js +211 -0
  82. package/dist/core/eventlog.js.map +1 -0
  83. package/dist/core/git.d.ts +203 -0
  84. package/dist/core/git.js +460 -0
  85. package/dist/core/git.js.map +1 -0
  86. package/dist/core/logbook.d.ts +59 -0
  87. package/dist/core/logbook.js +118 -0
  88. package/dist/core/logbook.js.map +1 -0
  89. package/dist/core/memory.d.ts +34 -0
  90. package/dist/core/memory.js +124 -0
  91. package/dist/core/memory.js.map +1 -0
  92. package/dist/core/notify.d.ts +11 -0
  93. package/dist/core/notify.js +30 -0
  94. package/dist/core/notify.js.map +1 -0
  95. package/dist/core/projection.d.ts +20 -0
  96. package/dist/core/projection.js +96 -0
  97. package/dist/core/projection.js.map +1 -0
  98. package/dist/core/registry.d.ts +76 -0
  99. package/dist/core/registry.js +147 -0
  100. package/dist/core/registry.js.map +1 -0
  101. package/dist/core/router.d.ts +42 -0
  102. package/dist/core/router.js +99 -0
  103. package/dist/core/router.js.map +1 -0
  104. package/dist/core/routes.d.ts +93 -0
  105. package/dist/core/routes.js +399 -0
  106. package/dist/core/routes.js.map +1 -0
  107. package/dist/core/search.d.ts +63 -0
  108. package/dist/core/search.js +0 -0
  109. package/dist/core/search.js.map +1 -0
  110. package/dist/core/setup.d.ts +70 -0
  111. package/dist/core/setup.js +250 -0
  112. package/dist/core/setup.js.map +1 -0
  113. package/dist/core/suggestions.d.ts +15 -0
  114. package/dist/core/suggestions.js +38 -0
  115. package/dist/core/suggestions.js.map +1 -0
  116. package/dist/core/worktree.d.ts +32 -0
  117. package/dist/core/worktree.js +83 -0
  118. package/dist/core/worktree.js.map +1 -0
  119. package/dist/daemon/app-page.d.ts +32 -0
  120. package/dist/daemon/app-page.js +6363 -0
  121. package/dist/daemon/app-page.js.map +1 -0
  122. package/dist/daemon/auth.d.ts +51 -0
  123. package/dist/daemon/auth.js +135 -0
  124. package/dist/daemon/auth.js.map +1 -0
  125. package/dist/daemon/board.d.ts +117 -0
  126. package/dist/daemon/board.js +202 -0
  127. package/dist/daemon/board.js.map +1 -0
  128. package/dist/daemon/brand-icons.d.ts +29 -0
  129. package/dist/daemon/brand-icons.js +44 -0
  130. package/dist/daemon/brand-icons.js.map +1 -0
  131. package/dist/daemon/client.d.ts +127 -0
  132. package/dist/daemon/client.js +237 -0
  133. package/dist/daemon/client.js.map +1 -0
  134. package/dist/daemon/geist-font.d.ts +10 -0
  135. package/dist/daemon/geist-font.js +783 -0
  136. package/dist/daemon/geist-font.js.map +1 -0
  137. package/dist/daemon/guards.d.ts +18 -0
  138. package/dist/daemon/guards.js +40 -0
  139. package/dist/daemon/guards.js.map +1 -0
  140. package/dist/daemon/linear.d.ts +59 -0
  141. package/dist/daemon/linear.js +117 -0
  142. package/dist/daemon/linear.js.map +1 -0
  143. package/dist/daemon/push.d.ts +22 -0
  144. package/dist/daemon/push.js +58 -0
  145. package/dist/daemon/push.js.map +1 -0
  146. package/dist/daemon/runtime.d.ts +299 -0
  147. package/dist/daemon/runtime.js +1016 -0
  148. package/dist/daemon/runtime.js.map +1 -0
  149. package/dist/daemon/server.d.ts +125 -0
  150. package/dist/daemon/server.js +1728 -0
  151. package/dist/daemon/server.js.map +1 -0
  152. package/dist/daemon/tasks.d.ts +153 -0
  153. package/dist/daemon/tasks.js +264 -0
  154. package/dist/daemon/tasks.js.map +1 -0
  155. package/dist/daemon/terminals.d.ts +82 -0
  156. package/dist/daemon/terminals.js +372 -0
  157. package/dist/daemon/terminals.js.map +1 -0
  158. package/dist/index.d.ts +20 -0
  159. package/dist/index.js +20 -0
  160. package/dist/index.js.map +1 -0
  161. package/dist/sdk.d.ts +17 -0
  162. package/dist/sdk.js +17 -0
  163. package/dist/sdk.js.map +1 -0
  164. package/dist/types.d.ts +236 -0
  165. package/dist/types.js +18 -0
  166. package/dist/types.js.map +1 -0
  167. package/docs/SETUP.md +265 -0
  168. package/docs/adapters.md +132 -0
  169. package/docs/design-system.md +245 -0
  170. package/docs/img/board-linear.png +0 -0
  171. package/docs/img/board-projects.png +0 -0
  172. package/docs/img/brain.png +0 -0
  173. package/docs/img/settings.png +0 -0
  174. package/docs/img/workspace.png +0 -0
  175. package/docs/integration-notes.md +76 -0
  176. package/docs/proposals/brain.md +262 -0
  177. package/package.json +84 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geist-font.js","sourceRoot":"","sources":["../../src/daemon/geist-font.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,kBAAkB,GACtB,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,0HAA0H;IAC1H,kEAAkE,CAAC;AAErE,MAAM,CAAC,MAAM,WAAW,GAAW,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Crash guards for a long-running daemon.
3
+ *
4
+ * The daemon holds every project's runtime, every PTY, and every connected
5
+ * client. Node terminates the process on an unhandled rejection, so before
6
+ * this existed one stray promise anywhere — an adapter, a `gh` call, a push —
7
+ * took all of that down at once. And because `loom up` spawned it with
8
+ * stdio:"ignore", it did so without leaving a single byte to read.
9
+ *
10
+ * The trade is deliberate: a daemon that survives a bad turn is worth more
11
+ * than one that exits cleanly on it. Nothing here swallows quietly — every
12
+ * caught fault is written where `loom up` is pointing (~/.loom/daemon.log).
13
+ */
14
+ /**
15
+ * Keep the process alive through faults it would otherwise die on.
16
+ * Returns a teardown so tests can install and remove it.
17
+ */
18
+ export declare function installCrashGuards(): () => void;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Crash guards for a long-running daemon.
3
+ *
4
+ * The daemon holds every project's runtime, every PTY, and every connected
5
+ * client. Node terminates the process on an unhandled rejection, so before
6
+ * this existed one stray promise anywhere — an adapter, a `gh` call, a push —
7
+ * took all of that down at once. And because `loom up` spawned it with
8
+ * stdio:"ignore", it did so without leaving a single byte to read.
9
+ *
10
+ * The trade is deliberate: a daemon that survives a bad turn is worth more
11
+ * than one that exits cleanly on it. Nothing here swallows quietly — every
12
+ * caught fault is written where `loom up` is pointing (~/.loom/daemon.log).
13
+ */
14
+ import { logbook } from "../core/logbook.js";
15
+ /**
16
+ * Write a fault the same way whichever kind it is.
17
+ *
18
+ * Through the logbook, so it reaches the Console tab as well as the log file.
19
+ * A daemon that survives a fault silently is only half the fix — you'd never
20
+ * know the turn you're waiting on already died.
21
+ */
22
+ function report(kind, detail) {
23
+ const message = detail instanceof Error ? detail.message : String(detail);
24
+ logbook.error("daemon", `${kind}: ${message}`, detail);
25
+ }
26
+ /**
27
+ * Keep the process alive through faults it would otherwise die on.
28
+ * Returns a teardown so tests can install and remove it.
29
+ */
30
+ export function installCrashGuards() {
31
+ const onRejection = (reason) => report("unhandled rejection", reason);
32
+ const onException = (err) => report("uncaught exception", err);
33
+ process.on("unhandledRejection", onRejection);
34
+ process.on("uncaughtException", onException);
35
+ return () => {
36
+ process.off("unhandledRejection", onRejection);
37
+ process.off("uncaughtException", onException);
38
+ };
39
+ }
40
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/daemon/guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C;;;;;;GAMG;AACH,SAAS,MAAM,CAAC,IAAY,EAAE,MAAe;IAC3C,MAAM,OAAO,GAAG,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1E,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,IAAI,KAAK,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,WAAW,GAAG,CAAC,MAAe,EAAQ,EAAE,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IACrF,MAAM,WAAW,GAAG,CAAC,GAAU,EAAQ,EAAE,CAAC,MAAM,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;IAC5E,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;IAC7C,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Linear, through the user's own key — the same bet gh makes for GitHub. Loom
3
+ * holds no Linear token of its own: the personal API key lives in the daemon's
4
+ * environment (`LINEAR_API_KEY`, which the user exports), and this module reads
5
+ * it from `process.env` and hands it straight to Linear's GraphQL endpoint. It
6
+ * is never written to disk by us, never sent to a client, never logged.
7
+ *
8
+ * Everything degrades honestly: no key → `reason: "no-key"` with the one line a
9
+ * setup panel needs, not an empty team list that reads like "you have no teams".
10
+ */
11
+ export type LinearUnavailable = {
12
+ available: false;
13
+ reason: "no-key" | "auth" | "error";
14
+ detail: string;
15
+ };
16
+ export interface LinearTeam {
17
+ id: string;
18
+ key: string;
19
+ name: string;
20
+ }
21
+ export interface LinearIssue {
22
+ id: string;
23
+ identifier: string;
24
+ title: string;
25
+ state: string;
26
+ url: string;
27
+ assignee: string | null;
28
+ updatedAt: string;
29
+ }
30
+ export type LinearTeams = {
31
+ available: true;
32
+ teams: LinearTeam[];
33
+ };
34
+ export type LinearIssues = {
35
+ available: true;
36
+ issues: LinearIssue[];
37
+ };
38
+ export type LinearCreated = {
39
+ available: true;
40
+ issue: {
41
+ id: string;
42
+ identifier: string;
43
+ title: string;
44
+ url: string;
45
+ };
46
+ };
47
+ /** The key, from the daemon's environment — or null when it isn't set. */
48
+ export declare function linearKey(): string | null;
49
+ export declare function linearConfigured(): boolean;
50
+ /** The teams this key can see — the selector in the New issue form. */
51
+ export declare function linearTeams(): Promise<LinearTeams | LinearUnavailable>;
52
+ /** Recent issues, optionally scoped to one team — the Linear column's contents. */
53
+ export declare function listLinearIssues(teamId?: string): Promise<LinearIssues | LinearUnavailable>;
54
+ /** Create an issue on a team. The one write — gated behind a confirm in the UI. */
55
+ export declare function linearCreateIssue(input: {
56
+ teamId: string;
57
+ title: string;
58
+ description?: string;
59
+ }): Promise<LinearCreated | LinearUnavailable>;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Linear, through the user's own key — the same bet gh makes for GitHub. Loom
3
+ * holds no Linear token of its own: the personal API key lives in the daemon's
4
+ * environment (`LINEAR_API_KEY`, which the user exports), and this module reads
5
+ * it from `process.env` and hands it straight to Linear's GraphQL endpoint. It
6
+ * is never written to disk by us, never sent to a client, never logged.
7
+ *
8
+ * Everything degrades honestly: no key → `reason: "no-key"` with the one line a
9
+ * setup panel needs, not an empty team list that reads like "you have no teams".
10
+ */
11
+ const ENDPOINT = "https://api.linear.app/graphql";
12
+ /** The key, from the daemon's environment — or null when it isn't set. */
13
+ export function linearKey() {
14
+ const k = process.env.LINEAR_API_KEY?.trim();
15
+ return k || null;
16
+ }
17
+ export function linearConfigured() {
18
+ return linearKey() !== null;
19
+ }
20
+ const NO_KEY = {
21
+ available: false,
22
+ reason: "no-key",
23
+ detail: "Set LINEAR_API_KEY in the daemon's environment to enable Linear, then reload.",
24
+ };
25
+ /** One line for a setup panel, mapped from Linear's own error text. */
26
+ function classify(msg) {
27
+ const first = (msg.split("\n").find((l) => l.trim()) ?? msg).trim().slice(0, 300);
28
+ if (/authentication|unauthorized|invalid api key|401|403/i.test(first)) {
29
+ return { available: false, reason: "auth", detail: "LINEAR_API_KEY was rejected — check the key." };
30
+ }
31
+ return { available: false, reason: "error", detail: first };
32
+ }
33
+ async function gql(query, variables = {}) {
34
+ const key = linearKey();
35
+ if (!key)
36
+ throw new Error("no-key");
37
+ const res = await fetch(ENDPOINT, {
38
+ method: "POST",
39
+ headers: { "content-type": "application/json", authorization: key },
40
+ body: JSON.stringify({ query, variables }),
41
+ signal: AbortSignal.timeout(15_000),
42
+ });
43
+ const json = (await res.json());
44
+ if (json.errors?.length)
45
+ throw new Error(json.errors[0]?.message ?? "Linear error");
46
+ if (!res.ok || !json.data)
47
+ throw new Error(`HTTP ${res.status}`);
48
+ return json.data;
49
+ }
50
+ /** The teams this key can see — the selector in the New issue form. */
51
+ export async function linearTeams() {
52
+ if (!linearConfigured())
53
+ return NO_KEY;
54
+ try {
55
+ const data = await gql("query { teams(first: 100) { nodes { id key name } } }");
56
+ return { available: true, teams: data.teams.nodes };
57
+ }
58
+ catch (err) {
59
+ return classify(String(err.message));
60
+ }
61
+ }
62
+ /** Recent issues, optionally scoped to one team — the Linear column's contents. */
63
+ export async function listLinearIssues(teamId) {
64
+ if (!linearConfigured())
65
+ return NO_KEY;
66
+ try {
67
+ const filter = teamId ? { team: { id: { eq: teamId } } } : {};
68
+ const data = await gql(`query($filter: IssueFilter) {
69
+ issues(first: 50, filter: $filter, orderBy: updatedAt) {
70
+ nodes { id identifier title url updatedAt state { name } assignee { name } }
71
+ }
72
+ }`, { filter });
73
+ return {
74
+ available: true,
75
+ issues: data.issues.nodes.map((n) => ({
76
+ id: n.id,
77
+ identifier: n.identifier,
78
+ title: n.title,
79
+ url: n.url,
80
+ updatedAt: n.updatedAt,
81
+ state: n.state?.name ?? "",
82
+ assignee: n.assignee?.name ?? null,
83
+ })),
84
+ };
85
+ }
86
+ catch (err) {
87
+ return classify(String(err.message));
88
+ }
89
+ }
90
+ /** Create an issue on a team. The one write — gated behind a confirm in the UI. */
91
+ export async function linearCreateIssue(input) {
92
+ if (!linearConfigured())
93
+ return NO_KEY;
94
+ if (!input.teamId)
95
+ return { available: false, reason: "error", detail: "pick a team first" };
96
+ if (!input.title.trim())
97
+ return { available: false, reason: "error", detail: "an issue needs a title" };
98
+ try {
99
+ const data = await gql(`mutation($input: IssueCreateInput!) {
100
+ issueCreate(input: $input) { success issue { id identifier title url } }
101
+ }`, {
102
+ input: {
103
+ teamId: input.teamId,
104
+ title: input.title.trim(),
105
+ ...(input.description?.trim() ? { description: input.description.trim() } : {}),
106
+ },
107
+ });
108
+ if (!data.issueCreate.success || !data.issueCreate.issue) {
109
+ throw new Error("Linear declined to create the issue");
110
+ }
111
+ return { available: true, issue: data.issueCreate.issue };
112
+ }
113
+ catch (err) {
114
+ return classify(String(err.message));
115
+ }
116
+ }
117
+ //# sourceMappingURL=linear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear.js","sourceRoot":"","sources":["../../src/daemon/linear.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AA+BlD,0EAA0E;AAC1E,MAAM,UAAU,SAAS;IACvB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IAC7C,OAAO,CAAC,IAAI,IAAI,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,SAAS,EAAE,KAAK,IAAI,CAAC;AAC9B,CAAC;AAED,MAAM,MAAM,GAAsB;IAChC,SAAS,EAAE,KAAK;IAChB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,+EAA+E;CACxF,CAAC;AAEF,uEAAuE;AACvE,SAAS,QAAQ,CAAC,GAAW;IAC3B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClF,IAAI,sDAAsD,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACvE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,8CAA8C,EAAE,CAAC;IACtG,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC9D,CAAC;AAOD,KAAK,UAAU,GAAG,CAAI,KAAa,EAAE,YAAqC,EAAE;IAC1E,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,GAAG,EAAE;QACnE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QAC1C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAmB,CAAC;IAClD,IAAI,IAAI,CAAC,MAAM,EAAE,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,cAAc,CAAC,CAAC;IACpF,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC,gBAAgB,EAAE;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CACpB,uDAAuD,CACxD,CAAC;QACF,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC,MAAM,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAe;IACpD,IAAI,CAAC,gBAAgB,EAAE;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,MAAM,GAAG,CAapB;;;;QAIE,EACF,EAAE,MAAM,EAAE,CACX,CAAC;QACF,OAAO;YACL,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACpC,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE;gBAC1B,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,IAAI,IAAI;aACnC,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC,MAAM,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAIvC;IACC,IAAI,CAAC,gBAAgB,EAAE;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC7F,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IACxG,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAMpB;;QAEE,EACF;YACE,KAAK,EAAE;gBACL,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;gBACzB,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChF;SACF,CACF,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC5D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC,MAAM,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Phone push — the daemon's side of fire-and-notify.
3
+ *
4
+ * Paired devices register an Expo push token; when an agent needs input or
5
+ * work lands, the daemon POSTs to Expo's push API (no APNs/FCM credentials
6
+ * to manage). Route hops are deliberately NOT pushed — a 5-step pipeline
7
+ * should buzz your pocket once, not five times.
8
+ *
9
+ * LOOM_NO_PUSH=1 disables sending; LOOM_EXPO_PUSH_URL overrides the endpoint
10
+ * (used by tests to point at a mock).
11
+ */
12
+ import type { LoomEvent } from "../types.js";
13
+ export interface PushMessage {
14
+ title: string;
15
+ body: string;
16
+ data?: Record<string, unknown>;
17
+ }
18
+ /** Kinds that reach the phone. run_complete is filtered upstream during routes. */
19
+ export declare const PUSH_KINDS: Set<string>;
20
+ export declare function pushContent(projectName: string, event: LoomEvent): PushMessage;
21
+ /** Send one message to many devices in a single Expo batch call. Best-effort. */
22
+ export declare function sendExpoPush(tokens: string[], message: PushMessage): Promise<void>;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Phone push — the daemon's side of fire-and-notify.
3
+ *
4
+ * Paired devices register an Expo push token; when an agent needs input or
5
+ * work lands, the daemon POSTs to Expo's push API (no APNs/FCM credentials
6
+ * to manage). Route hops are deliberately NOT pushed — a 5-step pipeline
7
+ * should buzz your pocket once, not five times.
8
+ *
9
+ * LOOM_NO_PUSH=1 disables sending; LOOM_EXPO_PUSH_URL overrides the endpoint
10
+ * (used by tests to point at a mock).
11
+ */
12
+ const EXPO_PUSH_URL = "https://exp.host/--/api/v2/push/send";
13
+ /** Kinds that reach the phone. run_complete is filtered upstream during routes. */
14
+ export const PUSH_KINDS = new Set(["needs_input", "run_complete", "route_completed", "route_failed"]);
15
+ export function pushContent(projectName, event) {
16
+ const title = `Loom · ${projectName}`;
17
+ const p = event.payload;
18
+ switch (event.kind) {
19
+ case "needs_input":
20
+ return { title, body: `${event.agentId} asks: ${String(p.question ?? "").slice(0, 140)}` };
21
+ case "run_complete":
22
+ return { title, body: `${event.agentId} finished its turn` };
23
+ case "route_completed":
24
+ return { title, body: `✔ route complete (${Number(p.steps ?? 0)} steps)` };
25
+ case "route_failed":
26
+ return {
27
+ title,
28
+ body: `${p.aborted ? "⊘ route stopped" : "✗ route failed"}: ${String(p.reason ?? "").slice(0, 120)}`,
29
+ };
30
+ default:
31
+ return { title, body: event.kind };
32
+ }
33
+ }
34
+ /** Send one message to many devices in a single Expo batch call. Best-effort. */
35
+ export async function sendExpoPush(tokens, message) {
36
+ if (!tokens.length || process.env.LOOM_NO_PUSH)
37
+ return;
38
+ const url = process.env.LOOM_EXPO_PUSH_URL ?? EXPO_PUSH_URL;
39
+ const batch = tokens.map((to) => ({
40
+ to,
41
+ title: message.title,
42
+ body: message.body,
43
+ sound: "default",
44
+ ...(message.data ? { data: message.data } : {}),
45
+ }));
46
+ try {
47
+ await fetch(url, {
48
+ method: "POST",
49
+ headers: { "content-type": "application/json", accept: "application/json" },
50
+ body: JSON.stringify(batch),
51
+ signal: AbortSignal.timeout(10_000),
52
+ });
53
+ }
54
+ catch {
55
+ // Push is best-effort by design; the event log remains the source of truth.
56
+ }
57
+ }
58
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/daemon/push.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,aAAa,GAAG,sCAAsC,CAAC;AAQ7D,mFAAmF;AACnF,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,CAAC,CAAC,CAAC;AAEtG,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,KAAgB;IAC/D,MAAM,KAAK,GAAG,UAAU,WAAW,EAAE,CAAC;IACtC,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC;IACxB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,aAAa;YAChB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,OAAO,UAAU,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;QAC7F,KAAK,cAAc;YACjB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,OAAO,oBAAoB,EAAE,CAAC;QAC/D,KAAK,iBAAiB;YACpB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;QAC7E,KAAK,cAAc;YACjB,OAAO;gBACL,KAAK;gBACL,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;aACrG,CAAC;QACJ;YACE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAgB,EAAE,OAAoB;IACvE,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAAE,OAAO;IACvD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,aAAa,CAAC;IAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAChC,EAAE;QACF,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,SAAS;QAChB,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC,CAAC,CAAC;IACJ,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,GAAG,EAAE;YACf,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;YAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YAC3B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,299 @@
1
+ /**
2
+ * ProjectRuntime — one live project inside the daemon: its event log, its
3
+ * agents, and its baton. All mutations flow through here so the log stays
4
+ * the single source of truth.
5
+ */
6
+ import type { AgentConfig, AnyAgent, ChatInfo, CostSummary, ProjectConfig, ProjectInfo, ProjectStatus, UnifiedMemory } from "../types.js";
7
+ import type { RouteState, RouteStepSpec, RouterKind } from "../types.js";
8
+ import { BatonManager } from "../core/baton.js";
9
+ import { Brain } from "../core/brain.js";
10
+ import { EventLog } from "../core/eventlog.js";
11
+ import { RouteEngine } from "../core/routes.js";
12
+ import { type BoardTask } from "../core/registry.js";
13
+ import { type WorkingTree } from "../core/worktree.js";
14
+ export declare class ProjectRuntime {
15
+ readonly info: ProjectInfo;
16
+ readonly config: ProjectConfig;
17
+ readonly log: EventLog;
18
+ readonly baton: BatonManager;
19
+ readonly routes: RouteEngine;
20
+ /** Memory as units — see core/brain.ts. Reads and writes through `log`. */
21
+ readonly brain: Brain;
22
+ private agents;
23
+ private startedAgents;
24
+ private configMtime;
25
+ /**
26
+ * Which conversation each agent's current turn belongs to. Set when a turn
27
+ * starts and left in place afterwards — an agent's trailing events (a late
28
+ * run_complete, a diff) still belong to the chat that prompted them.
29
+ */
30
+ private turnChat;
31
+ private constructor();
32
+ static open(info: ProjectInfo): Promise<ProjectRuntime>;
33
+ private costs;
34
+ private costsByAgent;
35
+ private rehydrateCosts;
36
+ private trackCost;
37
+ costSummary(): CostSummary;
38
+ /** Has .loom/config.json changed since this runtime was opened? */
39
+ configStale(): boolean;
40
+ /**
41
+ * Rename an agent's job. Writes .loom/config.json (the source of truth) and
42
+ * updates this runtime in place — the generic hot-reload would do it too, but
43
+ * only once the project is quiet, and a label you just typed shouldn't wait
44
+ * on an agent's turn to finish. Nothing is torn down: a role is a name, not
45
+ * a capability, so no adapter needs restarting.
46
+ */
47
+ setAgentRole(agentId: string, role: string): {
48
+ id: string;
49
+ role: string;
50
+ } | null;
51
+ /**
52
+ * Edit the project's settings the Settings screen owns — the brain extractor,
53
+ * the projection mode, the default agent. These were config-file-only until
54
+ * now; everything is read live from this.config (brain?.extractor at turn end,
55
+ * projection at handoff), so a merge here takes effect on the next turn/hop
56
+ * with no restart. Only the known keys are honoured; unknown ones are ignored.
57
+ */
58
+ patchConfig(patch: {
59
+ brain?: {
60
+ extractor?: "auto" | "off";
61
+ model?: string;
62
+ };
63
+ projection?: {
64
+ mode?: "template" | "llm";
65
+ model?: string;
66
+ timeoutMs?: number;
67
+ };
68
+ defaultAgent?: string;
69
+ }): ProjectConfig;
70
+ /**
71
+ * The slice of config the Settings screen edits, read back for display: the
72
+ * brain extractor, the projection mode, the default agent, and the roster the
73
+ * default-agent picker chooses from. Defaults are spelled out here (extractor
74
+ * "auto", projection "template") so the screen shows the effective value, not
75
+ * a blank that hides what's actually running.
76
+ */
77
+ settings(): {
78
+ brain: {
79
+ extractor: "auto" | "off";
80
+ model: string;
81
+ };
82
+ projection: {
83
+ mode: "template" | "llm";
84
+ model: string;
85
+ };
86
+ defaultAgent: string;
87
+ agents: Array<{
88
+ id: string;
89
+ kind: string;
90
+ role?: string;
91
+ }>;
92
+ };
93
+ /**
94
+ * Put an agent in this project.
95
+ *
96
+ * Until this existed a project's roster was whatever was detected the moment
97
+ * it was created, forever. Install a new ADE and your existing projects never
98
+ * heard about it — which is why a machine with six agents had boards offering
99
+ * two, and looked like a bug in the board.
100
+ *
101
+ * The role defaults to the kind, which is a description rather than an
102
+ * opinion: Loom has no basis for deciding Codex is "the reviewer".
103
+ */
104
+ addAgent(kind: string, opts?: {
105
+ id?: string;
106
+ role?: string;
107
+ }): AgentConfig;
108
+ /**
109
+ * Create one agent and subscribe to it, exactly as the constructor does.
110
+ *
111
+ * Shared so a roster change can't drift from a cold start: an agent added at
112
+ * runtime must stream its events into the log the same way as one that was
113
+ * there when the project opened.
114
+ */
115
+ private spawnAgent;
116
+ /**
117
+ * Take an agent out.
118
+ *
119
+ * Refused while it holds the baton or is mid-turn: removing it there would
120
+ * strand the lock on an agent that no longer exists, and the thread would
121
+ * show a turn that nothing is running.
122
+ */
123
+ removeAgent(agentId: string): {
124
+ removed: string;
125
+ };
126
+ /**
127
+ * Point an agent at a different model.
128
+ *
129
+ * The model is read once, when the adapter is constructed (createAgent hands
130
+ * it cfg.options), so changing it means building a fresh agent — which drops
131
+ * the CLI session the old one was resuming. That's the right behaviour for a
132
+ * model switch: continuing one model's conversation on another model is not a
133
+ * thing the underlying CLIs support anyway. Refused mid-turn, because swapping
134
+ * the process out from under a running turn would strand it.
135
+ *
136
+ * An empty model clears the override, so the CLI falls back to its own default
137
+ * — the honest "Default" the picker offers.
138
+ */
139
+ setAgentModel(agentId: string, model: string): AgentConfig;
140
+ /** Write the roster, without tripping our own staleness check. */
141
+ private saveConfig;
142
+ /**
143
+ * Every conversation in this project, main first. Main is implicit: it's
144
+ * always there and it owns every event written before chats existed, so it
145
+ * is never stored. The rest live in state.json — a chat you created and
146
+ * haven't spoken in yet has no events to derive it from.
147
+ */
148
+ chats(): ChatInfo[];
149
+ createChat(title: string): ChatInfo;
150
+ renameChat(id: string, title: string): ChatInfo | null;
151
+ /**
152
+ * Forget a conversation. Its events stay in the log — it's append-only, and
153
+ * the brain is built from all of them; deleting the thread you had with an
154
+ * agent shouldn't quietly rewrite what the project decided. The chat just
155
+ * stops being listed.
156
+ */
157
+ deleteChat(id: string): boolean;
158
+ boardTasks(): BoardTask[];
159
+ createTask(input: {
160
+ title: string;
161
+ column?: string;
162
+ agent?: string;
163
+ }): BoardTask;
164
+ /** Move or retitle a card. Yours, so this is the real state — not a hint. */
165
+ updateTask(id: string, patch: {
166
+ title?: string;
167
+ column?: string;
168
+ agent?: string;
169
+ }): BoardTask | null;
170
+ deleteTask(id: string): boolean;
171
+ /** Any adapter mid-turn? (Hot reloads are deferred while work is in flight.) */
172
+ anyBusy(): boolean;
173
+ agent(id: string): AnyAgent;
174
+ private ensureStarted;
175
+ /** Pre-turn porcelain snapshots, for per-prompt diff attribution. */
176
+ private preTurnTree;
177
+ /** After a turn: log which files that prompt changed (turn_diff), then learn. */
178
+ private captureTurnDiff;
179
+ /**
180
+ * Phase 2: read a finished turn for durable memory.
181
+ *
182
+ * Fire-and-forget on purpose. A slow or missing extractor must never delay
183
+ * anything — extractFromTurn already swallows engine failures, and this is
184
+ * void-ed so even an unexpected throw can't escape into the event pipeline.
185
+ * Off entirely when config says so; a no-op when Claude isn't available.
186
+ */
187
+ private extractMemory;
188
+ /**
189
+ * The transcript of the most recent turn in a chat: from the last human
190
+ * message to now — the user's ask and what the agent did in reply.
191
+ */
192
+ private gatherTurnText;
193
+ workingTree(): Promise<WorkingTree>;
194
+ /** Freshly read every connected ADE's native memory from disk. */
195
+ private importedMemory;
196
+ /** The merged brain: decisions + imported ADE memories + shared context. */
197
+ unifiedMemory(): UnifiedMemory;
198
+ /**
199
+ * Phase 3: the brain brief for a handoff — the memories relevant to the work
200
+ * in flight, compiled. Query is the recent conversation plus the files recent
201
+ * turns touched; scoped to the incoming agent; low-confidence memories are
202
+ * held back from injection (they stay visible in the Brain tab). Empty string
203
+ * when there's nothing relevant, so callers append it unconditionally.
204
+ */
205
+ private retrieveBrief;
206
+ /**
207
+ * Pull each ADE's native memory into the shared log. Idempotent — a source
208
+ * whose content hasn't changed since its last import is skipped, so this is
209
+ * safe to call on connect, on demand, or on a timer.
210
+ */
211
+ importMemories(): {
212
+ imported: number;
213
+ sources: string[];
214
+ };
215
+ /** Fire-and-notify hooks + routing + suggested handoffs, off the log. */
216
+ private afterAgentEvent;
217
+ /**
218
+ * Convention: any agent line starting "Decision: …" is pinned into shared
219
+ * memory automatically — it survives every future handoff projection.
220
+ */
221
+ private captureDecisions;
222
+ /**
223
+ * The persisted holder, unless it refers to an agent that has since been
224
+ * removed from the config — ghost holders are cleared, not fatal.
225
+ */
226
+ private validHolder;
227
+ /**
228
+ * Send a user message. Routing rules (decided in the design interview):
229
+ * - no explicit agent → goes to the baton holder (or defaultAgent/first
230
+ * adapter on first contact, which acquires the baton);
231
+ * - explicit agent that is NOT the holder → NotHolderError; surfaces
232
+ * prompt the user to confirm a handoff (explicit, never silent).
233
+ */
234
+ /**
235
+ * Hand a prompt to a GUI agent by typing it into its own window.
236
+ *
237
+ * This is the road not taken by sendMessage. Antigravity and Kiro can't hold
238
+ * the baton — they edit the tree on their own schedule and know nothing about
239
+ * Loom's lock, so giving them the baton would be a promise Loom can't keep.
240
+ * But they can be *driven*: Loom types into the chat panel of the app you're
241
+ * already signed into, exactly as you would, and reads back what appeared.
242
+ * That's what makes them reachable from your phone.
243
+ *
244
+ * The exchange lands in the thread like any other, because the whole point of
245
+ * Loom is one place where you can see what was said to whom. It just never
246
+ * touches the baton on the way, so an adapter mid-turn is undisturbed.
247
+ *
248
+ * Awaited, unlike sendMessage's fire-and-notify: there's no event stream to
249
+ * follow here, only a panel that stops changing.
250
+ */
251
+ askBridge(agentId: string, text: string, opts?: {
252
+ chat?: string;
253
+ }): Promise<{
254
+ agentId: string;
255
+ reply: string;
256
+ }>;
257
+ sendMessage(text: string, agentId?: string, opts?: {
258
+ source?: "user" | "route";
259
+ chat?: string;
260
+ }): Promise<{
261
+ agentId: string;
262
+ }>;
263
+ private defaultAdapterId;
264
+ /** Briefings are injected with the first turn after a handoff. */
265
+ private pendingBriefings;
266
+ private consumePendingBriefing;
267
+ /**
268
+ * Explicit baton pass: interrupt the current holder if mid-turn, project
269
+ * the log into the target's namespaced memory, arm the one-shot briefing.
270
+ * A *manual* handoff cancels any active route — the human outranks it.
271
+ */
272
+ handoff(to: string, opts?: {
273
+ source?: "user" | "route";
274
+ }): Promise<{
275
+ from: string | null;
276
+ }>;
277
+ interrupt(opts?: {
278
+ source?: "user" | "route";
279
+ }): Promise<{
280
+ interrupted: string | null;
281
+ }>;
282
+ /**
283
+ * Start a multi-hop route. `spec` may be: "auto" (dynamic — a router picks
284
+ * every hop), an array of steps, a named route from config, or a comma
285
+ * list of agent ids/roles. Undefined → the "ship" route if defined, else
286
+ * every adapter in config order.
287
+ */
288
+ startRoute(opts: {
289
+ task: string;
290
+ spec?: string | RouteStepSpec[];
291
+ router?: RouterKind;
292
+ maxHops?: number;
293
+ }): Promise<RouteState>;
294
+ abortRoute(): Promise<RouteState>;
295
+ routeState(): RouteState | null;
296
+ status(): Promise<ProjectStatus>;
297
+ close(): Promise<void>;
298
+ }
299
+ export declare function relativeToProject(projectDir: string, p: string): string;