* Fix flat replies in DMs DM replies were threaded under Adam's message instead of appearing flat. Root cause: listener fell back to event["ts"] as thread_ts for new DMs, causing say() to post as a threaded reply. Removed the fallback so DMs always use flat messages with placeholder update. Closes #4 * Add synchronous digest trigger for inline stats Changed trigger_daily_digest from async (fire-and-forget) to synchronous invocation so Lauren can report summary stats inline while the full Block Kit digest arrives as a separate DM. Closes #1 * Add tasks and reminders - DynamoDB task CRUD with TASK#{ulid} prefix - 5 new tools: create_task, list_tasks, complete_task, delete_task, create_reminder - New exec-aide-reminder Lambda triggered by EventBridge Scheduler one-shots - CDK: reminder Lambda, scheduler IAM role, conversation Lambda permissions - Updated system prompt with task/reminder capabilities Closes #3 * Add Google Calendar integration - New src/shared/calendar.py: OAuth service builder, list_events, create_event, check_availability (reuses gmail-oauth secret) - 3 new tools: get_calendar_events, create_calendar_event, check_availability - Extended OAuth scopes to include calendar in gmail.py and token script - Updated system prompt with calendar capabilities Requires re-running scripts/get_gmail_token.py to grant the calendar scope and updating the exec-aide/gmail-oauth secret with the new refresh token. Closes #2 * Add CodeBuild CI/CD pipeline CodePipeline triggers on pushes to main, CodeBuild runs cdk deploy via buildspec. * Update README for tasks, reminders, calendar, and CI/CD pipeline
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""One-time OAuth token exchange for Gmail API access.
|
|
|
|
Usage:
|
|
1. Download OAuth client JSON from Google Cloud Console
|
|
2. Run: python scripts/get_gmail_token.py --client-secrets-file path/to/client_secret.json
|
|
3. Authorize as adam@seahavenind.com in the browser
|
|
4. Copy the output JSON into Secrets Manager:
|
|
aws secretsmanager create-secret --name exec-aide/gmail-oauth --secret-string '<json>'
|
|
"""
|
|
import argparse
|
|
import json
|
|
|
|
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
|
|
SCOPES = [
|
|
"https://www.googleapis.com/auth/gmail.readonly",
|
|
"https://www.googleapis.com/auth/calendar",
|
|
]
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Get Gmail OAuth refresh token")
|
|
parser.add_argument(
|
|
"--client-secrets-file",
|
|
required=True,
|
|
help="Path to the OAuth client secrets JSON downloaded from Google Cloud Console",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
flow = InstalledAppFlow.from_client_secrets_file(args.client_secrets_file, SCOPES)
|
|
creds = flow.run_local_server(port=8080)
|
|
|
|
secret = {
|
|
"client_id": creds.client_id,
|
|
"client_secret": creds.client_secret,
|
|
"refresh_token": creds.refresh_token,
|
|
"access_token": creds.token,
|
|
"token_expiry": creds.expiry.isoformat() if creds.expiry else "",
|
|
}
|
|
|
|
print("\nStore this in Secrets Manager as exec-aide/gmail-oauth:\n")
|
|
print(json.dumps(secret, indent=2))
|
|
print(
|
|
"\nCommand:\n"
|
|
f"aws secretsmanager create-secret --name exec-aide/gmail-oauth "
|
|
f"--secret-string '{json.dumps(secret)}'"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|