chore: aden provider factory method

This commit is contained in:
Timothy
2026-01-28 14:04:08 -08:00
parent 3a308ba67e
commit 480ade22ce
3 changed files with 244 additions and 2 deletions
+145
View File
@@ -0,0 +1,145 @@
# Triage Issue Skill
Analyze a GitHub issue, verify claims against the codebase, and close invalid issues with a technical response.
## Trigger
User provides a GitHub issue URL or number, e.g.:
- `/triage-issue 1970`
- `/triage-issue https://github.com/adenhq/hive/issues/1970`
## Workflow
### Step 1: Fetch Issue Details
```bash
gh issue view <number> --repo adenhq/hive --json title,body,state,labels,author
```
Extract:
- Title
- Body (the claim/bug report)
- Current state
- Labels
- Author
If issue is already closed, inform user and stop.
### Step 2: Analyze the Claim
Read the issue body and identify:
1. **The core claim** - What is the user asserting?
2. **Technical specifics** - File paths, function names, code snippets mentioned
3. **Expected behavior** - What do they think should happen?
4. **Severity claimed** - Security issue? Bug? Feature request?
### Step 3: Investigate the Codebase
For each technical claim:
1. Find the referenced code using Grep/Glob/Read
2. Understand the actual implementation
3. Check if the claim accurately describes the behavior
4. Look for related tests, documentation, or design decisions
### Step 4: Evaluate Validity
Categorize the issue as one of:
| Category | Action |
|----------|--------|
| **Valid Bug** | Do NOT close. Inform user this is a real issue. |
| **Valid Feature Request** | Do NOT close. Suggest labeling appropriately. |
| **Misunderstanding** | Prepare technical explanation for why behavior is correct. |
| **Fundamentally Flawed** | Prepare critique explaining the technical impossibility or design rationale. |
| **Duplicate** | Find the original issue and prepare duplicate notice. |
| **Incomplete** | Prepare request for more information. |
### Step 5: Draft Response
For issues to be closed, draft a response that:
1. **Acknowledges the concern** - Don't be dismissive
2. **Explains the actual behavior** - With code references
3. **Provides technical rationale** - Why it works this way
4. **References industry standards** - If applicable
5. **Offers alternatives** - If there's a better approach for the user
Use this template:
```markdown
## Analysis
[Brief summary of what was investigated]
## Technical Details
[Explanation with code references]
## Why This Is Working As Designed
[Rationale]
## Recommendation
[What the user should do instead, if applicable]
---
*This issue was reviewed and closed by the maintainers.*
```
### Step 6: User Review
Present the draft to the user with:
```
## Issue #<number>: <title>
**Claim:** <summary of claim>
**Finding:** <valid/invalid/misunderstanding/etc>
**Draft Response:**
<the markdown response>
---
Do you want me to post this comment and close the issue?
```
Use AskUserQuestion with options:
- "Post and close" - Post comment, close issue
- "Edit response" - Let user modify the response
- "Skip" - Don't take action
### Step 7: Execute Action
If user approves:
```bash
# Post comment
gh issue comment <number> --repo adenhq/hive --body "<response>"
# Close issue
gh issue close <number> --repo adenhq/hive --reason "not planned"
```
Report success with link to the issue.
## Important Guidelines
1. **Never close valid issues** - If there's any merit to the claim, don't close it
2. **Be respectful** - The reporter took time to file the issue
3. **Be technical** - Provide code references and evidence
4. **Be educational** - Help them understand, don't just dismiss
5. **Check twice** - Make sure you understand the code before declaring something invalid
6. **Consider edge cases** - Maybe their environment reveals a real issue
## Example Critiques
### Security Misunderstanding
> "The claim that secrets are exposed in plaintext misunderstands the encryption architecture. While `SecretStr` is used for logging protection, actual encryption is provided by Fernet (AES-128-CBC) at the storage layer. The code path is: serialize → encrypt → write. Only encrypted bytes touch disk."
### Impossible Request
> "The requested feature would require [X] which violates [fundamental constraint]. This is not a limitation of our implementation but a fundamental property of [technology/protocol]."
### Already Handled
> "This scenario is already handled by [code reference]. The reporter may be using an older version or misconfigured environment."
+5 -2
View File
@@ -175,8 +175,8 @@ class AdenIntegrationInfo:
return cls(
integration_id=data["integration_id"],
integration_type=data["integration_type"],
status=data["status"],
integration_type=data.get("provider", data["integration_id"]),
status=data.get("status", "unknown"),
expires_at=expires_at,
)
@@ -254,6 +254,9 @@ class AdenCredentialClient:
) -> httpx.Response:
"""Make a request with retry logic."""
client = self._get_client()
print(client.base_url)
print(client.headers)
print(method, path, kwargs)
last_error: Exception | None = None
for attempt in range(self.config.retry_attempts):
+94
View File
@@ -612,3 +612,97 @@ class CredentialStore:
providers=providers,
**kwargs,
)
@classmethod
def with_aden_sync(
cls,
base_url: str = "https://hive.adenhq.com",
cache_ttl_seconds: int = 300,
local_path: str | None = None,
auto_sync: bool = True,
**kwargs: Any,
) -> CredentialStore:
"""
Create a credential store with Aden server sync.
Automatically syncs OAuth2 tokens from the Aden authentication server.
Falls back to local-only storage if ADEN_API_KEY is not set or Aden
is unreachable.
Args:
base_url: Aden server URL (default: https://hive.adenhq.com)
cache_ttl_seconds: How long to cache credentials locally (default: 5 min)
local_path: Path for local credential storage (default: ~/.hive/credentials)
auto_sync: Whether to sync all credentials on startup (default: True)
**kwargs: Additional arguments passed to CredentialStore
Returns:
CredentialStore configured with Aden sync
Example:
# Simple usage - just set ADEN_API_KEY env var
store = CredentialStore.with_aden_sync()
# Get HubSpot token (auto-refreshed via Aden)
token = store.get_key("hubspot", "access_token")
"""
import os
from pathlib import Path
from .storage import EncryptedFileStorage
# Determine local storage path
if local_path is None:
local_path = str(Path.home() / ".hive" / "credentials")
local_storage = EncryptedFileStorage(base_path=local_path)
# Check if Aden is configured
api_key = os.environ.get("ADEN_API_KEY")
if not api_key:
logger.info("ADEN_API_KEY not set, using local-only credential storage")
return cls(storage=local_storage, **kwargs)
# Try to setup Aden sync
try:
from .aden import (
AdenCachedStorage,
AdenClientConfig,
AdenCredentialClient,
AdenSyncProvider,
)
# Create Aden client
client = AdenCredentialClient(AdenClientConfig(base_url=base_url))
# Create sync provider
provider = AdenSyncProvider(client=client)
# Use cached storage for offline resilience
cached_storage = AdenCachedStorage(
local_storage=local_storage,
aden_provider=provider,
cache_ttl_seconds=cache_ttl_seconds,
)
store = cls(
storage=cached_storage,
providers=[provider],
auto_refresh=True,
**kwargs,
)
# Initial sync
if auto_sync:
synced = provider.sync_all(store)
logger.info(f"Synced {synced} credentials from Aden server")
return store
except ImportError:
logger.warning("Aden components not available, using local storage")
return cls(storage=local_storage, **kwargs)
except Exception as e:
logger.warning(f"Failed to setup Aden sync: {e}. Using local storage.")
return cls(storage=local_storage, **kwargs)