@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.
- package/ARCHITECTURE.md +211 -0
- package/CHANGELOG.md +470 -0
- package/LICENSE +21 -0
- package/README.md +630 -0
- package/dist/adapters/base.d.ts +71 -0
- package/dist/adapters/base.js +187 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/bridges/antigravity.d.ts +53 -0
- package/dist/adapters/bridges/antigravity.js +106 -0
- package/dist/adapters/bridges/antigravity.js.map +1 -0
- package/dist/adapters/bridges/cdp.d.ts +82 -0
- package/dist/adapters/bridges/cdp.js +222 -0
- package/dist/adapters/bridges/cdp.js.map +1 -0
- package/dist/adapters/bridges/gui-chat.d.ts +113 -0
- package/dist/adapters/bridges/gui-chat.js +498 -0
- package/dist/adapters/bridges/gui-chat.js.map +1 -0
- package/dist/adapters/bridges/kiro.d.ts +19 -0
- package/dist/adapters/bridges/kiro.js +22 -0
- package/dist/adapters/bridges/kiro.js.map +1 -0
- package/dist/adapters/bridges/profiles.d.ts +82 -0
- package/dist/adapters/bridges/profiles.js +125 -0
- package/dist/adapters/bridges/profiles.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +26 -0
- package/dist/adapters/claude-code.js +209 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +51 -0
- package/dist/adapters/codex.js +291 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/echo.d.ts +20 -0
- package/dist/adapters/echo.js +79 -0
- package/dist/adapters/echo.js.map +1 -0
- package/dist/adapters/grok.d.ts +61 -0
- package/dist/adapters/grok.js +217 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.js +33 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +64 -0
- package/dist/adapters/opencode.js +426 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/cli/common.d.ts +11 -0
- package/dist/cli/common.js +40 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/doctor.d.ts +12 -0
- package/dist/cli/doctor.js +181 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +641 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/tui-model.d.ts +73 -0
- package/dist/cli/tui-model.js +312 -0
- package/dist/cli/tui-model.js.map +1 -0
- package/dist/cli/tui.d.ts +15 -0
- package/dist/cli/tui.js +451 -0
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli/ui.d.ts +10 -0
- package/dist/cli/ui.js +135 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/core/ades.d.ts +79 -0
- package/dist/core/ades.js +130 -0
- package/dist/core/ades.js.map +1 -0
- package/dist/core/baton.d.ts +37 -0
- package/dist/core/baton.js +92 -0
- package/dist/core/baton.js.map +1 -0
- package/dist/core/brain-extract.d.ts +111 -0
- package/dist/core/brain-extract.js +248 -0
- package/dist/core/brain-extract.js.map +1 -0
- package/dist/core/brain-index.d.ts +128 -0
- package/dist/core/brain-index.js +338 -0
- package/dist/core/brain-index.js.map +1 -0
- package/dist/core/brain.d.ts +214 -0
- package/dist/core/brain.js +425 -0
- package/dist/core/brain.js.map +1 -0
- package/dist/core/claude-cli.d.ts +12 -0
- package/dist/core/claude-cli.js +47 -0
- package/dist/core/claude-cli.js.map +1 -0
- package/dist/core/distill.d.ts +19 -0
- package/dist/core/distill.js +88 -0
- package/dist/core/distill.js.map +1 -0
- package/dist/core/eventlog.d.ts +43 -0
- package/dist/core/eventlog.js +211 -0
- package/dist/core/eventlog.js.map +1 -0
- package/dist/core/git.d.ts +203 -0
- package/dist/core/git.js +460 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/logbook.d.ts +59 -0
- package/dist/core/logbook.js +118 -0
- package/dist/core/logbook.js.map +1 -0
- package/dist/core/memory.d.ts +34 -0
- package/dist/core/memory.js +124 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/notify.d.ts +11 -0
- package/dist/core/notify.js +30 -0
- package/dist/core/notify.js.map +1 -0
- package/dist/core/projection.d.ts +20 -0
- package/dist/core/projection.js +96 -0
- package/dist/core/projection.js.map +1 -0
- package/dist/core/registry.d.ts +76 -0
- package/dist/core/registry.js +147 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/router.d.ts +42 -0
- package/dist/core/router.js +99 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/routes.d.ts +93 -0
- package/dist/core/routes.js +399 -0
- package/dist/core/routes.js.map +1 -0
- package/dist/core/search.d.ts +63 -0
- package/dist/core/search.js +0 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/setup.d.ts +70 -0
- package/dist/core/setup.js +250 -0
- package/dist/core/setup.js.map +1 -0
- package/dist/core/suggestions.d.ts +15 -0
- package/dist/core/suggestions.js +38 -0
- package/dist/core/suggestions.js.map +1 -0
- package/dist/core/worktree.d.ts +32 -0
- package/dist/core/worktree.js +83 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/daemon/app-page.d.ts +32 -0
- package/dist/daemon/app-page.js +6363 -0
- package/dist/daemon/app-page.js.map +1 -0
- package/dist/daemon/auth.d.ts +51 -0
- package/dist/daemon/auth.js +135 -0
- package/dist/daemon/auth.js.map +1 -0
- package/dist/daemon/board.d.ts +117 -0
- package/dist/daemon/board.js +202 -0
- package/dist/daemon/board.js.map +1 -0
- package/dist/daemon/brand-icons.d.ts +29 -0
- package/dist/daemon/brand-icons.js +44 -0
- package/dist/daemon/brand-icons.js.map +1 -0
- package/dist/daemon/client.d.ts +127 -0
- package/dist/daemon/client.js +237 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/geist-font.d.ts +10 -0
- package/dist/daemon/geist-font.js +783 -0
- package/dist/daemon/geist-font.js.map +1 -0
- package/dist/daemon/guards.d.ts +18 -0
- package/dist/daemon/guards.js +40 -0
- package/dist/daemon/guards.js.map +1 -0
- package/dist/daemon/linear.d.ts +59 -0
- package/dist/daemon/linear.js +117 -0
- package/dist/daemon/linear.js.map +1 -0
- package/dist/daemon/push.d.ts +22 -0
- package/dist/daemon/push.js +58 -0
- package/dist/daemon/push.js.map +1 -0
- package/dist/daemon/runtime.d.ts +299 -0
- package/dist/daemon/runtime.js +1016 -0
- package/dist/daemon/runtime.js.map +1 -0
- package/dist/daemon/server.d.ts +125 -0
- package/dist/daemon/server.js +1728 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/tasks.d.ts +153 -0
- package/dist/daemon/tasks.js +264 -0
- package/dist/daemon/tasks.js.map +1 -0
- package/dist/daemon/terminals.d.ts +82 -0
- package/dist/daemon/terminals.js +372 -0
- package/dist/daemon/terminals.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/sdk.d.ts +17 -0
- package/dist/sdk.js +17 -0
- package/dist/sdk.js.map +1 -0
- package/dist/types.d.ts +236 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/docs/SETUP.md +265 -0
- package/docs/adapters.md +132 -0
- package/docs/design-system.md +245 -0
- package/docs/img/board-linear.png +0 -0
- package/docs/img/board-projects.png +0 -0
- package/docs/img/brain.png +0 -0
- package/docs/img/settings.png +0 -0
- package/docs/img/workspace.png +0 -0
- package/docs/integration-notes.md +76 -0
- package/docs/proposals/brain.md +262 -0
- 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;
|