constella 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/.next/BUILD_ID +1 -0
- package/.next/app-path-routes-manifest.json +53 -0
- package/.next/build-manifest.json +20 -0
- package/.next/diagnostics/build-diagnostics.json +6 -0
- package/.next/diagnostics/framework.json +1 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +68 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +36 -0
- package/.next/react-loadable-manifest.json +14 -0
- package/.next/required-server-files.js +343 -0
- package/.next/required-server-files.json +343 -0
- package/.next/routes-manifest.json +362 -0
- package/.next/server/app/(app)/activity/page.js +2 -0
- package/.next/server/app/(app)/activity/page.js.nft.json +1 -0
- package/.next/server/app/(app)/activity/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/agents/[handle]/page.js +18 -0
- package/.next/server/app/(app)/agents/[handle]/page.js.nft.json +1 -0
- package/.next/server/app/(app)/agents/[handle]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/code/page.js +2 -0
- package/.next/server/app/(app)/code/page.js.nft.json +1 -0
- package/.next/server/app/(app)/code/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/config/page.js +2 -0
- package/.next/server/app/(app)/config/page.js.nft.json +1 -0
- package/.next/server/app/(app)/config/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/costs/page.js +2 -0
- package/.next/server/app/(app)/costs/page.js.nft.json +1 -0
- package/.next/server/app/(app)/costs/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/cron/page.js +2 -0
- package/.next/server/app/(app)/cron/page.js.nft.json +1 -0
- package/.next/server/app/(app)/cron/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/dashboard/page.js +2 -0
- package/.next/server/app/(app)/dashboard/page.js.nft.json +1 -0
- package/.next/server/app/(app)/dashboard/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/docs/[id]/page.js +2 -0
- package/.next/server/app/(app)/docs/[id]/page.js.nft.json +1 -0
- package/.next/server/app/(app)/docs/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/docs/page.js +2 -0
- package/.next/server/app/(app)/docs/page.js.nft.json +1 -0
- package/.next/server/app/(app)/docs/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/github/page.js +2 -0
- package/.next/server/app/(app)/github/page.js.nft.json +1 -0
- package/.next/server/app/(app)/github/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/goals/page.js +2 -0
- package/.next/server/app/(app)/goals/page.js.nft.json +1 -0
- package/.next/server/app/(app)/goals/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/inbox/page.js +2 -0
- package/.next/server/app/(app)/inbox/page.js.nft.json +1 -0
- package/.next/server/app/(app)/inbox/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/knowledge/page.js +3 -0
- package/.next/server/app/(app)/knowledge/page.js.nft.json +1 -0
- package/.next/server/app/(app)/knowledge/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/models/page.js +2 -0
- package/.next/server/app/(app)/models/page.js.nft.json +1 -0
- package/.next/server/app/(app)/models/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/notifications/page.js +2 -0
- package/.next/server/app/(app)/notifications/page.js.nft.json +1 -0
- package/.next/server/app/(app)/notifications/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/org/page.js +2 -0
- package/.next/server/app/(app)/org/page.js.nft.json +1 -0
- package/.next/server/app/(app)/org/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/organizations/page.js +2 -0
- package/.next/server/app/(app)/organizations/page.js.nft.json +1 -0
- package/.next/server/app/(app)/organizations/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/page.js +3 -0
- package/.next/server/app/(app)/page.js.nft.json +1 -0
- package/.next/server/app/(app)/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/planner/page.js +2 -0
- package/.next/server/app/(app)/planner/page.js.nft.json +1 -0
- package/.next/server/app/(app)/planner/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/plugins/page.js +2 -0
- package/.next/server/app/(app)/plugins/page.js.nft.json +1 -0
- package/.next/server/app/(app)/plugins/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/pm/page.js +2 -0
- package/.next/server/app/(app)/pm/page.js.nft.json +1 -0
- package/.next/server/app/(app)/pm/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/prepare-deploy/page.js +19 -0
- package/.next/server/app/(app)/prepare-deploy/page.js.nft.json +1 -0
- package/.next/server/app/(app)/prepare-deploy/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/profile/page.js +2 -0
- package/.next/server/app/(app)/profile/page.js.nft.json +1 -0
- package/.next/server/app/(app)/profile/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/pulse/page.js +2 -0
- package/.next/server/app/(app)/pulse/page.js.nft.json +1 -0
- package/.next/server/app/(app)/pulse/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/reports/[id]/page.js +3 -0
- package/.next/server/app/(app)/reports/[id]/page.js.nft.json +1 -0
- package/.next/server/app/(app)/reports/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/reports/page.js +5 -0
- package/.next/server/app/(app)/reports/page.js.nft.json +1 -0
- package/.next/server/app/(app)/reports/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/routines/page.js +2 -0
- package/.next/server/app/(app)/routines/page.js.nft.json +1 -0
- package/.next/server/app/(app)/routines/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/search/page.js +2 -0
- package/.next/server/app/(app)/search/page.js.nft.json +1 -0
- package/.next/server/app/(app)/search/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/security/page.js +2 -0
- package/.next/server/app/(app)/security/page.js.nft.json +1 -0
- package/.next/server/app/(app)/security/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/skills/page.js +18 -0
- package/.next/server/app/(app)/skills/page.js.nft.json +1 -0
- package/.next/server/app/(app)/skills/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/tasks/page.js +2 -0
- package/.next/server/app/(app)/tasks/page.js.nft.json +1 -0
- package/.next/server/app/(app)/tasks/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/test-dev/page.js +2 -0
- package/.next/server/app/(app)/test-dev/page.js.nft.json +1 -0
- package/.next/server/app/(app)/test-dev/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/update/page.js +2 -0
- package/.next/server/app/(app)/update/page.js.nft.json +1 -0
- package/.next/server/app/(app)/update/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(auth)/login/page.js +2 -0
- package/.next/server/app/(auth)/login/page.js.nft.json +1 -0
- package/.next/server/app/(auth)/login/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(auth)/onboarding/page.js +18 -0
- package/.next/server/app/(auth)/onboarding/page.js.nft.json +1 -0
- package/.next/server/app/(auth)/onboarding/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_global-error/page.js +32 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_global-error.html +1 -0
- package/.next/server/app/_global-error.meta +16 -0
- package/.next/server/app/_global-error.rsc +15 -0
- package/.next/server/app/_global-error.segments/_full.segment.rsc +15 -0
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_global-error.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_index.segment.rsc +6 -0
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/api/auth/[...all]/route.js +1 -0
- package/.next/server/app/api/auth/[...all]/route.js.nft.json +1 -0
- package/.next/server/app/api/auth/[...all]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/cron/tick/route.js +52 -0
- package/.next/server/app/api/cron/tick/route.js.nft.json +1 -0
- package/.next/server/app/api/cron/tick/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/dev-login/route.js +1 -0
- package/.next/server/app/api/dev-login/route.js.nft.json +1 -0
- package/.next/server/app/api/dev-login/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/locks/acquire/route.js +1 -0
- package/.next/server/app/api/locks/acquire/route.js.nft.json +1 -0
- package/.next/server/app/api/locks/acquire/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/models/progress/route.js +1 -0
- package/.next/server/app/api/models/progress/route.js.nft.json +1 -0
- package/.next/server/app/api/models/progress/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/passkey/authenticate/options/route.js +1 -0
- package/.next/server/app/api/passkey/authenticate/options/route.js.nft.json +1 -0
- package/.next/server/app/api/passkey/authenticate/options/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/passkey/authenticate/verify/route.js +1 -0
- package/.next/server/app/api/passkey/authenticate/verify/route.js.nft.json +1 -0
- package/.next/server/app/api/passkey/authenticate/verify/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/passkey/register/options/route.js +1 -0
- package/.next/server/app/api/passkey/register/options/route.js.nft.json +1 -0
- package/.next/server/app/api/passkey/register/options/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/passkey/register/verify/route.js +1 -0
- package/.next/server/app/api/passkey/register/verify/route.js.nft.json +1 -0
- package/.next/server/app/api/passkey/register/verify/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/stream/route.js +4 -0
- package/.next/server/app/api/stream/route.js.nft.json +1 -0
- package/.next/server/app/api/stream/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sync/file/route.js +2 -0
- package/.next/server/app/api/sync/file/route.js.nft.json +1 -0
- package/.next/server/app/api/sync/file/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/telegram/poll/route.js +15 -0
- package/.next/server/app/api/telegram/poll/route.js.nft.json +1 -0
- package/.next/server/app/api/telegram/poll/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/upload/route.js +1 -0
- package/.next/server/app/api/upload/route.js.nft.json +1 -0
- package/.next/server/app/api/upload/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/v1/[[...path]]/route.js +1 -0
- package/.next/server/app/api/v1/[[...path]]/route.js.nft.json +1 -0
- package/.next/server/app/api/v1/[[...path]]/route_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +53 -0
- package/.next/server/chunks/1003.js +1 -0
- package/.next/server/chunks/127.js +26 -0
- package/.next/server/chunks/1388.js +1 -0
- package/.next/server/chunks/1408.js +21 -0
- package/.next/server/chunks/1572.js +1 -0
- package/.next/server/chunks/1591.js +24 -0
- package/.next/server/chunks/1619.js +188 -0
- package/.next/server/chunks/162.js +1 -0
- package/.next/server/chunks/1881.js +1 -0
- package/.next/server/chunks/1968.js +1 -0
- package/.next/server/chunks/2297.js +348 -0
- package/.next/server/chunks/2341.js +1 -0
- package/.next/server/chunks/2517.js +1 -0
- package/.next/server/chunks/2549.js +1 -0
- package/.next/server/chunks/259.js +14 -0
- package/.next/server/chunks/2599.js +1 -0
- package/.next/server/chunks/260.js +1 -0
- package/.next/server/chunks/2867.js +147 -0
- package/.next/server/chunks/3018.js +1 -0
- package/.next/server/chunks/3050.js +18 -0
- package/.next/server/chunks/3085.js +12 -0
- package/.next/server/chunks/3131.js +1 -0
- package/.next/server/chunks/3242.js +1 -0
- package/.next/server/chunks/3266.js +15 -0
- package/.next/server/chunks/3524.js +1 -0
- package/.next/server/chunks/3527.js +479 -0
- package/.next/server/chunks/3533.js +869 -0
- package/.next/server/chunks/3550.js +1 -0
- package/.next/server/chunks/3609.js +2 -0
- package/.next/server/chunks/3667.js +462 -0
- package/.next/server/chunks/3760.js +4 -0
- package/.next/server/chunks/4679.js +1 -0
- package/.next/server/chunks/4804.js +1 -0
- package/.next/server/chunks/4832.js +2 -0
- package/.next/server/chunks/4853.js +1 -0
- package/.next/server/chunks/4979.js +67 -0
- package/.next/server/chunks/5060.js +1 -0
- package/.next/server/chunks/5278.js +1 -0
- package/.next/server/chunks/5614.js +1 -0
- package/.next/server/chunks/5818.js +1 -0
- package/.next/server/chunks/6479.js +1 -0
- package/.next/server/chunks/6658.js +1 -0
- package/.next/server/chunks/6706.js +1 -0
- package/.next/server/chunks/6719.js +1 -0
- package/.next/server/chunks/678.js +1 -0
- package/.next/server/chunks/683.js +1 -0
- package/.next/server/chunks/6862.js +1 -0
- package/.next/server/chunks/6882.js +1 -0
- package/.next/server/chunks/7037.js +1 -0
- package/.next/server/chunks/7107.js +741 -0
- package/.next/server/chunks/73.js +17 -0
- package/.next/server/chunks/7327.js +1 -0
- package/.next/server/chunks/7514.js +1 -0
- package/.next/server/chunks/7622.js +1 -0
- package/.next/server/chunks/7778.js +1 -0
- package/.next/server/chunks/7912.js +1 -0
- package/.next/server/chunks/7949.js +1 -0
- package/.next/server/chunks/7971.js +1 -0
- package/.next/server/chunks/7989.js +1 -0
- package/.next/server/chunks/842.js +22 -0
- package/.next/server/chunks/8762.js +15 -0
- package/.next/server/chunks/8823.js +77 -0
- package/.next/server/chunks/9146.js +4 -0
- package/.next/server/chunks/9676.js +1 -0
- package/.next/server/chunks/9783.js +22 -0
- package/.next/server/chunks/9969.js +3 -0
- package/.next/server/functions-config-manifest.json +18 -0
- package/.next/server/instrumentation.js +1 -0
- package/.next/server/instrumentation.js.nft.json +1 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/middleware.js +18 -0
- package/.next/server/middleware.js.nft.json +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages-manifest.json +3 -0
- package/.next/server/prefetch-hints.json +1 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/chunks/1858-339516f78a4b00da.js +1 -0
- package/.next/static/chunks/2320-fc8b39380e69d465.js +2 -0
- package/.next/static/chunks/23550918-ff694f70f4b0648c.js +1 -0
- package/.next/static/chunks/3219-ebb3c23be38c838d.js +1 -0
- package/.next/static/chunks/4263-adecb5b466380b6e.js +1 -0
- package/.next/static/chunks/5479-0cceab68cd0ca9c7.js +1 -0
- package/.next/static/chunks/5701-665b927b06158b76.js +1 -0
- package/.next/static/chunks/5920.6451a68b63918988.js +1 -0
- package/.next/static/chunks/6575-5c9139720bb0f5bf.js +4 -0
- package/.next/static/chunks/6834-4759af1ce7d95fb6.js +32 -0
- package/.next/static/chunks/7509.721cd47a931c5518.js +1 -0
- package/.next/static/chunks/8264-1ca011989ee2b231.js +1 -0
- package/.next/static/chunks/9219-4a39a98b5502d9d1.js +1 -0
- package/.next/static/chunks/9690-53d5222618cbeddb.js +1 -0
- package/.next/static/chunks/app/(app)/activity/page-3973534281ecea81.js +1 -0
- package/.next/static/chunks/app/(app)/agents/[handle]/page-83662a175c098282.js +1 -0
- package/.next/static/chunks/app/(app)/code/page-33979545192cd137.js +1 -0
- package/.next/static/chunks/app/(app)/config/page-9933aed1ca8a85c1.js +1 -0
- package/.next/static/chunks/app/(app)/costs/page-131c4dc580efcc19.js +1 -0
- package/.next/static/chunks/app/(app)/cron/page-53ea1aff998a87ca.js +1 -0
- package/.next/static/chunks/app/(app)/dashboard/page-deed83aaa9d0d447.js +1 -0
- package/.next/static/chunks/app/(app)/docs/[id]/page-38c993d73c0eab4f.js +1 -0
- package/.next/static/chunks/app/(app)/docs/page-bf463b55d0554e86.js +1 -0
- package/.next/static/chunks/app/(app)/error-988cd28480809861.js +1 -0
- package/.next/static/chunks/app/(app)/github/page-62678b4e82dfecb6.js +1 -0
- package/.next/static/chunks/app/(app)/goals/page-4adb426fe1c96106.js +1 -0
- package/.next/static/chunks/app/(app)/inbox/page-e347dc55ab467310.js +1 -0
- package/.next/static/chunks/app/(app)/knowledge/page-65393a045b4349be.js +1 -0
- package/.next/static/chunks/app/(app)/layout-7f65675705b011d8.js +1 -0
- package/.next/static/chunks/app/(app)/models/page-e01f1dd7e49a2951.js +1 -0
- package/.next/static/chunks/app/(app)/notifications/page-56548ac87aef00da.js +1 -0
- package/.next/static/chunks/app/(app)/org/page-699e6a6dc0db7d81.js +1 -0
- package/.next/static/chunks/app/(app)/organizations/page-36051a380a7e8eb7.js +1 -0
- package/.next/static/chunks/app/(app)/page-7d1011a566f81520.js +1 -0
- package/.next/static/chunks/app/(app)/planner/page-dab7ced94083373a.js +1 -0
- package/.next/static/chunks/app/(app)/plugins/page-5b5a1f53389be42e.js +1 -0
- package/.next/static/chunks/app/(app)/pm/page-0de5c08c0b227bb0.js +1 -0
- package/.next/static/chunks/app/(app)/prepare-deploy/page-e426038552df8d41.js +1 -0
- package/.next/static/chunks/app/(app)/profile/page-608dfcaf8aae0a69.js +1 -0
- package/.next/static/chunks/app/(app)/pulse/page-309ccaca91de1faa.js +1 -0
- package/.next/static/chunks/app/(app)/reports/[id]/page-53ea1aff998a87ca.js +1 -0
- package/.next/static/chunks/app/(app)/reports/page-68cdc6dcfa472d86.js +1 -0
- package/.next/static/chunks/app/(app)/routines/page-bcc55550b197a9fa.js +1 -0
- package/.next/static/chunks/app/(app)/search/page-5c5f67558d0dbf0d.js +1 -0
- package/.next/static/chunks/app/(app)/security/page-a7d41e36aa366b45.js +1 -0
- package/.next/static/chunks/app/(app)/skills/page-c5b21e89593b8336.js +1 -0
- package/.next/static/chunks/app/(app)/tasks/page-08ae079e3e54d2ce.js +1 -0
- package/.next/static/chunks/app/(app)/test-dev/page-633f82dfd9c3ce23.js +1 -0
- package/.next/static/chunks/app/(app)/update/page-4be019054351bfac.js +1 -0
- package/.next/static/chunks/app/(auth)/login/page-6e85d3377062acae.js +1 -0
- package/.next/static/chunks/app/(auth)/onboarding/page-ebb10c175abf3b85.js +1 -0
- package/.next/static/chunks/app/_global-error/page-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/_not-found/page-dc38b02aebeab535.js +1 -0
- package/.next/static/chunks/app/api/auth/[...all]/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/cron/tick/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/dev-login/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/locks/acquire/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/models/progress/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/passkey/authenticate/options/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/passkey/authenticate/verify/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/passkey/register/options/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/passkey/register/verify/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/stream/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/sync/file/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/telegram/poll/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/upload/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/api/v1/[[...path]]/route-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/app/error-09899a13c38b6e89.js +1 -0
- package/.next/static/chunks/app/global-error-b8050d4d886f448c.js +1 -0
- package/.next/static/chunks/app/layout-ab9deed1e7e2e9df.js +1 -0
- package/.next/static/chunks/framework-4b2c6b6043dd203f.js +1 -0
- package/.next/static/chunks/main-722e16032e7764d1.js +5 -0
- package/.next/static/chunks/main-app-761880af2b6f1962.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-23fe50a6bf589c97.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-222e3894b78c67db.js +1 -0
- package/.next/static/css/0a9b5805594444e3.css +1 -0
- package/.next/static/yztMvBwyrWWkSqP6jfXoa/_buildManifest.js +1 -0
- package/.next/static/yztMvBwyrWWkSqP6jfXoa/_ssgManifest.js +1 -0
- package/.next/trace-build +1 -0
- package/.next/types/app/(app)/activity/page.ts +87 -0
- package/.next/types/app/(app)/agents/[handle]/page.ts +87 -0
- package/.next/types/app/(app)/code/page.ts +87 -0
- package/.next/types/app/(app)/config/page.ts +87 -0
- package/.next/types/app/(app)/costs/page.ts +87 -0
- package/.next/types/app/(app)/cron/page.ts +87 -0
- package/.next/types/app/(app)/dashboard/page.ts +87 -0
- package/.next/types/app/(app)/docs/[id]/page.ts +87 -0
- package/.next/types/app/(app)/docs/page.ts +87 -0
- package/.next/types/app/(app)/github/page.ts +87 -0
- package/.next/types/app/(app)/goals/page.ts +87 -0
- package/.next/types/app/(app)/inbox/page.ts +87 -0
- package/.next/types/app/(app)/knowledge/page.ts +87 -0
- package/.next/types/app/(app)/models/page.ts +87 -0
- package/.next/types/app/(app)/notifications/page.ts +87 -0
- package/.next/types/app/(app)/org/page.ts +87 -0
- package/.next/types/app/(app)/organizations/page.ts +87 -0
- package/.next/types/app/(app)/page.ts +87 -0
- package/.next/types/app/(app)/planner/page.ts +87 -0
- package/.next/types/app/(app)/plugins/page.ts +87 -0
- package/.next/types/app/(app)/pm/page.ts +87 -0
- package/.next/types/app/(app)/prepare-deploy/page.ts +87 -0
- package/.next/types/app/(app)/profile/page.ts +87 -0
- package/.next/types/app/(app)/pulse/page.ts +87 -0
- package/.next/types/app/(app)/reports/[id]/page.ts +87 -0
- package/.next/types/app/(app)/reports/page.ts +87 -0
- package/.next/types/app/(app)/routines/page.ts +87 -0
- package/.next/types/app/(app)/search/page.ts +87 -0
- package/.next/types/app/(app)/security/page.ts +87 -0
- package/.next/types/app/(app)/skills/page.ts +87 -0
- package/.next/types/app/(app)/tasks/page.ts +87 -0
- package/.next/types/app/(app)/test-dev/page.ts +87 -0
- package/.next/types/app/(app)/update/page.ts +87 -0
- package/.next/types/app/(auth)/login/page.ts +87 -0
- package/.next/types/app/(auth)/onboarding/page.ts +87 -0
- package/.next/types/app/api/auth/[...all]/route.ts +351 -0
- package/.next/types/app/api/cron/tick/route.ts +351 -0
- package/.next/types/app/api/dev-login/route.ts +351 -0
- package/.next/types/app/api/locks/acquire/route.ts +351 -0
- package/.next/types/app/api/models/progress/route.ts +351 -0
- package/.next/types/app/api/passkey/authenticate/options/route.ts +351 -0
- package/.next/types/app/api/passkey/authenticate/verify/route.ts +351 -0
- package/.next/types/app/api/passkey/register/options/route.ts +351 -0
- package/.next/types/app/api/passkey/register/verify/route.ts +351 -0
- package/.next/types/app/api/stream/route.ts +351 -0
- package/.next/types/app/api/sync/file/route.ts +351 -0
- package/.next/types/app/api/telegram/poll/route.ts +351 -0
- package/.next/types/app/api/upload/route.ts +351 -0
- package/.next/types/app/api/v1/[[...path]]/route.ts +351 -0
- package/.next/types/cache-life.d.ts +145 -0
- package/.next/types/link.d.ts +210 -0
- package/.next/types/package.json +1 -0
- package/.next/types/routes.d.ts +120 -0
- package/.next/types/validator.ts +511 -0
- package/CHANGELOG.md +312 -0
- package/LICENSE +21 -0
- package/README.md +382 -0
- package/README.pt-BR.md +391 -0
- package/bin/constella.mjs +329 -0
- package/bin/guard-hook.mjs +44 -0
- package/bin/lock-hook.mjs +49 -0
- package/bin/worker.mjs +142 -0
- package/docs/assets/arch-orbit.svg +56 -0
- package/docs/assets/blackhole.svg +37 -0
- package/docs/assets/divider-orbit.svg +23 -0
- package/docs/assets/hero-constella.svg +72 -0
- package/docs/en/AGENTS.md +279 -0
- package/docs/en/AI_ARCHITECTURE.md +373 -0
- package/docs/en/ARCHITECTURE.md +334 -0
- package/docs/en/AUTH_MODE.md +247 -0
- package/docs/en/CHAT_COMMANDS.md +305 -0
- package/docs/en/CONFIGURATION.md +340 -0
- package/docs/en/DEPLOY.md +331 -0
- package/docs/en/DM.md +297 -0
- package/docs/en/FAQ.md +258 -0
- package/docs/en/GITHUB.md +341 -0
- package/docs/en/GOALS_SPECS_ISSUES.md +303 -0
- package/docs/en/INBOX.md +340 -0
- package/docs/en/INSTALLATION.md +329 -0
- package/docs/en/KB_AGENT.md +305 -0
- package/docs/en/KB_RAG.md +356 -0
- package/docs/en/MCP.md +313 -0
- package/docs/en/MEMORY_RAG.md +289 -0
- package/docs/en/MODELS.md +341 -0
- package/docs/en/ONBOARDING.md +327 -0
- package/docs/en/PLUGINS.md +290 -0
- package/docs/en/PORTABLE_MODE.md +387 -0
- package/docs/en/PO_AGENT.md +379 -0
- package/docs/en/PREPARE_DEPLOY.md +308 -0
- package/docs/en/PROJECT_STACKS.md +258 -0
- package/docs/en/PUBLIC_API.md +315 -0
- package/docs/en/PUBLISHING.md +343 -0
- package/docs/en/README.md +95 -0
- package/docs/en/SECURITY.md +280 -0
- package/docs/en/SKILLS.md +349 -0
- package/docs/en/START_MODE.md +340 -0
- package/docs/en/SYNCED_BLOCKS.md +320 -0
- package/docs/en/TEAM_ROOM.md +285 -0
- package/docs/en/TELEGRAM.md +294 -0
- package/docs/en/TEST_DEV.md +321 -0
- package/docs/en/TROUBLESHOOTING.md +294 -0
- package/docs/en/UPDATE.md +301 -0
- package/docs/en/VPS_MODE.md +334 -0
- package/docs/en/WORKFLOW.md +321 -0
- package/docs/pt/AGENTS.md +279 -0
- package/docs/pt/AI_ARCHITECTURE.md +373 -0
- package/docs/pt/ARCHITECTURE.md +334 -0
- package/docs/pt/AUTH_MODE.md +247 -0
- package/docs/pt/CHAT_COMMANDS.md +307 -0
- package/docs/pt/CONFIGURATION.md +340 -0
- package/docs/pt/DEPLOY.md +331 -0
- package/docs/pt/DM.md +297 -0
- package/docs/pt/FAQ.md +258 -0
- package/docs/pt/GITHUB.md +341 -0
- package/docs/pt/GOALS_SPECS_ISSUES.md +303 -0
- package/docs/pt/INBOX.md +340 -0
- package/docs/pt/INSTALLATION.md +329 -0
- package/docs/pt/KB_AGENT.md +305 -0
- package/docs/pt/KB_RAG.md +356 -0
- package/docs/pt/MCP.md +313 -0
- package/docs/pt/MEMORY_RAG.md +289 -0
- package/docs/pt/MODELS.md +341 -0
- package/docs/pt/ONBOARDING.md +327 -0
- package/docs/pt/PLUGINS.md +290 -0
- package/docs/pt/PORTABLE_MODE.md +387 -0
- package/docs/pt/PO_AGENT.md +379 -0
- package/docs/pt/PREPARE_DEPLOY.md +308 -0
- package/docs/pt/PROJECT_STACKS.md +258 -0
- package/docs/pt/PUBLIC_API.md +315 -0
- package/docs/pt/PUBLISHING.md +343 -0
- package/docs/pt/README.md +95 -0
- package/docs/pt/SECURITY.md +280 -0
- package/docs/pt/SKILLS.md +349 -0
- package/docs/pt/START_MODE.md +340 -0
- package/docs/pt/SYNCED_BLOCKS.md +320 -0
- package/docs/pt/TEAM_ROOM.md +285 -0
- package/docs/pt/TELEGRAM.md +294 -0
- package/docs/pt/TEST_DEV.md +321 -0
- package/docs/pt/TROUBLESHOOTING.md +294 -0
- package/docs/pt/UPDATE.md +301 -0
- package/docs/pt/VPS_MODE.md +334 -0
- package/docs/pt/WORKFLOW.md +321 -0
- package/drizzle/0000_regular_nightshade.sql +644 -0
- package/drizzle/0001_mixed_zombie.sql +106 -0
- package/drizzle/meta/0000_snapshot.json +4650 -0
- package/drizzle/meta/0001_snapshot.json +5418 -0
- package/drizzle/meta/_journal.json +20 -0
- package/drizzle.config.mjs +16 -0
- package/next.config.mjs +18 -0
- package/package.json +130 -0
- package/scripts/clean-repo.mjs +20 -0
- package/scripts/dev-all.mjs +46 -0
- package/scripts/i18n-parity.mjs +57 -0
- package/scripts/mcp-server.mjs +100 -0
- package/scripts/postbuild.mjs +11 -0
- package/scripts/publish-public.mjs +116 -0
- package/scripts/start-all.mjs +45 -0
- package/scripts/trim-next.mjs +23 -0
- package/scripts/vps-install.sh +39 -0
- package/skills/CONTRIBUTING.md +122 -0
- package/skills/COVERAGE.md +129 -0
- package/skills/INDEX.json +3443 -0
- package/skills/README.md +57 -0
- package/skills/design/animation-motion/SKILL.md +60 -0
- package/skills/design/color-and-typography/SKILL.md +60 -0
- package/skills/design/css-techniques/SKILL.md +58 -0
- package/skills/design/design-systems/SKILL.md +60 -0
- package/skills/design/gradients/SKILL.md +59 -0
- package/skills/design/graphic-design-basics/SKILL.md +55 -0
- package/skills/design/microinteractions/SKILL.md +58 -0
- package/skills/design/responsive-layout/SKILL.md +59 -0
- package/skills/design/ui-ux-principles/SKILL.md +58 -0
- package/skills/engineering/architecture/api-design-rest-graphql/SKILL.md +67 -0
- package/skills/engineering/architecture/caching-strategies/SKILL.md +59 -0
- package/skills/engineering/architecture/data-modeling/SKILL.md +64 -0
- package/skills/engineering/architecture/message-queues-async/SKILL.md +58 -0
- package/skills/engineering/architecture/scalability-reliability/SKILL.md +62 -0
- package/skills/engineering/architecture/software-architecture-patterns/SKILL.md +56 -0
- package/skills/engineering/architecture/system-design-fundamentals/SKILL.md +56 -0
- package/skills/engineering/backend/auth-and-authorization/SKILL.md +62 -0
- package/skills/engineering/backend/backend-fundamentals/SKILL.md +65 -0
- package/skills/engineering/backend/observability-logging/SKILL.md +60 -0
- package/skills/engineering/frontend/accessibility-wcag/SKILL.md +57 -0
- package/skills/engineering/frontend/frontend-architecture/SKILL.md +65 -0
- package/skills/engineering/frontend/rendering-strategies-ssr-csr/SKILL.md +60 -0
- package/skills/engineering/frontend/state-management/SKILL.md +69 -0
- package/skills/engineering/performance/backend-performance/SKILL.md +69 -0
- package/skills/engineering/performance/database-query-optimization/SKILL.md +64 -0
- package/skills/engineering/performance/profiling-and-benchmarking/SKILL.md +60 -0
- package/skills/engineering/performance/web-performance-core-vitals/SKILL.md +72 -0
- package/skills/engineering/practices/clean-code/SKILL.md +61 -0
- package/skills/engineering/practices/code-optimization/SKILL.md +60 -0
- package/skills/engineering/practices/code-review-practices/SKILL.md +58 -0
- package/skills/engineering/practices/git-workflow/SKILL.md +62 -0
- package/skills/engineering/practices/refactoring/SKILL.md +58 -0
- package/skills/engineering/security/appsec-fundamentals/SKILL.md +70 -0
- package/skills/engineering/security/dependency-supply-chain/SKILL.md +77 -0
- package/skills/engineering/security/owasp-asvs/SKILL.md +54 -0
- package/skills/engineering/security/owasp-top-10/SKILL.md +63 -0
- package/skills/engineering/security/secrets-management/SKILL.md +58 -0
- package/skills/engineering/security/secure-auth-sessions/SKILL.md +56 -0
- package/skills/engineering/testing/tdd-and-coverage/SKILL.md +62 -0
- package/skills/engineering/testing/testing-strategy-pyramid/SKILL.md +56 -0
- package/skills/engineering/testing/unit-integration-e2e/SKILL.md +75 -0
- package/skills/languages/c/SKILL.md +74 -0
- package/skills/languages/clojure/SKILL.md +73 -0
- package/skills/languages/cpp/SKILL.md +75 -0
- package/skills/languages/csharp/SKILL.md +75 -0
- package/skills/languages/dart/SKILL.md +82 -0
- package/skills/languages/elixir/SKILL.md +74 -0
- package/skills/languages/erlang/SKILL.md +76 -0
- package/skills/languages/go/SKILL.md +83 -0
- package/skills/languages/haskell/SKILL.md +70 -0
- package/skills/languages/java/SKILL.md +71 -0
- package/skills/languages/javascript/SKILL.md +62 -0
- package/skills/languages/kotlin/SKILL.md +68 -0
- package/skills/languages/lua/SKILL.md +79 -0
- package/skills/languages/objectivec/SKILL.md +83 -0
- package/skills/languages/php/SKILL.md +74 -0
- package/skills/languages/python/SKILL.md +68 -0
- package/skills/languages/r/SKILL.md +70 -0
- package/skills/languages/ruby/SKILL.md +67 -0
- package/skills/languages/rust/SKILL.md +72 -0
- package/skills/languages/scala/SKILL.md +73 -0
- package/skills/languages/swift/SKILL.md +73 -0
- package/skills/languages/typescript/SKILL.md +69 -0
- package/skills/meta/authoring-agent-skills/SKILL.md +73 -0
- package/skills/meta/progressive-disclosure/SKILL.md +65 -0
- package/skills/meta/skill-frontmatter-spec/SKILL.md +65 -0
- package/skills/process/adr-technical-decisions/SKILL.md +59 -0
- package/skills/process/app-planning/SKILL.md +63 -0
- package/skills/process/architecture-before-code/SKILL.md +52 -0
- package/skills/process/breaking-work-into-sprints/SKILL.md +53 -0
- package/skills/process/idea-to-product/SKILL.md +50 -0
- package/skills/process/mocks-and-screen-flows/SKILL.md +52 -0
- package/skills/process/prioritization-moscow-rice/SKILL.md +64 -0
- package/skills/process/problem-framing/SKILL.md +51 -0
- package/skills/process/product-discovery/SKILL.md +53 -0
- package/skills/process/readme-generation/SKILL.md +90 -0
- package/skills/process/requirements-to-specs/SKILL.md +53 -0
- package/skills/process/research-official-docs/SKILL.md +58 -0
- package/skills/process/review-code-perf-security/SKILL.md +65 -0
- package/skills/process/security-by-design/SKILL.md +68 -0
- package/skills/process/specs-to-issues/SKILL.md +53 -0
- package/skills/process/testing-before-done/SKILL.md +61 -0
- package/skills/process/validating-ux-navigation/SKILL.md +63 -0
- package/skills/references/ai-attachments-ui/SKILL.md +66 -0
- package/skills/references/ai-in-browser-webllm/SKILL.md +74 -0
- package/skills/references/ai-tool-ui-patterns/SKILL.md +63 -0
- package/skills/references/component-patterns-gallery/SKILL.md +62 -0
- package/skills/references/gradient-resources/SKILL.md +66 -0
- package/skills/references/react-component-libraries/SKILL.md +61 -0
- package/skills/references/saas-landing-patterns/SKILL.md +67 -0
- package/skills/references/shadcn-tailwind-theming/SKILL.md +74 -0
- package/skills/references/vercel-ai-sdk-elements/SKILL.md +66 -0
- package/skills/references/web-animation-codrops/SKILL.md +68 -0
- package/skills/stacks/aiml/jupyter/SKILL.md +68 -0
- package/skills/stacks/aiml/keras/SKILL.md +77 -0
- package/skills/stacks/aiml/numpy/SKILL.md +69 -0
- package/skills/stacks/aiml/pandas/SKILL.md +72 -0
- package/skills/stacks/aiml/pytorch/SKILL.md +77 -0
- package/skills/stacks/aiml/scikit-learn/SKILL.md +74 -0
- package/skills/stacks/aiml/tensorflow/SKILL.md +79 -0
- package/skills/stacks/auth/auth0/SKILL.md +63 -0
- package/skills/stacks/auth/authjs/SKILL.md +69 -0
- package/skills/stacks/auth/clerk/SKILL.md +72 -0
- package/skills/stacks/auth/keycloak/SKILL.md +63 -0
- package/skills/stacks/auth/lucia/SKILL.md +56 -0
- package/skills/stacks/auth/passport/SKILL.md +70 -0
- package/skills/stacks/auth/supabase-auth/SKILL.md +66 -0
- package/skills/stacks/baas/amplify/SKILL.md +71 -0
- package/skills/stacks/baas/appwrite/SKILL.md +79 -0
- package/skills/stacks/baas/firebase/SKILL.md +73 -0
- package/skills/stacks/baas/heroku/SKILL.md +71 -0
- package/skills/stacks/backend/actix/SKILL.md +77 -0
- package/skills/stacks/backend/adonisjs/SKILL.md +65 -0
- package/skills/stacks/backend/aspnet-core/SKILL.md +75 -0
- package/skills/stacks/backend/codeigniter/SKILL.md +76 -0
- package/skills/stacks/backend/django/SKILL.md +62 -0
- package/skills/stacks/backend/express/SKILL.md +65 -0
- package/skills/stacks/backend/fastapi/SKILL.md +64 -0
- package/skills/stacks/backend/fastify/SKILL.md +64 -0
- package/skills/stacks/backend/fiber/SKILL.md +68 -0
- package/skills/stacks/backend/flask/SKILL.md +71 -0
- package/skills/stacks/backend/gin/SKILL.md +68 -0
- package/skills/stacks/backend/graphql/SKILL.md +70 -0
- package/skills/stacks/backend/hono/SKILL.md +64 -0
- package/skills/stacks/backend/koa/SKILL.md +63 -0
- package/skills/stacks/backend/laravel/SKILL.md +73 -0
- package/skills/stacks/backend/nestjs/SKILL.md +70 -0
- package/skills/stacks/backend/nginx/SKILL.md +77 -0
- package/skills/stacks/backend/phoenix/SKILL.md +68 -0
- package/skills/stacks/backend/rails/SKILL.md +67 -0
- package/skills/stacks/backend/spring/SKILL.md +70 -0
- package/skills/stacks/backend/spring-boot/SKILL.md +70 -0
- package/skills/stacks/backend/symfony/SKILL.md +77 -0
- package/skills/stacks/container/containerd/SKILL.md +75 -0
- package/skills/stacks/container/docker/SKILL.md +90 -0
- package/skills/stacks/container/podman/SKILL.md +93 -0
- package/skills/stacks/database/cassandra/SKILL.md +74 -0
- package/skills/stacks/database/cockroachdb/SKILL.md +69 -0
- package/skills/stacks/database/dynamodb/SKILL.md +62 -0
- package/skills/stacks/database/mariadb/SKILL.md +71 -0
- package/skills/stacks/database/mongodb/SKILL.md +71 -0
- package/skills/stacks/database/mysql/SKILL.md +72 -0
- package/skills/stacks/database/neon/SKILL.md +68 -0
- package/skills/stacks/database/planetscale/SKILL.md +70 -0
- package/skills/stacks/database/postgresql/SKILL.md +81 -0
- package/skills/stacks/database/redis/SKILL.md +78 -0
- package/skills/stacks/database/sqlite/SKILL.md +70 -0
- package/skills/stacks/database/supabase/SKILL.md +79 -0
- package/skills/stacks/dataviz/chart-js/SKILL.md +72 -0
- package/skills/stacks/dataviz/d3/SKILL.md +77 -0
- package/skills/stacks/dataviz/grafana/SKILL.md +69 -0
- package/skills/stacks/dataviz/plotly/SKILL.md +71 -0
- package/skills/stacks/frontend/alpine/SKILL.md +75 -0
- package/skills/stacks/frontend/angular/SKILL.md +75 -0
- package/skills/stacks/frontend/backbone/SKILL.md +82 -0
- package/skills/stacks/frontend/ember/SKILL.md +85 -0
- package/skills/stacks/frontend/htmx/SKILL.md +73 -0
- package/skills/stacks/frontend/lit/SKILL.md +76 -0
- package/skills/stacks/frontend/preact/SKILL.md +74 -0
- package/skills/stacks/frontend/qwik/SKILL.md +65 -0
- package/skills/stacks/frontend/react/SKILL.md +77 -0
- package/skills/stacks/frontend/solidjs/SKILL.md +75 -0
- package/skills/stacks/frontend/svelte/SKILL.md +70 -0
- package/skills/stacks/frontend/vue/SKILL.md +69 -0
- package/skills/stacks/infra/ansible/SKILL.md +76 -0
- package/skills/stacks/infra/aws/SKILL.md +66 -0
- package/skills/stacks/infra/azure/SKILL.md +72 -0
- package/skills/stacks/infra/circleci/SKILL.md +78 -0
- package/skills/stacks/infra/cloudflare/SKILL.md +65 -0
- package/skills/stacks/infra/fly-io/SKILL.md +63 -0
- package/skills/stacks/infra/gcp/SKILL.md +66 -0
- package/skills/stacks/infra/jenkins/SKILL.md +73 -0
- package/skills/stacks/infra/kubernetes/SKILL.md +64 -0
- package/skills/stacks/infra/netlify/SKILL.md +60 -0
- package/skills/stacks/infra/railway/SKILL.md +63 -0
- package/skills/stacks/infra/tailscale/SKILL.md +65 -0
- package/skills/stacks/infra/terraform/SKILL.md +75 -0
- package/skills/stacks/infra/vagrant/SKILL.md +70 -0
- package/skills/stacks/infra/vercel/SKILL.md +60 -0
- package/skills/stacks/meta/astro/SKILL.md +64 -0
- package/skills/stacks/meta/docusaurus/SKILL.md +71 -0
- package/skills/stacks/meta/eleventy/SKILL.md +69 -0
- package/skills/stacks/meta/gatsby/SKILL.md +63 -0
- package/skills/stacks/meta/hugo/SKILL.md +73 -0
- package/skills/stacks/meta/jekyll/SKILL.md +70 -0
- package/skills/stacks/meta/nextjs/SKILL.md +62 -0
- package/skills/stacks/meta/nuxt/SKILL.md +66 -0
- package/skills/stacks/meta/remix/SKILL.md +67 -0
- package/skills/stacks/meta/sveltekit/SKILL.md +70 -0
- package/skills/stacks/meta/vite/SKILL.md +63 -0
- package/skills/stacks/mobile/android/SKILL.md +77 -0
- package/skills/stacks/mobile/flutter/SKILL.md +77 -0
- package/skills/stacks/mobile/ionic/SKILL.md +72 -0
- package/skills/stacks/mobile/nativescript/SKILL.md +71 -0
- package/skills/stacks/mobile/react-native/SKILL.md +75 -0
- package/skills/stacks/mobile/xamarin/SKILL.md +73 -0
- package/skills/stacks/orm/diesel/SKILL.md +72 -0
- package/skills/stacks/orm/django-orm/SKILL.md +58 -0
- package/skills/stacks/orm/drizzle/SKILL.md +67 -0
- package/skills/stacks/orm/gorm/SKILL.md +73 -0
- package/skills/stacks/orm/knex/SKILL.md +64 -0
- package/skills/stacks/orm/mongoose/SKILL.md +64 -0
- package/skills/stacks/orm/prisma/SKILL.md +64 -0
- package/skills/stacks/orm/sequelize/SKILL.md +65 -0
- package/skills/stacks/orm/sqlalchemy/SKILL.md +71 -0
- package/skills/stacks/orm/typeorm/SKILL.md +70 -0
- package/skills/stacks/queue/bullmq/SKILL.md +69 -0
- package/skills/stacks/queue/celery/SKILL.md +68 -0
- package/skills/stacks/queue/kafka/SKILL.md +66 -0
- package/skills/stacks/queue/nats/SKILL.md +66 -0
- package/skills/stacks/queue/rabbitmq/SKILL.md +64 -0
- package/skills/stacks/queue/redis/SKILL.md +66 -0
- package/skills/stacks/runtime/beam/SKILL.md +72 -0
- package/skills/stacks/runtime/bun/SKILL.md +80 -0
- package/skills/stacks/runtime/deno/SKILL.md +74 -0
- package/skills/stacks/runtime/dotnet/SKILL.md +64 -0
- package/skills/stacks/runtime/jvm/SKILL.md +66 -0
- package/skills/stacks/runtime/node/SKILL.md +70 -0
- package/skills/stacks/runtime/pypy/SKILL.md +69 -0
- package/skills/stacks/runtime/python3/SKILL.md +70 -0
- package/skills/stacks/styling/bootstrap/SKILL.md +74 -0
- package/skills/stacks/styling/bulma/SKILL.md +80 -0
- package/skills/stacks/styling/chakra-ui/SKILL.md +61 -0
- package/skills/stacks/styling/css-modules/SKILL.md +54 -0
- package/skills/stacks/styling/mui/SKILL.md +60 -0
- package/skills/stacks/styling/sass/SKILL.md +63 -0
- package/skills/stacks/styling/shadcn-ui/SKILL.md +58 -0
- package/skills/stacks/styling/styled-components/SKILL.md +62 -0
- package/skills/stacks/styling/tailwind/SKILL.md +59 -0
- package/skills/stacks/styling/unocss/SKILL.md +64 -0
- package/skills/stacks/styling/vanilla-extract/SKILL.md +64 -0
- package/skills/stacks/styling/vuetify/SKILL.md +89 -0
- package/skills/stacks/testing/cypress/SKILL.md +68 -0
- package/skills/stacks/testing/jasmine/SKILL.md +67 -0
- package/skills/stacks/testing/jest/SKILL.md +67 -0
- package/skills/stacks/testing/mocha/SKILL.md +71 -0
- package/skills/stacks/testing/playwright/SKILL.md +68 -0
- package/skills/stacks/testing/puppeteer/SKILL.md +70 -0
- package/skills/stacks/testing/selenium/SKILL.md +70 -0
- package/skills/stacks/testing/vitest/SKILL.md +68 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
[← Índice](./README.md) · [🇬🇧 English](../en/TEAM_ROOM.md) · [✦ Constella](../../README.pt-BR.md)
|
|
2
|
+
|
|
3
|
+
# Team Room — A Constelação Compartilhada 🌌🛰️
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
A **Team Room** (sala da equipe) é o canal único e compartilhado onde o operador e a constelação de agentes conversam abertamente. Uma mensagem precisa `@mencionar` um colega para ser respondida; até **três** estrelas acendem por turno, e a partir daí a conversa pode se retransmitir de agente para agente em uma **cadeia de handoff** limitada, até o trabalho ser reportado de volta.
|
|
8
|
+
|
|
9
|
+
## Quando usar
|
|
10
|
+
|
|
11
|
+
- Você quer **se dirigir a um ou mais agentes abertamente** (toda a equipe vê o thread), ao contrário de uma [DM](./DM.md) privada.
|
|
12
|
+
- Você quer **iniciar um handoff** — pedir ao QA para testar, depois fazê-lo pedir ao engenheiro para corrigir, depois pedir ao Docs para documentar — sem microgerenciar cada passo.
|
|
13
|
+
- Você quer transformar uma linha de chat em **novo trabalho** pedindo à CEO (Ada) ou a um planner para "construir / corrigir / mudar" algo (o ritual spec→issue→plan; veja [WORKFLOW](./WORKFLOW.md)).
|
|
14
|
+
- Você quer a **rastreabilidade** de uma mensagem de volta à sua task no board → issue → goal.
|
|
15
|
+
|
|
16
|
+
Use uma **DM** (`dm:<handle>`) quando quiser um 1:1 privado com um agente; use o **[Telegram](./TELEGRAM.md)** quando estiver remoto. A Team Room é a praça pública.
|
|
17
|
+
|
|
18
|
+
## Como funciona ✦
|
|
19
|
+
|
|
20
|
+
A Team Room é o canal de `message` literalmente chamado **`"room"`**. Duas server actions em `src/server/chat.ts` a movimentam, apoiadas pelo motor de relay em `src/server/collab.ts`:
|
|
21
|
+
|
|
22
|
+
| Função | Arquivo | Responsabilidade |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `sendMessage(channel, text, attachments?)` | `chat.ts` | Armazena a mensagem do operador, faz parse dos `@mentions`, retorna até **3** handles respondentes. Intercepta slash commands primeiro. |
|
|
25
|
+
| `agentRespond(channel, handle)` | `chat.ts` | Roda a resposta de um agente via `replyInChannel` e então (na room) dispara a cadeia autônoma de handoff via `relayRoomMentions`. |
|
|
26
|
+
| `replyInChannel(orgId, ws, channel, a, mode, handoff?)` | `collab.ts` | Um turno real de agente: monta o prompt, roda o runtime do CLI, faz scrub de segredos, armazena a resposta, contabiliza o custo. `mode` = `chat` ou `work`. |
|
|
27
|
+
| `relayRoomMentions(orgId, ws, fromHandle, text, depth, fired)` | `collab.ts` | Handoff recursivo: para cada colega que a resposta `@menciona`, faz com que ele **aja** em modo work e então recursa na menção da resposta dele. |
|
|
28
|
+
|
|
29
|
+
O fluxo é deliberadamente **chat-first**: nada é falso. Cada turno de agente é um processo real do CLI `claude`/`codex` rodando com o workspace como diretório atual (a jaula de FS), produzindo saída real e contabilizando linhas reais em `costEntry`.
|
|
30
|
+
|
|
31
|
+
### Canais num relance
|
|
32
|
+
|
|
33
|
+
A coluna `message.channel` distingue onde uma mensagem vive:
|
|
34
|
+
|
|
35
|
+
| Valor de `channel` | Significado | Respondentes |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `room` | A Team Room (este doc) | Os handles `@mencionados`, máximo 3 |
|
|
38
|
+
| `dm:<handle>` | Um 1:1 privado com um agente | Sempre aquele handle |
|
|
39
|
+
| `telegram` | O thread remoto isolado | Sempre a CEO (`ada`), com fallback ao primeiro agente |
|
|
40
|
+
|
|
41
|
+
## Fluxo principal 🌠
|
|
42
|
+
|
|
43
|
+
```mermaid
|
|
44
|
+
sequenceDiagram
|
|
45
|
+
actor Op as Operador
|
|
46
|
+
participant Room as Team Room (canal "room")
|
|
47
|
+
participant Send as sendMessage
|
|
48
|
+
participant Resp as agentRespond
|
|
49
|
+
participant Reply as replyInChannel
|
|
50
|
+
participant Relay as relayRoomMentions
|
|
51
|
+
|
|
52
|
+
Op->>Send: "@edsger por favor teste o fluxo de login"
|
|
53
|
+
Send->>Send: mentions() → ["edsger"] (máx 3)
|
|
54
|
+
Send->>Room: insere mensagem do operador (fromKind=operator)
|
|
55
|
+
Send-->>Resp: responders = ["edsger"]
|
|
56
|
+
Resp->>Reply: edsger, mode "chat"
|
|
57
|
+
Reply->>Room: insere resposta de edsger ("Falhou — @margaret corrija o login")
|
|
58
|
+
Resp->>Relay: relayRoomMentions(from=edsger, text, depth 0)
|
|
59
|
+
Relay->>Reply: margaret, mode "work", handoff={from:edsger}
|
|
60
|
+
Reply->>Room: insere resposta de margaret ("Corrigido. @barbara documente")
|
|
61
|
+
Relay->>Reply: barbara, mode "work", handoff={from:margaret}
|
|
62
|
+
Reply->>Room: insere resposta de barbara (sem menção → cadeia termina)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
1. O operador posta uma mensagem. `sendMessage` checa se começa com `/` (slash command) — se sim, ela é despachada para `runSlashCommand` e o caminho normal é pulado.
|
|
66
|
+
2. Caso contrário, `sendMessage` extrai os `@mentions`, mantém apenas handles que são **agentes reais** e corta nos primeiros **3**. Se nenhum casar, **nada é postado como conjunto de respondentes** (`return { responders: [] }`) — a room nunca guarda uma mensagem sem saída.
|
|
67
|
+
3. A mensagem do operador é armazenada (`fromKind: "operator"`), o stream SSE é acordado (`wake`), o chat é agendado para reindexação RAG e — se a mensagem for substancial (≥15 caracteres) — é registrada como uma **decisão** (`source: "operator-instruction"`).
|
|
68
|
+
4. A UI chama `agentRespond` para cada respondente. Cada um roda `replyInChannel` em modo **`chat`** (conversacional, sem edição de arquivos) e a resposta é armazenada.
|
|
69
|
+
5. Na room, `agentRespond` então chama `relayRoomMentions` — a cadeia autônoma de handoff. Agentes retransmitidos rodam em modo **`work`** (podem ler/editar/rodar arquivos), e a cadeia continua para quem quer que eles `@mencionem`.
|
|
70
|
+
|
|
71
|
+
## Conceitos-chave ✦
|
|
72
|
+
|
|
73
|
+
### `@mentions` e a regra do máximo 3
|
|
74
|
+
|
|
75
|
+
Uma mensagem da Team Room só é respondida se `@mencionar` um colega real. A regex é `@([a-z0-9-]+)`:
|
|
76
|
+
|
|
77
|
+
- Em `sendMessage`, `mentions(text)` põe cada handle em minúsculas, filtra para agentes conhecidos e faz **`.slice(0, 3)`** — no máximo três agentes respondem a uma única mensagem do operador.
|
|
78
|
+
- O composer do lado do cliente bloqueia um post sem menção; a checagem no servidor é a guarda autoritativa.
|
|
79
|
+
- `@operator` é um alvo especial: quando um agente `@menciona @operator`, nenhum agente dispara (o operador não é um agente), mas uma notificação persistente + item de Inbox é levantado (veja [INBOX](./INBOX.md)).
|
|
80
|
+
|
|
81
|
+
### Modo `chat` vs modo `work`
|
|
82
|
+
|
|
83
|
+
`replyInChannel` recebe um `mode`:
|
|
84
|
+
|
|
85
|
+
| Modo | Usado por | Comportamento |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `chat` | A resposta direta a uma menção do operador (`agentRespond`) | "Reply in 1-3 sentences as yourself. **Do not modify files.**" Apenas conversacional. |
|
|
88
|
+
| `work` | Handoffs retransmitidos (`relayRoomMentions`) | "Do what's needed in the workspace now… then post a SHORT update… END by `@mentioning` EXACTLY ONE teammate with a concrete ask." O agente lê/edita/roda arquivos. |
|
|
89
|
+
|
|
90
|
+
No modo `work`, quando há um handoff presente, o prompt o torna explícito: *"Your teammate `@<from>` just handed off to YOU… that hand-off IS your instruction — there is NO separate operator message."* Isso resolveu a confusão do "não vejo uma mensagem do operador".
|
|
91
|
+
|
|
92
|
+
### A cadeia de handoff (relay)
|
|
93
|
+
|
|
94
|
+
`relayRoomMentions` é a espinha dorsal autônoma. Ela é **limitada por design** para que uma única menção nunca se espalhe em gasto descontrolado de tokens:
|
|
95
|
+
|
|
96
|
+
| Constante | Arquivo | Valor | Efeito |
|
|
97
|
+
|---|---|---|---|
|
|
98
|
+
| `MAX_DEPTH` | `collab.ts` | `2` | A cadeia para após 2 saltos. |
|
|
99
|
+
| `MAX_FANOUT` | `collab.ts` | `1` | Uma única mensagem repassa para **um** colega, não vários — é uma cadeia, não uma árvore. |
|
|
100
|
+
|
|
101
|
+
Guardas adicionais do relay (todas em `collab.ts`):
|
|
102
|
+
|
|
103
|
+
- **Conjunto `fired`** — cada agente é disparado pelo relay no máximo **uma vez por cadeia**.
|
|
104
|
+
- **Nunca redisparar o remetente** — o agente que acabou de falar é excluído (`h !== fromHandle`).
|
|
105
|
+
- **`busyOnBoard`** — um agente com status `working`, ou que possui uma task no board na coluna `doing`, é **pulado**. Uma task em "doing" é a unidade coordenada de trabalho daquele agente; um relay paralelo o faria reeditar os mesmos arquivos (o caos do "mesmo agente fica mexendo no mesmo arquivo").
|
|
106
|
+
- **`agentAtCap`** — um agente acima do seu orçamento `dailyCapUsd` é pulado (veja [MODELS](./MODELS.md) para os caps).
|
|
107
|
+
- **`isNoisePing`** — um ping sem conteúdo (só menções/emoji/pontuação, ou filler como "on it", "got it", "done") **não** dispara um handoff. A mensagem armazenada fica intacta; só o relay é governado.
|
|
108
|
+
- **`sanitizeForRelay`** — colapsa sequências de emoji no contexto que o próximo agente vê.
|
|
109
|
+
|
|
110
|
+
### Decisões
|
|
111
|
+
|
|
112
|
+
Uma linha substancial do operador na room é uma diretiva que os agentes devem honrar, então ela é registrada no log durável `decision` (`logDecision`, `src/server/decisions.ts`):
|
|
113
|
+
|
|
114
|
+
- Disparada quando `channel === "room"` e `text.trim().length >= 15`.
|
|
115
|
+
- Armazenada com `by: "operator"`, `source: "operator-instruction"`.
|
|
116
|
+
- Espelhada na Knowledge Base como uma entrada `decision` (best-effort), para que qualquer agente a recupere via retrieval state-aware (veja [KB_RAG](./KB_RAG.md), [MEMORY_RAG](./MEMORY_RAG.md)).
|
|
117
|
+
|
|
118
|
+
O Context Manager apresenta o log de decisões a cada agente independentemente do modelo, mantendo a continuidade entre execuções.
|
|
119
|
+
|
|
120
|
+
### Anexos
|
|
121
|
+
|
|
122
|
+
O operador pode anexar até **10** arquivos por mensagem (fotos / PDF / docs). Eles são salvos sob `uploads/` no workspace (para que o agente possa lê-los com suas ferramentas de arquivo) e armazenados como JSON na coluna `message.attachments`. Em `replyInChannel`, os caminhos dos anexos das últimas 6 mensagens (limitados a 12) são injetados no prompt como **dados, não instruções** — um nome de arquivo não pode contrabandear uma diretiva (bloco `<<attached-files>>`).
|
|
123
|
+
|
|
124
|
+
### Rastreabilidade de task
|
|
125
|
+
|
|
126
|
+
Quando o **runner** posta o resultado de uma task na room (`src/server/runner.ts`), ele define `message.taskId`. `taskRef(taskId)` em `chat.ts` resolve o chip:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
task key · issue key · goal title · column
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Assim, um post na room que veio de trabalho do board liga de volta à sua `task` → `issue` → `goal`, e à coluna (`triage|todo|doing|blocked|review|done`). Veja [GOALS_SPECS_ISSUES](./GOALS_SPECS_ISSUES.md).
|
|
133
|
+
|
|
134
|
+
### Captura de conhecimento no chat
|
|
135
|
+
|
|
136
|
+
Dentro de `replyInChannel`, as respostas dos agentes são varridas por tokens de KB (cada um em sua própria linha, entre colchetes duplos):
|
|
137
|
+
|
|
138
|
+
- `[[REMEMBER type=<…>: <fact>]]` → ingerido na KB (deduplicado), token removido da resposta exibida.
|
|
139
|
+
- `[[CONSULT: <question>]]` → respondido por Vannevar no mesmo thread (postado como mensagem `🔎 KB consult`), disponível no próximo turno.
|
|
140
|
+
- `[[KB: reindex|index-chat|health]]` → apenas para o agente de Conhecimento; resultados postados como `🛠️ KB tools`.
|
|
141
|
+
|
|
142
|
+
Veja [KB_AGENT](./KB_AGENT.md) e [KB_RAG](./KB_RAG.md) para a gramática completa dos tokens.
|
|
143
|
+
|
|
144
|
+
### Transformar chat em novo trabalho
|
|
145
|
+
|
|
146
|
+
No modo `chat`, o prompt permite que **qualquer** agente transforme um pedido explícito de construção em novo trabalho. Se o operador pede para BUILD / IMPLEMENT / ADD / FIX / CHANGE algo, o agente confirma brevemente e emite o token de máquina `[[CREATE_WORK]]` em uma linha final. `agentRespond` detecta `planRequested`, remove o token e roda `planFromConversation` — o mesmo ritual spec→issue→plan do primeiro plano, aguardando a aprovação do operador. Veja [WORKFLOW](./WORKFLOW.md) e [PO_AGENT](./PO_AGENT.md).
|
|
147
|
+
|
|
148
|
+
## Tabelas 🪐
|
|
149
|
+
|
|
150
|
+
### `message` (a espinha da room — `src/db/schema.ts`)
|
|
151
|
+
|
|
152
|
+
| Coluna | Tipo | Notas |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `id` | text PK | UUID |
|
|
155
|
+
| `workspaceId` | text | FK → `workspace`, cascade delete |
|
|
156
|
+
| `channel` | text | `room` \| `dm:<handle>` \| `telegram` (padrão `room`) |
|
|
157
|
+
| `fromKind` | enum | `operator` \| `agent` |
|
|
158
|
+
| `fromHandle` | text | handle do agente (NULL para o operador) |
|
|
159
|
+
| `text` | text | corpo da mensagem (respostas armazenadas ≤4000 caracteres) |
|
|
160
|
+
| `sources` | json `string[]` | arquivos do workspace que o agente recuperou (RAG) para produzir a resposta → chips de fonte |
|
|
161
|
+
| `attachments` | json | `{ name, type, size, path }[]`, ≤10/mensagem |
|
|
162
|
+
| `sessionId` | text | sessão de DM (`chat_session`); NULL para room/Telegram |
|
|
163
|
+
| `taskId` | text | a task de board que esta mensagem reporta → chip de rastreabilidade |
|
|
164
|
+
| `kind` | text | dica de renderização (ex.: `kb-card`); NULL = mensagem normal |
|
|
165
|
+
| `blocks` | json `string[]` | slugs de synced-block que uma resposta propôs editar (veja [SYNCED_BLOCKS](./SYNCED_BLOCKS.md)) |
|
|
166
|
+
| `createdAt` | timestamp | padrão `unixepoch()` |
|
|
167
|
+
|
|
168
|
+
Índice: `msg_ws_chan_idx` em `(workspaceId, channel)`.
|
|
169
|
+
|
|
170
|
+
### `decision` (`src/db/schema.ts`)
|
|
171
|
+
|
|
172
|
+
| Coluna | Notas |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `text` | a decisão (instrução do operador, ≤400 caracteres da linha da room) |
|
|
175
|
+
| `by` | `operator` ou um handle de agente |
|
|
176
|
+
| `source` | `operator-instruction` aqui; também `plan-approve` \| `issue-block` \| `spec-reject` \| `task-done` |
|
|
177
|
+
| `rationale`, `refKey`, `goalId` | links opcionais para retorno |
|
|
178
|
+
|
|
179
|
+
### `messageSummary` & `event`
|
|
180
|
+
|
|
181
|
+
| Tabela | Papel |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `messageSummary` | Resumo compactado das mensagens mais antigas por `(workspace, channel, sessionId)` — alimenta o Context Manager para que threads longos não estourem a janela do modelo. Apagado em `clearConversation`. |
|
|
184
|
+
| `event` | Passos de runtime ao vivo transmitidos de uma execução de agente (`read`/`create`/`edit`/`run`/`search`/`thinking`/`text`/`done`), agrupados por `runId` em **work-blocks** na Team Room. Podados por `pruneRunEvents`. |
|
|
185
|
+
|
|
186
|
+
## Diagrama — menção → respondentes → handoff 🛰️
|
|
187
|
+
|
|
188
|
+
```mermaid
|
|
189
|
+
flowchart TD
|
|
190
|
+
A["Operador posta na room"] --> B{"Começa com '/'?"}
|
|
191
|
+
B -- "sim" --> C["runSlashCommand"]
|
|
192
|
+
B -- "não" --> D["mentions() → handles reais"]
|
|
193
|
+
D --> E{"algum handle?"}
|
|
194
|
+
E -- "não" --> X["sem respondentes — nada postado"]
|
|
195
|
+
E -- "sim" --> F["slice(0,3) respondentes"]
|
|
196
|
+
F --> G["armazena msg do operador + logDecision se ≥15 caracteres"]
|
|
197
|
+
G --> H["agentRespond por respondente (modo chat)"]
|
|
198
|
+
H --> I["relayRoomMentions(depth 0)"]
|
|
199
|
+
I --> J{"resposta @menciona um colega?"}
|
|
200
|
+
J -- "não / noise ping" --> K["cadeia termina"]
|
|
201
|
+
J -- "sim" --> L{"guardas: fired? busyOnBoard? atCap? depth<MAX_DEPTH?"}
|
|
202
|
+
L -- "bloqueado" --> K
|
|
203
|
+
L -- "ok" --> M["colega responde em modo WORK (contexto do handoff)"]
|
|
204
|
+
M --> I
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Passo a passo
|
|
208
|
+
|
|
209
|
+
1. **Mencione um colega.** Digite `@edsger run the e2e suite on the checkout flow` na room. O composer exige ao menos um `@handle` válido.
|
|
210
|
+
2. **Até 3 respondem.** `@margaret @grace @edsger triage this bug` acende os três; uma quarta menção é descartada por `.slice(0, 3)`.
|
|
211
|
+
3. **Acompanhe o handoff.** Se Edsger responde "Failing — `@margaret` please fix the null check", Margaret é disparada em modo **work** com a mensagem de Edsger como contexto explícito de handoff, edita o arquivo e responde "Fixed — `@barbara` document the change."
|
|
212
|
+
4. **A cadeia termina.** Após `MAX_DEPTH` (2) saltos, ou quando uma resposta não menciona ninguém (ou só emite um noise ping), o relay para.
|
|
213
|
+
5. **Peça ao operador.** Quando um agente precisa da sua decisão, ele termina com `@operator` — você recebe um item de Inbox + notificação, não outro turno de agente.
|
|
214
|
+
6. **Promova à KB.** Use a ação por mensagem para enviar uma linha útil à Knowledge Base (`sendMessageToKb` → uma entrada `note`).
|
|
215
|
+
7. **Limpe.** "Clear conversation" na Welcome Home chama `clearConversation("room")` — apaga as mensagens da room, seu resumo e seus eventos de execução.
|
|
216
|
+
|
|
217
|
+
## Exemplos
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
# Uma cadeia limitada QA → fix → docs (3 saltos seriam limitados a 2):
|
|
221
|
+
Operator: @edsger smoke-test the new /settings page
|
|
222
|
+
Edsger: 404 on save — @margaret the PUT handler is missing
|
|
223
|
+
Margaret: Added the handler + test, green now — @barbara update the API doc
|
|
224
|
+
# a cadeia termina em depth 2 (a resposta de barbara, se mencionar alguém, NÃO é retransmitida)
|
|
225
|
+
|
|
226
|
+
# Dirija-se ao humano para uma decisão:
|
|
227
|
+
Grace: Two layout options attached — @operator which do you prefer?
|
|
228
|
+
# → item de Inbox "question" + notificação; nenhum agente dispara
|
|
229
|
+
|
|
230
|
+
# Transforme um pedido em novo trabalho (qualquer agente, roda o ritual):
|
|
231
|
+
Operator: @ada add a CSV export to the reports page
|
|
232
|
+
Ada: Got it — I'll turn this into a spec + issues for your approval.
|
|
233
|
+
# (Ada emite [[CREATE_WORK]] internamente → planFromConversation → CEO Planner)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Estados possíveis
|
|
237
|
+
|
|
238
|
+
| Estado | Onde | Significado |
|
|
239
|
+
|---|---|---|
|
|
240
|
+
| sem respondentes | `sendMessage` retorna `{ responders: [] }` | a mensagem não `@mencionou` nenhum agente real → ninguém responde |
|
|
241
|
+
| respondendo | agente `status = working` | a execução do CLI do agente está em andamento |
|
|
242
|
+
| retransmitido | `relayRoomMentions` dispara um colega | handoff em modo work |
|
|
243
|
+
| fim da cadeia | `depth >= MAX_DEPTH`, sem menção, ou noise ping | a cadeia autônoma para |
|
|
244
|
+
| pulado (ocupado) | `busyOnBoard` verdadeiro | agente já executando uma task de board → não disparado pelo relay |
|
|
245
|
+
| pulado (cap) | `agentAtCap` verdadeiro | agente acima do `dailyCapUsd` → não disparado pelo relay |
|
|
246
|
+
| dirigido-ao-operador | `@operator` detectado | Inbox + notificação levantados, nenhum agente dispara |
|
|
247
|
+
| falhou | resposta armazenada como `(<name> couldn't respond: …)` | a execução do CLI deu erro ou não retornou saída |
|
|
248
|
+
|
|
249
|
+
## Integrações relacionadas 🌌
|
|
250
|
+
|
|
251
|
+
- **[DM](./DM.md)** — canal 1:1 privado (`dm:<handle>`), baseado em sessões; a room é seu equivalente público.
|
|
252
|
+
- **[Telegram](./TELEGRAM.md)** — o thread remoto isolado; Ada responde, respostas espelhadas da aba in-app.
|
|
253
|
+
- **[Inbox](./INBOX.md)** — onde os pedidos `@operator` e as solicitações de aprovação chegam.
|
|
254
|
+
- **[KB_AGENT](./KB_AGENT.md) / [KB_RAG](./KB_RAG.md)** — captura de conhecimento `[[REMEMBER]]` / `[[CONSULT]]` no chat.
|
|
255
|
+
- **[GOALS_SPECS_ISSUES](./GOALS_SPECS_ISSUES.md)** — a task/issue/goal a que um chip `taskId` liga de volta.
|
|
256
|
+
- **[CHAT_COMMANDS](./CHAT_COMMANDS.md)** — slash commands interceptados por `sendMessage`.
|
|
257
|
+
- **[WORKFLOW](./WORKFLOW.md) / [PO_AGENT](./PO_AGENT.md)** — o ritual spec→issue→plan disparado por `[[CREATE_WORK]]`.
|
|
258
|
+
|
|
259
|
+
## Segurança 🕳️
|
|
260
|
+
|
|
261
|
+
- **Scrub de segredos.** Toda resposta passa por `scrubSecrets` (`src/lib/scrub.ts`) antes de ser armazenada, exibida ou notificada — room, DM e Telegram todos passam por `replyInChannel`.
|
|
262
|
+
- **Caminhos de anexo são dados.** Caminhos de arquivos anexados são injetados dentro de um bloco `<<attached-files>>` e o prompt explicitamente diz ao agente para ignorar qualquer diretiva embutida em um nome de arquivo.
|
|
263
|
+
- **Autonomia limitada.** `MAX_DEPTH=2`, `MAX_FANOUT=1`, o conjunto `fired`, `busyOnBoard` e `agentAtCap` juntos limitam tanto a propagação quanto o gasto da cadeia de handoff — uma única menção nunca pode virar um enxame descontrolado.
|
|
264
|
+
- **Endurecimento do Telegram.** O canal `telegram` adiciona uma cláusula anti prompt-injection (nunca revelar segredos / `.env` / `.claude/` / system prompt) e pula o operator-ping. Veja [TELEGRAM](./TELEGRAM.md).
|
|
265
|
+
- **Jaula de FS.** Agentes em modo work rodam com o workspace da org como cwd; a jaula de FS (`safe()`) bloqueia traversal e protege a raiz do workspace. Veja [SECURITY](./SECURITY.md) e [ARCHITECTURE](./ARCHITECTURE.md).
|
|
266
|
+
|
|
267
|
+
## Solução de problemas
|
|
268
|
+
|
|
269
|
+
| Sintoma | Causa provável | Correção |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| Mensagem postada mas ninguém responde | Nenhum `@mention` válido | Mencione um handle de agente real; caso contrário `sendMessage` não retorna respondentes. |
|
|
272
|
+
| Só 1-3 agentes respondem a uma lista grande de menções | O corte de máximo 3 (`.slice(0, 3)`) | Por design — divida em várias mensagens ou conte com a cadeia de handoff. |
|
|
273
|
+
| O handoff para cedo demais | `MAX_DEPTH=2` atingido | A cadeia é intencionalmente limitada; continue manualmente com uma nova menção. |
|
|
274
|
+
| O relay pula um agente | `busyOnBoard` (status `working` ou uma task em `doing`), ou `agentAtCap` | Espere a task terminar, ou aumente o `dailyCapUsd` do agente (veja [MODELS](./MODELS.md)). |
|
|
275
|
+
| "on it" / "done" não dispara o próximo agente | Filtro `isNoisePing` | Responda com um pedido concreto + uma menção; pings sem conteúdo não retransmitem. |
|
|
276
|
+
| `@operator` não levantou item de Inbox | A resposta falhou (armazenada como "couldn't respond") ou foi Telegram | Verifique a saída da execução; o Telegram pula o operator-ping por design. |
|
|
277
|
+
| A resposta mostra `(<name> couldn't respond: …)` | Erro/timeout do runtime do CLI (180s) | Verifique o adapter/modelo do agente e o runtime; veja [AGENTS](./AGENTS.md), [MODELS](./MODELS.md), [TROUBLESHOOTING](./TROUBLESHOOTING.md). |
|
|
278
|
+
|
|
279
|
+
## Links relacionados
|
|
280
|
+
|
|
281
|
+
- [DM](./DM.md) · [Telegram](./TELEGRAM.md) · [Inbox](./INBOX.md)
|
|
282
|
+
- [Agentes](./AGENTS.md) · [Agente de KB](./KB_AGENT.md) · [Agente PO](./PO_AGENT.md)
|
|
283
|
+
- [Workflow](./WORKFLOW.md) · [Goals, Specs & Issues](./GOALS_SPECS_ISSUES.md) · [Chat Commands](./CHAT_COMMANDS.md)
|
|
284
|
+
- [KB & RAG](./KB_RAG.md) · [Memória & RAG](./MEMORY_RAG.md) · [Synced Blocks](./SYNCED_BLOCKS.md)
|
|
285
|
+
- [Arquitetura](./ARCHITECTURE.md) · [Arquitetura de IA](./AI_ARCHITECTURE.md) · [Segurança](./SECURITY.md) · [Solução de problemas](./TROUBLESHOOTING.md)
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
[← Índice](./README.md) · [🇬🇧 English](../en/TELEGRAM.md) · [✦ Constella](../../README.pt-BR.md)
|
|
2
|
+
|
|
3
|
+
# 🛰️ Telegram — a ponte de bolso para a sua constelação
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
Um único chat privado do Telegram vira uma ponte remota para a sua empresa de agentes: você conversa com a CEO (Ada), aprova planos, liga ou pausa a execução 24/7, dispara novos trabalhos e consulta a Base de Conhecimento — tudo pelo celular, enquanto a nave de controle continua rodando sem interface.
|
|
8
|
+
|
|
9
|
+
> Fonte da verdade: `src/server/telegram.ts` (ingest + comandos + callbacks), `src/lib/telegram.ts` (cliente da Bot API + formato do token), `bin/worker.mjs` (loop de long-poll), `src/app/api/telegram/poll/route.ts` (entrada exclusiva do worker), `src/server/actions/profile-actions.ts` (`connectTelegram`), `src/lib/scrub.ts` (limpeza de segredos).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 2. O que é
|
|
14
|
+
|
|
15
|
+
Um bot do Telegram bidirecional, restrito a **um** chat privado por workspace (allowlist). Mensagens recebidas chegam à agente CEO por um canal **isolado** (`telegram`), e um conjunto de comandos de barra + botões inline funcionam como um controle remoto real sobre o ciclo de trabalho. Saída: respostas da agente digitadas na aba Telegram dentro do app são espelhadas de volta para o celular, mantendo a conversa em uma única thread independentemente de onde você digitou.
|
|
16
|
+
|
|
17
|
+
## 3. Quando usar 🌠
|
|
18
|
+
|
|
19
|
+
- Você está longe da nave de controle mas quer **ver o status**, **aprovar um plano pendente** ou **ligar/desligar a execução 24/7**.
|
|
20
|
+
- Você quer **iniciar um novo trabalho** a partir de um briefing de uma linha (`/new …`) e deixar a CEO transformá-lo em specs · issues · TODOs.
|
|
21
|
+
- Você quer **perguntar à Base de Conhecimento** (`/kb …`) sem abrir o app.
|
|
22
|
+
- Você quer **conversar com a CEO** (Ada) como em qualquer DM, mas pelo celular.
|
|
23
|
+
|
|
24
|
+
O Telegram é opcional. É um plugin nativo e o toggle de integração (`settings.integrations.telegram`) vem **LIGADO** por padrão, mas nada acontece até você conectar um token de bot + chat id pela tela de Perfil. Se não estiver configurado, todo caminho do Telegram é um no-op honesto.
|
|
25
|
+
|
|
26
|
+
## 4. Como funciona 🌌
|
|
27
|
+
|
|
28
|
+
### Os dois processos
|
|
29
|
+
|
|
30
|
+
A Constella roda um processo **web** (Next.js) e um **worker** separado (`bin/worker.mjs`). O polling do Telegram vive no worker:
|
|
31
|
+
|
|
32
|
+
- O worker roda `telegramLoop()` — um loop infinito que faz POST em `BASE/api/telegram/poll` com o header privilegiado `x-worker-secret`.
|
|
33
|
+
- Essa rota (`src/app/api/telegram/poll/route.ts`) é **fail-closed**: exige `CONSTELLA_WORKER_SECRET` e retorna `401` se o header faltar/estiver errado. Em `401`, o worker recua por 30s (tratado como "não configurado / segredo divergente").
|
|
34
|
+
- A rota chama `pollTelegram()` (em `src/server/telegram.ts`), que faz o trabalho real, e devolve `{ ok, updates }`.
|
|
35
|
+
|
|
36
|
+
### Long-polling, por workspace
|
|
37
|
+
|
|
38
|
+
`pollTelegram()` itera por **todos** os workspaces. Para cada um, ela:
|
|
39
|
+
|
|
40
|
+
1. Pula o workspace se a integração estiver desligada (`integrationOn(settings.integrations, "telegram")` — veja `src/lib/integrations.ts`).
|
|
41
|
+
2. Carrega a config do cofre via `getTelegramConfig(ws.id)`; pula se ausente ou se o token estiver malformado.
|
|
42
|
+
3. Registra o menu de comandos `/` do bot **uma vez por bot por processo** (`tgSetMyCommands`, protegido por um set em memória `commandsRegistered`).
|
|
43
|
+
4. Chama `tgGetUpdates(token, offset)` — o `getUpdates` do Telegram com `timeout=25` (um **long-poll do lado do servidor** de ~25s) e `allowed_updates=["message","callback_query"]`.
|
|
44
|
+
5. Faz o ingest de cada update, avança o cursor (`maxId = update_id + 1`) e persiste de volta em `settings.telegram.offset`.
|
|
45
|
+
|
|
46
|
+
O worker deixa um intervalo breve de 1s entre os long-polls; em erro, recua por 5s.
|
|
47
|
+
|
|
48
|
+
### A allowlist 🕳️
|
|
49
|
+
|
|
50
|
+
Somente o **único chat privado registrado** pode comandar o bot. Em `ingest()`:
|
|
51
|
+
|
|
52
|
+
- O `chat.id` da mensagem deve ser igual a `cfg.chatId`, **e**
|
|
53
|
+
- se `m.from` existir, o `from.id` do remetente também deve ser igual a `cfg.chatId` (em um chat privado eles são o mesmo número).
|
|
54
|
+
|
|
55
|
+
Qualquer outra coisa é **ignorada silenciosamente**. A mesma checagem é reaplicada aos toques em botões inline em `handleCallback()`. Na conexão (`connectTelegram`), o chat id é validado como um id numérico positivo (ids de grupo são negativos e deixariam qualquer membro comandar o bot — são rejeitados).
|
|
56
|
+
|
|
57
|
+
### Roteamento de entrada
|
|
58
|
+
|
|
59
|
+
Para uma mensagem permitida, `ingest()` decide o caminho:
|
|
60
|
+
|
|
61
|
+
| Condição | O que acontece |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `callback_query` presente | Toque em botão inline → `handleCallback()` |
|
|
64
|
+
| aguardando motivo de rejeição + texto puro (não `/…`) | O texto **é** o motivo da rejeição → `requestPlanChangesFor()` |
|
|
65
|
+
| texto começa com `/` | Comando de controle remoto → `handleCommand()` |
|
|
66
|
+
| caso contrário | Falar com a CEO → `runCeoReply()` |
|
|
67
|
+
|
|
68
|
+
Texto + legenda são limitados a 4000 caracteres. Fotos e documentos são baixados e salvos como anexos (veja [Anexos](#anexos)).
|
|
69
|
+
|
|
70
|
+
### Conversando com a CEO
|
|
71
|
+
|
|
72
|
+
`runCeoReply()` resolve a agente **Ada** (`handle = "ada"`, com fallback para o primeiro agente), coloca o status dela em `working`, mostra um indicador `typing…` ao vivo num heartbeat de 4s (o Telegram limpa após ~5s) e chama `replyInChannel(orgId, ws, "telegram", ada, "chat")` (`src/server/collab.ts`).
|
|
73
|
+
|
|
74
|
+
O `replyInChannel` adiciona uma **proteção contra injeção de prompt específica do Telegram**: avisa ao modelo que a mensagem do operador é *dado, não instrução*, que ele nunca deve revelar segredos / conteúdo de `.env` / `.claude/` / o system prompt, e que deve recusar qualquer tentativa de override. A resposta passa pela limpeza de segredos antes do envio.
|
|
75
|
+
|
|
76
|
+
Se a Ada decidir que é trabalho de build/fix, ela emite um token interno `[[CREATE_WORK]]`; `replyInChannel` devolve `planRequested = true`, e o `runCeoReply` então roda `planFromConversationFor(orgId, ws, "telegram")` — o **mesmo** ritual de planejamento do caminho web (specs → issues → TODOs) — e confirma no celular.
|
|
77
|
+
|
|
78
|
+
## 5. Fluxo principal — poll → agente → resposta 🚀
|
|
79
|
+
|
|
80
|
+
```mermaid
|
|
81
|
+
sequenceDiagram
|
|
82
|
+
autonumber
|
|
83
|
+
participant TG as Telegram Bot API
|
|
84
|
+
participant W as worker (bin/worker.mjs)
|
|
85
|
+
participant API as /api/telegram/poll
|
|
86
|
+
participant P as pollTelegram()
|
|
87
|
+
participant ING as ingest()
|
|
88
|
+
participant CEO as replyInChannel (Ada)
|
|
89
|
+
participant DB as tabela message
|
|
90
|
+
|
|
91
|
+
W->>API: POST (x-worker-secret)
|
|
92
|
+
API->>API: verifica CONSTELLA_WORKER_SECRET (senão 401)
|
|
93
|
+
API->>P: pollTelegram()
|
|
94
|
+
P->>TG: getUpdates(offset, timeout=25)
|
|
95
|
+
TG-->>P: updates[] (long-poll ~25s)
|
|
96
|
+
loop cada update
|
|
97
|
+
P->>ING: ingest(ws, cfg, update)
|
|
98
|
+
ING->>ING: allowlist: chat.id == cfg.chatId?
|
|
99
|
+
alt comando (/…)
|
|
100
|
+
ING->>ING: handleCommand() → ação real
|
|
101
|
+
else botão inline
|
|
102
|
+
ING->>ING: handleCallback() → ação real
|
|
103
|
+
else texto livre
|
|
104
|
+
ING->>DB: persiste turno do operador (channel=telegram)
|
|
105
|
+
ING->>CEO: replyInChannel(..., "chat")
|
|
106
|
+
CEO-->>ING: text + planRequested
|
|
107
|
+
ING->>TG: sendMessage(resposta limpa)
|
|
108
|
+
opt planRequested
|
|
109
|
+
ING->>ING: planFromConversationFor() (specs·issues·TODOs)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
P->>DB: salva settings.telegram.offset = maxId
|
|
114
|
+
P-->>W: { updates: N }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 6. Conceitos-chave ✦
|
|
118
|
+
|
|
119
|
+
- **Canal isolado.** O Telegram vive em seu próprio canal `telegram` — nunca `room` ou `dm:<handle>` — então a conversa do celular nunca vaza contexto para a team room ou DMs. (`TG_CHANNEL = "telegram"`.)
|
|
120
|
+
- **Credenciais no cofre.** O token do bot + chat id ficam criptografados no cofre sob o ref `telegram_bot` como JSON `{botToken, chatId, allowedName}`. Nunca são persistidos em settings em texto puro.
|
|
121
|
+
- **Cursor de offset.** `settings.telegram.offset` é o cursor de updates do Telegram; avançá-lo confirma os updates processados para que nunca sejam reentregues.
|
|
122
|
+
- **Espera pelo motivo da rejeição.** Um set em memória `awaitingReason` lembra que você tocou no botão **↩️ Reject**; sua próxima mensagem de texto puro vira o motivo. Em memória basta — um restart do servidor simplesmente descarta a espera pendente (toque de novo para repetir).
|
|
123
|
+
- **Registro do menu de comandos.** `commandsRegistered` garante que `setMyCommands` rode uma vez por bot por processo — até bots conectados antes desse recurso existir recebem o menu no próximo poll.
|
|
124
|
+
- **Limpeza de segredos.** Toda string de saída passa por `scrubSecrets(text, [cfg.botToken])` (`src/lib/scrub.ts`) — redigindo o token do bot, os segredos de ambiente padrão e formatos de credenciais de alta confiança (OpenAI/Anthropic `sk-…`, tokens do GitHub, chaves AWS, JWTs, chaves PEM, PATs `cn_…` da Constella e até outros tokens do Telegram).
|
|
125
|
+
|
|
126
|
+
## 7. Tabelas
|
|
127
|
+
|
|
128
|
+
### Comandos de barra do Telegram (`handleCommand`)
|
|
129
|
+
|
|
130
|
+
| Comando | Aliases | Ação |
|
|
131
|
+
| --- | --- | --- |
|
|
132
|
+
| `/help` | — | Mostra o texto de ajuda do controle remoto |
|
|
133
|
+
| `/status` | — | `planStatusFor(ws)` — status rápido |
|
|
134
|
+
| `/review` | — | `reviewSummaryFor(ws)` — resumo de plano / issues / tasks |
|
|
135
|
+
| `/tasks` | — | `tasksListFor(ws)` — o que está em andamento agora |
|
|
136
|
+
| `/approve` | — | `approvePlanFor()` — aprova o plano pendente, enfileira tasks |
|
|
137
|
+
| `/start_execution` | `/start`, `/run` | `approvePlanFor()` + `setAuto247For(true)` — aprova e roda 24/7 |
|
|
138
|
+
| `/pause` | `/stop` | `setAuto247For(false)` — pausa o 24/7 |
|
|
139
|
+
| `/resume` | — | `setAuto247For(true)` — retoma o 24/7 |
|
|
140
|
+
| `/reject <motivo>` | — | `requestPlanChangesFor()` — devolve o plano à CEO |
|
|
141
|
+
| `/new <briefing>` | `/new-work`, `/new-goal` | Injeta um turno do operador + roda a CEO → goal · specs · issues |
|
|
142
|
+
| `/cancel` | — | `cancelGoalFor()` no goal ativo mais recente — para a execução |
|
|
143
|
+
| `/archive` | — | `archiveGoalFor()` no goal ativo mais recente — zipa + arquiva |
|
|
144
|
+
| `/kb <pergunta>` | `/ask-kb` | `kbAnswer(orgId, q)` — pergunta à Base de Conhecimento |
|
|
145
|
+
| *(desconhecido)* | — | Responde "Unknown command" + ajuda |
|
|
146
|
+
|
|
147
|
+
> O menu `/` que o Telegram mostra é registrado a partir de `TG_BOT_COMMANDS` em `src/lib/telegram.ts` e deve espelhar `handleCommand`. O menu exibido omite os aliases.
|
|
148
|
+
|
|
149
|
+
### Callbacks de botão inline (`handleCallback`)
|
|
150
|
+
|
|
151
|
+
| `callback_data` | Ação | Toast | One-shot? |
|
|
152
|
+
| --- | --- | --- | --- |
|
|
153
|
+
| `approve_plan` | `approvePlanFor()` | ✅ Approved | sim (teclado removido) |
|
|
154
|
+
| `start_exec` | `approvePlanFor()` + `setAuto247For(true)` | ▶️ Executing | sim |
|
|
155
|
+
| `reject_plan` | `requestPlanChangesFor()` + arma a espera do motivo | ↩️ Sent back | sim |
|
|
156
|
+
| `review` | `reviewSummaryFor(ws)` | 📝 Review | não |
|
|
157
|
+
| `status` | `planStatusFor(ws)` | 📊 Status | não |
|
|
158
|
+
| `pause` | `setAuto247For(false)` | ⏸ Paused | não |
|
|
159
|
+
| `resume` | `setAuto247For(true)` | ▶️ Resumed | não |
|
|
160
|
+
| *(desconhecido)* | — | Unknown action | — |
|
|
161
|
+
|
|
162
|
+
Ações one-shot (`approve_plan` / `start_exec` / `reject_plan`) têm seu teclado inline removido via `tgClearButtons`, para que um segundo toque não as dispare de novo.
|
|
163
|
+
|
|
164
|
+
### Config do cofre & settings
|
|
165
|
+
|
|
166
|
+
| Onde | Chave / coluna | Significado |
|
|
167
|
+
| --- | --- | --- |
|
|
168
|
+
| cofre | ref `telegram_bot` | JSON criptografado `{botToken, chatId, allowedName}` |
|
|
169
|
+
| `workspace.settings` | `integrations.telegram` | toggle de integração (padrão `true`) |
|
|
170
|
+
| `workspace.settings` | `telegram.offset` | cursor do `getUpdates` do Telegram |
|
|
171
|
+
|
|
172
|
+
### Linhas em `message` escritas pelo Telegram
|
|
173
|
+
|
|
174
|
+
| Coluna | Valor no caminho do Telegram |
|
|
175
|
+
| --- | --- |
|
|
176
|
+
| `channel` | `"telegram"` (constante `TG_CHANNEL`) |
|
|
177
|
+
| `fromKind` | `"operator"` (entrada) / `"agent"` (respostas) |
|
|
178
|
+
| `fromHandle` | `"system"` para respostas de controle; handle da Ada para respostas da CEO |
|
|
179
|
+
| `text` | texto da mensagem ou `"(attachment)"`, limitado a 4000 |
|
|
180
|
+
| `attachments` | descritores de arquivos salvos, ou `null` |
|
|
181
|
+
|
|
182
|
+
## 8. Superfície da Bot API 🪐
|
|
183
|
+
|
|
184
|
+
Todas as chamadas HTTP passam por `src/lib/telegram.ts` contra `https://api.telegram.org`. Cada helper primeiro checa `isTelegramToken()` — formato do token `^\d{6,}:[A-Za-z0-9_-]{30,}$` — para que um valor malformado nunca consiga repontar a URL da requisição.
|
|
185
|
+
|
|
186
|
+
| Helper | Método da Bot API | Propósito |
|
|
187
|
+
| --- | --- | --- |
|
|
188
|
+
| `tgGetMe` | `getMe` | verifica o token → `@username` (na conexão) |
|
|
189
|
+
| `tgSetMyCommands` | `setMyCommands` | registra o menu de comandos `/` |
|
|
190
|
+
| `tgGetUpdates` | `getUpdates` | long-poll (`timeout=25`, `message` + `callback_query`) |
|
|
191
|
+
| `tgGetFile` | `getFile` + `/file/bot…` | baixa uma foto/documento → bytes |
|
|
192
|
+
| `tgSendChatAction` | `sendChatAction` | indicador `typing…` |
|
|
193
|
+
| `sendTelegramTo` | `sendMessage` | resposta em texto puro (sem Markdown) |
|
|
194
|
+
| `sendTelegram` | `sendMessage` | envio de notificação (Markdown) |
|
|
195
|
+
| `sendTelegramButtons` | `sendMessage` + `inline_keyboard` | mensagem com botões de controle remoto |
|
|
196
|
+
| `tgAnswerCallback` | `answerCallbackQuery` | confirma um toque de botão + toast opcional |
|
|
197
|
+
| `tgClearButtons` | `editMessageReplyMarkup` | remove um teclado one-shot |
|
|
198
|
+
|
|
199
|
+
Respostas da agente usam `sendTelegramTo` (texto puro, sem `parse_mode`) de propósito — conteúdo arbitrário (títulos de issues, código, nomes de workspace) nunca deve quebrar o envio nem ser interpretado como Markdown.
|
|
200
|
+
|
|
201
|
+
## 9. Anexos
|
|
202
|
+
|
|
203
|
+
Fotos e documentos em uma mensagem recebida são baixados e armazenados no workspace:
|
|
204
|
+
|
|
205
|
+
- Um id curto de download por mensagem é gerado (`uid().slice(0,8)`).
|
|
206
|
+
- Cada arquivo é buscado via `tgGetFile`, tem o nome sanitizado (`[^\w.\-]` → `_`, últimos 60 caracteres) e é gravado em `uploads/tg-<dlId>/<nome-seguro>` sob a **raiz da org** (`orgRoot(ws.orgId)`).
|
|
207
|
+
- Um descritor de anexo `{name, type, size, path}` é adicionado ao `message.attachments` persistido.
|
|
208
|
+
- Fotos usam o maior tamanho disponível; documentos mantêm seu `file_name` e `mime_type` originais.
|
|
209
|
+
|
|
210
|
+
Uma mensagem sem texto e sem nenhum anexo salvo é descartada.
|
|
211
|
+
|
|
212
|
+
## 10. Passo a passo — conectar & comandar 🛰️
|
|
213
|
+
|
|
214
|
+
### Conectar o bot (`connectTelegram`)
|
|
215
|
+
|
|
216
|
+
1. Crie um bot com o **@BotFather** do Telegram e copie o token.
|
|
217
|
+
2. Descubra seu **chat id numérico pessoal** (um chat privado — não um grupo).
|
|
218
|
+
3. Na tela de **Perfil** da Constella, informe o token + chat id (e um nome de exibição opcional).
|
|
219
|
+
4. `connectTelegram()` valida o formato do token, rejeita ids não-positivos/de grupo, chama `tgGetMe` para verificar que o token realmente funciona, então armazena `{botToken, chatId, allowedName}` no cofre e registra o menu `/` (`tgSetMyCommands`).
|
|
220
|
+
5. O worker pega isso no próximo poll — mande uma mensagem ao bot para confirmar.
|
|
221
|
+
|
|
222
|
+
> `telegramStatus()` alimenta o card no app e mascara o chat id (`12•••89`). `disconnectTelegram()` apaga o ref `telegram_bot` do cofre.
|
|
223
|
+
|
|
224
|
+
### Comandar pelo celular
|
|
225
|
+
|
|
226
|
+
```text
|
|
227
|
+
/status → status rápido
|
|
228
|
+
/review → resumo completo de plano / issues / tasks
|
|
229
|
+
/new uma página de cobrança com checkout
|
|
230
|
+
→ a CEO rascunha goal · specs · issues · TODOs
|
|
231
|
+
/approve → enfileira as tasks
|
|
232
|
+
/start_execution → aprova + 24/7 LIGADO
|
|
233
|
+
/pause /resume → liga/desliga o 24/7
|
|
234
|
+
/reject use Stripe e não PayPal→ devolve o plano com um motivo
|
|
235
|
+
/cancel /archive → para / arquiva o goal ativo
|
|
236
|
+
/kb como funciona a auth? → pergunta à Base de Conhecimento
|
|
237
|
+
só conversar normalmente → fala com a CEO (Ada)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Espelhamento (app → celular)
|
|
241
|
+
|
|
242
|
+
Quando você responde pela **aba Telegram dentro do app**, `src/server/chat.ts` chama `mirrorToTelegram(workspace.id, reply)`. Ele carrega a config do cofre e envia a resposta já limpa para o chat real — mantendo a conversa do bot numa única thread independentemente de onde você digitou.
|
|
243
|
+
|
|
244
|
+
## 11. Estados possíveis
|
|
245
|
+
|
|
246
|
+
| Estado | Sintoma | Causa |
|
|
247
|
+
| --- | --- | --- |
|
|
248
|
+
| **Não configurado** | Bot nunca responde; rota de poll retorna `401` e depois recua 30s | sem segredo `telegram_bot` no cofre |
|
|
249
|
+
| **Integração desligada** | Configurado mas ignorado | `settings.integrations.telegram = false` |
|
|
250
|
+
| **Conectado** | Respostas, comandos e botões funcionam | token válido + chat id correspondente |
|
|
251
|
+
| **Chat estranho** | Silêncio | id de remetente / chat ≠ `cfg.chatId` (ignorado silenciosamente) |
|
|
252
|
+
| **Aguardando motivo** | Próxima mensagem de texto registrada como motivo da rejeição | você tocou em **↩️ Reject** |
|
|
253
|
+
| **Typing…** | Indicador ao vivo enquanto a resposta é gerada | heartbeat de 4s em `runCeoReply` |
|
|
254
|
+
| **Worker fora do ar** | Nenhuma resposta | o processo worker não está rodando (veja [TEST_DEV](./TEST_DEV.md) / [ARCHITECTURE](./ARCHITECTURE.md)) |
|
|
255
|
+
|
|
256
|
+
## 12. Integrações relacionadas
|
|
257
|
+
|
|
258
|
+
- O caminho de resposta da CEO é o mesmo usado por [DM](./DM.md) e pela [TEAM_ROOM](./TEAM_ROOM.md) — o Telegram só o roda em seu canal isolado com uma proteção extra contra injeção.
|
|
259
|
+
- `/new` roda o ritual completo do [WORKFLOW](./WORKFLOW.md) (Goal → Spec → Issue → Plan → TODOs); veja [GOALS_SPECS_ISSUES](./GOALS_SPECS_ISSUES.md).
|
|
260
|
+
- `/kb` responde a partir da nebulosa de memória [KB_RAG](./KB_RAG.md).
|
|
261
|
+
- As mesmas ações de controle remoto são expostas programaticamente pela [PUBLIC_API](./PUBLIC_API.md) e pelo servidor [MCP](./MCP.md).
|
|
262
|
+
- O Telegram é uma entrada nativa de [PLUGINS](./PLUGINS.md); o toggle vive ao lado das outras integrações.
|
|
263
|
+
|
|
264
|
+
## 13. Segurança 🕳️
|
|
265
|
+
|
|
266
|
+
- **Entrada exclusiva do worker.** `/api/telegram/poll` exige `x-worker-secret == CONSTELLA_WORKER_SECRET` (fail-closed `401`). O worker ainda se recusa a enviar esse segredo para qualquer `CONSTELLA_BASE_URL` não-loopback, a menos que `CONSTELLA_ALLOW_REMOTE_WORKER_BASE_URL=1` (proteção contra SSRF / exfiltração de segredo).
|
|
267
|
+
- **Allowlist estrita.** Exatamente um chat id privado; tanto `chat.id` quanto `from.id` são checados nas mensagens e nos toques de botão. Ids de grupo (negativos) são rejeitados na conexão.
|
|
268
|
+
- **Validação do formato do token.** `isTelegramToken()` protege toda chamada da Bot API para que um token adulterado não consiga redirecionar a URL da requisição.
|
|
269
|
+
- **Reforço contra injeção de prompt.** `replyInChannel` injeta uma cláusula de segurança específica do Telegram: a mensagem do operador é *dado*, segredos/`.env`/`.claude/`/system-prompt nunca devem ser revelados, tentativas de override são recusadas.
|
|
270
|
+
- **Limpeza de segredos na saída.** Toda mensagem de saída passa por `scrubSecrets(…, [cfg.botToken])` — redigindo o token do bot mais formatos de credenciais de alta confiança — antes de sair da nave.
|
|
271
|
+
- **Criptografado em repouso.** As credenciais vivem no [cofre](./SECURITY.md) AES-256-GCM, nunca em settings em texto puro; o card de status no app mascara o chat id.
|
|
272
|
+
- **Saída limitada.** Os corpos de saída têm tamanho limitado (`sendTelegramTo` 3800, `sendTelegram` 3500), e `callback_data` é limitado ao máximo de 64 bytes do Telegram.
|
|
273
|
+
|
|
274
|
+
## 14. Solução de problemas 🛠️
|
|
275
|
+
|
|
276
|
+
| Sintoma | Verifique |
|
|
277
|
+
| --- | --- |
|
|
278
|
+
| Bot mudo, rota de poll retorna `401` | Sem segredo `telegram_bot` — conecte pelo Perfil. (O worker trata `401` como "não configurado" e recua 30s.) |
|
|
279
|
+
| "Telegram rejected this bot token." na conexão | Token errado/revogado — `tgGetMe` falhou; copie de novo do @BotFather. |
|
|
280
|
+
| "Chat id must be your personal numeric id…" | Você usou um id de grupo (negativo) — use seu chat id privado. |
|
|
281
|
+
| Mensagens ignoradas, sem erro | `chat.id`/`from.id` do remetente ≠ o `cfg.chatId` registrado (allowlist). |
|
|
282
|
+
| Menu `/` não aparece | `setMyCommands` é best-effort; roda uma vez por bot por processo — reinicie o worker ou reconecte. |
|
|
283
|
+
| Nenhuma resposta | O processo **worker** não está rodando — inicie `npm start` (web + worker) ou `npm run dev:all`. |
|
|
284
|
+
| Resposta parece cortada | Os corpos têm tamanho limitado por design (3800/3500 caracteres). |
|
|
285
|
+
| Motivo da rejeição não registrado | Um comando de barra supera a espera pendente do motivo; envie o motivo como texto puro logo após tocar em ↩️ Reject. |
|
|
286
|
+
|
|
287
|
+
## 15. Links relacionados
|
|
288
|
+
|
|
289
|
+
- [DM](./DM.md) · [TEAM_ROOM](./TEAM_ROOM.md) · [CHAT_COMMANDS](./CHAT_COMMANDS.md)
|
|
290
|
+
- [WORKFLOW](./WORKFLOW.md) · [GOALS_SPECS_ISSUES](./GOALS_SPECS_ISSUES.md)
|
|
291
|
+
- [KB_RAG](./KB_RAG.md) · [KB_AGENT](./KB_AGENT.md)
|
|
292
|
+
- [PUBLIC_API](./PUBLIC_API.md) · [MCP](./MCP.md) · [PLUGINS](./PLUGINS.md)
|
|
293
|
+
- [ARCHITECTURE](./ARCHITECTURE.md) · [AI_ARCHITECTURE](./AI_ARCHITECTURE.md) · [SECURITY](./SECURITY.md)
|
|
294
|
+
- [CONFIGURATION](./CONFIGURATION.md) · [TROUBLESHOOTING](./TROUBLESHOOTING.md) · [FAQ](./FAQ.md)
|