auramaxx 1.0.0-alpha.4
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/LICENSE +26 -0
- package/README.md +112 -0
- package/bin/aurawallet.js +121 -0
- package/docs/ADAPTERS.md +467 -0
- package/docs/API.md +2679 -0
- package/docs/APPS.md +198 -0
- package/docs/ARCHITECTURE.md +350 -0
- package/docs/AUTH.md +698 -0
- package/docs/BEST-PRACTICES.md +121 -0
- package/docs/CLI.md +61 -0
- package/docs/DEVELOPING-APPS.md +452 -0
- package/docs/EXTENSION.md +97 -0
- package/docs/JOBS.md +33 -0
- package/docs/MCP.md +76 -0
- package/docs/PROTOCOL.md +142 -0
- package/docs/SETUP.md +219 -0
- package/docs/WORKSPACE.md +672 -0
- package/docs/agent-auth.md +63 -0
- package/docs/aura-file.md +48 -0
- package/docs/credentials.md +53 -0
- package/docs/external/getting-started.md +65 -0
- package/docs/external/overview.md +45 -0
- package/docs/external/use-cases.md +48 -0
- package/docs/external/why-aura.md +35 -0
- package/docs/jobs/connect-agent.md +77 -0
- package/docs/jobs/migrate-from-dotenv.md +79 -0
- package/docs/jobs/recover-from-lockout.md +72 -0
- package/docs/jobs/secure-ci.md +63 -0
- package/docs/oauth2.md +42 -0
- package/docs/passkeys.md +60 -0
- package/docs/security.md +540 -0
- package/docs/specs/aura-open-protocol.md +61 -0
- package/docs/specs/aura-provider-plugin.md +24 -0
- package/docs/specs/aura-registry-model.md +31 -0
- package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
- package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
- package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
- package/docs/specs/fixtures/valid-basic.aura +4 -0
- package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
- package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
- package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
- package/docs/totp.md +40 -0
- package/docs/wallet/AI.md +508 -0
- package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
- package/docs/wallet/README.md +47 -0
- package/docs/wallet/STRATEGY.md +89 -0
- package/next.config.ts +21 -0
- package/package.json +151 -0
- package/postcss.config.mjs +8 -0
- package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
- package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
- package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +447 -0
- package/public/logo-chevron.svg +31 -0
- package/public/logo-concentric.svg +31 -0
- package/public/logo-crosshatch.svg +39 -0
- package/public/logo-dashed.svg +39 -0
- package/public/logo-horizontal.svg +31 -0
- package/public/logo-m56.svg +64 -0
- package/public/logo.webp +0 -0
- package/scripts/add-app.js +245 -0
- package/scripts/init.sh +57 -0
- package/scripts/migrate-apikeys-to-credentials.ts +35 -0
- package/scripts/sandbox-agent-flow.sh +235 -0
- package/scripts/sandbox.sh +175 -0
- package/scripts/validate-job-docs.mjs +125 -0
- package/server/abi/SwapHelper.json +438 -0
- package/server/cli/approval.ts +447 -0
- package/server/cli/commands/app.ts +204 -0
- package/server/cli/commands/cron.ts +24 -0
- package/server/cli/commands/doctor.ts +1007 -0
- package/server/cli/commands/env.ts +456 -0
- package/server/cli/commands/init.ts +752 -0
- package/server/cli/commands/mcp.ts +125 -0
- package/server/cli/commands/restore.ts +314 -0
- package/server/cli/commands/shell-hook.ts +468 -0
- package/server/cli/commands/start.ts +62 -0
- package/server/cli/commands/status.ts +59 -0
- package/server/cli/commands/stop.ts +14 -0
- package/server/cli/commands/token.ts +180 -0
- package/server/cli/commands/unlock.ts +49 -0
- package/server/cli/commands/vault.ts +417 -0
- package/server/cli/index.ts +328 -0
- package/server/cli/lib/aura-parser.ts +64 -0
- package/server/cli/lib/credential-create.ts +74 -0
- package/server/cli/lib/credential-resolve.ts +254 -0
- package/server/cli/lib/dotenv-migrate.ts +116 -0
- package/server/cli/lib/dotenv-parser.ts +146 -0
- package/server/cli/lib/http.ts +91 -0
- package/server/cli/lib/init-steps.ts +76 -0
- package/server/cli/lib/local-agent-trust.ts +45 -0
- package/server/cli/lib/process.ts +136 -0
- package/server/cli/lib/prompt.ts +85 -0
- package/server/cli/lib/theme.ts +240 -0
- package/server/cli/socket.ts +570 -0
- package/server/cli/transport-client.ts +50 -0
- package/server/cron/index.ts +137 -0
- package/server/cron/job.ts +31 -0
- package/server/cron/jobs/balance-sync.ts +436 -0
- package/server/cron/jobs/incoming-scan.ts +506 -0
- package/server/cron/jobs/native-price.ts +70 -0
- package/server/cron/jobs/orphan-cleanup.ts +40 -0
- package/server/cron/jobs/strategy-runner.ts +175 -0
- package/server/cron/scheduler.ts +125 -0
- package/server/index.ts +406 -0
- package/server/lib/adapters/factory.ts +110 -0
- package/server/lib/adapters/index.ts +19 -0
- package/server/lib/adapters/router.ts +297 -0
- package/server/lib/adapters/telegram.ts +645 -0
- package/server/lib/adapters/types.ts +89 -0
- package/server/lib/adapters/webhook.ts +95 -0
- package/server/lib/address.ts +49 -0
- package/server/lib/agent-auth/contracts.ts +1194 -0
- package/server/lib/agent-profiles.ts +328 -0
- package/server/lib/ai.ts +285 -0
- package/server/lib/api-registry/contracts.ts +86 -0
- package/server/lib/api-registry/validation.ts +172 -0
- package/server/lib/apikey-migration.ts +189 -0
- package/server/lib/app-installer.ts +505 -0
- package/server/lib/app-tokens.ts +247 -0
- package/server/lib/auth.ts +314 -0
- package/server/lib/batch.ts +242 -0
- package/server/lib/cold.ts +874 -0
- package/server/lib/config.ts +381 -0
- package/server/lib/credential-access-audit.ts +85 -0
- package/server/lib/credential-access-policy.ts +110 -0
- package/server/lib/credential-health.ts +343 -0
- package/server/lib/credential-import.ts +487 -0
- package/server/lib/credential-scope.ts +87 -0
- package/server/lib/credential-shares.ts +190 -0
- package/server/lib/credential-transport.ts +342 -0
- package/server/lib/credential-vault.ts +77 -0
- package/server/lib/credentials.ts +333 -0
- package/server/lib/crypto.ts +8 -0
- package/server/lib/db.ts +15 -0
- package/server/lib/defaults.ts +366 -0
- package/server/lib/dex/index.ts +80 -0
- package/server/lib/dex/relay.ts +235 -0
- package/server/lib/dex/types.ts +59 -0
- package/server/lib/dex/uniswap.ts +370 -0
- package/server/lib/e2e-agent/artifacts.ts +36 -0
- package/server/lib/e2e-agent/contracts.ts +112 -0
- package/server/lib/e2e-agent/validation.ts +135 -0
- package/server/lib/encrypt.ts +128 -0
- package/server/lib/error.ts +20 -0
- package/server/lib/events.ts +205 -0
- package/server/lib/hot.ts +357 -0
- package/server/lib/key-fingerprint.ts +28 -0
- package/server/lib/logger.ts +331 -0
- package/server/lib/network.ts +137 -0
- package/server/lib/notifications.ts +219 -0
- package/server/lib/oauth2-refresh.ts +241 -0
- package/server/lib/oursecret.ts +54 -0
- package/server/lib/passkey-credential.ts +360 -0
- package/server/lib/passkey.ts +68 -0
- package/server/lib/permissions.ts +248 -0
- package/server/lib/pino.ts +24 -0
- package/server/lib/policy-preview.ts +138 -0
- package/server/lib/price.ts +338 -0
- package/server/lib/prices.ts +34 -0
- package/server/lib/project-scope.ts +239 -0
- package/server/lib/resolve-action.ts +427 -0
- package/server/lib/resolve.ts +36 -0
- package/server/lib/sessions.ts +632 -0
- package/server/lib/solana/connection.ts +26 -0
- package/server/lib/solana/jupiter.ts +128 -0
- package/server/lib/solana/transfer.ts +108 -0
- package/server/lib/solana/wallet.ts +136 -0
- package/server/lib/strategy/emits.ts +21 -0
- package/server/lib/strategy/engine.ts +1305 -0
- package/server/lib/strategy/executor.ts +115 -0
- package/server/lib/strategy/hook-context.ts +158 -0
- package/server/lib/strategy/hooks.ts +990 -0
- package/server/lib/strategy/index.ts +28 -0
- package/server/lib/strategy/installer.ts +305 -0
- package/server/lib/strategy/loader.ts +256 -0
- package/server/lib/strategy/message.ts +235 -0
- package/server/lib/strategy/repository.ts +218 -0
- package/server/lib/strategy/session-logger.ts +693 -0
- package/server/lib/strategy/sources.ts +288 -0
- package/server/lib/strategy/state.ts +189 -0
- package/server/lib/strategy/templates.ts +403 -0
- package/server/lib/strategy/tick.ts +404 -0
- package/server/lib/strategy/types.ts +230 -0
- package/server/lib/swap.ts +3 -0
- package/server/lib/temp.ts +86 -0
- package/server/lib/token-metadata.ts +86 -0
- package/server/lib/token-safety.ts +200 -0
- package/server/lib/token-search.ts +444 -0
- package/server/lib/totp.ts +194 -0
- package/server/lib/transactions.ts +123 -0
- package/server/lib/transport.ts +75 -0
- package/server/lib/txhistory/decoder.ts +262 -0
- package/server/lib/txhistory/enricher.ts +652 -0
- package/server/lib/txhistory/index.ts +391 -0
- package/server/lib/txhistory/signatures.ts +59 -0
- package/server/lib/verified-summary.ts +421 -0
- package/server/mcp/profile-policy.ts +30 -0
- package/server/mcp/server.ts +619 -0
- package/server/mcp/tools.ts +523 -0
- package/server/middleware/auth.ts +119 -0
- package/server/middleware/requestLogger.ts +84 -0
- package/server/routes/actions.ts +459 -0
- package/server/routes/adapters.ts +703 -0
- package/server/routes/addressbook.ts +113 -0
- package/server/routes/ai.ts +34 -0
- package/server/routes/apikeys.ts +295 -0
- package/server/routes/apps.ts +601 -0
- package/server/routes/auth.ts +457 -0
- package/server/routes/backup.ts +340 -0
- package/server/routes/batch.ts +270 -0
- package/server/routes/bookmarks.ts +162 -0
- package/server/routes/credential-shares.ts +198 -0
- package/server/routes/credential-vaults.ts +154 -0
- package/server/routes/credentials.ts +1290 -0
- package/server/routes/dashboard.ts +71 -0
- package/server/routes/defaults.ts +124 -0
- package/server/routes/fund.ts +229 -0
- package/server/routes/import.ts +352 -0
- package/server/routes/launch.ts +665 -0
- package/server/routes/lock.ts +54 -0
- package/server/routes/logs.ts +68 -0
- package/server/routes/nuke.ts +111 -0
- package/server/routes/passkey-credentials.ts +99 -0
- package/server/routes/passkey.ts +346 -0
- package/server/routes/portfolio.ts +217 -0
- package/server/routes/price.ts +63 -0
- package/server/routes/resolve.ts +31 -0
- package/server/routes/security.ts +45 -0
- package/server/routes/send-evm.ts +241 -0
- package/server/routes/send-solana.ts +281 -0
- package/server/routes/send.ts +178 -0
- package/server/routes/setup.ts +210 -0
- package/server/routes/strategy.ts +894 -0
- package/server/routes/swap-evm.ts +353 -0
- package/server/routes/swap-solana.ts +177 -0
- package/server/routes/swap.ts +356 -0
- package/server/routes/token.ts +247 -0
- package/server/routes/unlock.ts +403 -0
- package/server/routes/wallet-assets.ts +361 -0
- package/server/routes/wallet-transactions.ts +515 -0
- package/server/routes/wallet.ts +710 -0
- package/server/types.ts +146 -0
- package/skills/aurawallet/SKILL.md +739 -0
- package/skills/aurawallet-setup/SKILL.md +74 -0
- package/skills/security-review/SKILL.md +148 -0
- package/src/app/api/agent-requests/route.ts +30 -0
- package/src/app/api/apps/install/route.ts +126 -0
- package/src/app/api/apps/manifests/route.ts +16 -0
- package/src/app/api/apps/static/[...path]/route.ts +57 -0
- package/src/app/api/events/route.ts +92 -0
- package/src/app/api/page.tsx +212 -0
- package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
- package/src/app/api/workspace/[id]/apps/route.ts +81 -0
- package/src/app/api/workspace/[id]/export/route.ts +67 -0
- package/src/app/api/workspace/[id]/route.ts +168 -0
- package/src/app/api/workspace/auth.ts +34 -0
- package/src/app/api/workspace/config/route.ts +106 -0
- package/src/app/api/workspace/import/route.ts +127 -0
- package/src/app/api/workspace/route.ts +116 -0
- package/src/app/app/page.tsx +2122 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/docs/page.tsx +178 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +572 -0
- package/src/app/health/page.tsx +5 -0
- package/src/app/hello/page.tsx +15 -0
- package/src/app/icon.png +0 -0
- package/src/app/layout.tsx +34 -0
- package/src/app/page.tsx +986 -0
- package/src/app/providers.tsx +90 -0
- package/src/app/share/[token]/page.tsx +295 -0
- package/src/components/ChainSelector.tsx +144 -0
- package/src/components/HumanActionBar.tsx +695 -0
- package/src/components/NotificationDrawer.tsx +129 -0
- package/src/components/apps/AgentKeysApp.tsx +490 -0
- package/src/components/apps/App.tsx +153 -0
- package/src/components/apps/AppGrid.tsx +15 -0
- package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
- package/src/components/apps/DraggableApp.tsx +562 -0
- package/src/components/apps/IFrameApp.tsx +73 -0
- package/src/components/apps/LogsApp.tsx +360 -0
- package/src/components/apps/SendApp.tsx +394 -0
- package/src/components/apps/SetupWizardApp.tsx +1004 -0
- package/src/components/apps/SystemDefaultsApp.tsx +845 -0
- package/src/components/apps/ThirdPartyApp.tsx +428 -0
- package/src/components/apps/TokenApp.tsx +319 -0
- package/src/components/apps/TransactionsApp.tsx +438 -0
- package/src/components/apps/WalletDetailApp.tsx +1505 -0
- package/src/components/apps/index.ts +13 -0
- package/src/components/design-system/Button.tsx +53 -0
- package/src/components/design-system/ChainIndicator.tsx +65 -0
- package/src/components/design-system/ChainSelector.tsx +137 -0
- package/src/components/design-system/ConfirmationModal.tsx +106 -0
- package/src/components/design-system/ConfirmationPopover.tsx +81 -0
- package/src/components/design-system/Drawer.tsx +123 -0
- package/src/components/design-system/FilterDropdown.tsx +72 -0
- package/src/components/design-system/Modal.tsx +206 -0
- package/src/components/design-system/Popover.tsx +142 -0
- package/src/components/design-system/TextInput.tsx +85 -0
- package/src/components/design-system/Toggle.tsx +58 -0
- package/src/components/design-system/index.ts +11 -0
- package/src/components/docs/DocsThemeToggle.tsx +49 -0
- package/src/components/health/CredentialHealthDashboard.tsx +214 -0
- package/src/components/icons/ChainIcons.tsx +72 -0
- package/src/components/layout/AppStoreDrawer.tsx +369 -0
- package/src/components/layout/ContentArea.tsx +21 -0
- package/src/components/layout/TabBar.tsx +278 -0
- package/src/components/layout/WalletSidebar.tsx +1033 -0
- package/src/components/layout/index.ts +4 -0
- package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
- package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
- package/src/components/vault/ApiKeysConsole.tsx +1080 -0
- package/src/components/vault/AuditConsole.tsx +584 -0
- package/src/components/vault/CredentialDetail.tsx +455 -0
- package/src/components/vault/CredentialEmpty.tsx +55 -0
- package/src/components/vault/CredentialField.tsx +361 -0
- package/src/components/vault/CredentialForm.tsx +1212 -0
- package/src/components/vault/CredentialList.tsx +165 -0
- package/src/components/vault/CredentialRow.tsx +97 -0
- package/src/components/vault/CredentialShareModal.tsx +178 -0
- package/src/components/vault/CredentialVault.tsx +754 -0
- package/src/components/vault/CredentialWalletWidget.tsx +103 -0
- package/src/components/vault/ImportCredentialsModal.tsx +515 -0
- package/src/components/vault/LargeTypeModal.tsx +64 -0
- package/src/components/vault/PasswordGenerator.tsx +224 -0
- package/src/components/vault/TOTPDisplay.tsx +123 -0
- package/src/components/vault/VaultSidebar.tsx +413 -0
- package/src/components/vault/types.ts +54 -0
- package/src/context/AuthContext.tsx +337 -0
- package/src/context/PriceContext.tsx +113 -0
- package/src/context/ThemeContext.tsx +164 -0
- package/src/context/WebSocketContext.tsx +269 -0
- package/src/context/WorkspaceContext.tsx +668 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useAgentActions.ts +368 -0
- package/src/hooks/useBalance.ts +103 -0
- package/src/hooks/useBalances.ts +129 -0
- package/src/instrumentation.ts +12 -0
- package/src/lib/api.ts +449 -0
- package/src/lib/app-loader.ts +148 -0
- package/src/lib/app-registry.ts +178 -0
- package/src/lib/app-sdk.ts +157 -0
- package/src/lib/audit-console-adapter.ts +151 -0
- package/src/lib/auth-client.ts +75 -0
- package/src/lib/config.ts +74 -0
- package/src/lib/crypto.ts +112 -0
- package/src/lib/db.ts +21 -0
- package/src/lib/docs.ts +390 -0
- package/src/lib/events.ts +361 -0
- package/src/lib/pino.ts +24 -0
- package/src/lib/theme-handlers.ts +168 -0
- package/src/lib/theme.ts +351 -0
- package/src/lib/tokenData.ts +378 -0
- package/src/lib/vault-crypto.ts +129 -0
- package/src/lib/websocket-server.ts +302 -0
- package/src/lib/websocket-setup.ts +79 -0
- package/src/lib/wordlist.ts +2050 -0
- package/src/lib/workspace-handlers.ts +285 -0
- package/start.sh +80 -0
- package/tailwind.config.ts +99 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tick Runner
|
|
3
|
+
* ===========
|
|
4
|
+
* Orchestrates a single tick for a strategy:
|
|
5
|
+
* 1. Fetch sources
|
|
6
|
+
* 2. Call tick hook → intents + state
|
|
7
|
+
* 3. Approve (if config.approve)
|
|
8
|
+
* 4. For each intent → call execute hook → action
|
|
9
|
+
* 5. Execute action → outcome
|
|
10
|
+
* 6. Call result hook → state updates + follow-ups
|
|
11
|
+
* 7. Follow-up intents re-enter step 3 (depth limit: 3)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createHash } from 'crypto';
|
|
15
|
+
import { StrategyManifest, StrategyConfig, HookResult, Intent, Action, ActionOutcome } from './types';
|
|
16
|
+
import { fetchAllSources } from './sources';
|
|
17
|
+
import { callHook } from './hooks';
|
|
18
|
+
import { executeAction } from './executor';
|
|
19
|
+
import { getState, updateState, getConfigOverrides, restoreState, persistState } from './state';
|
|
20
|
+
import { requestHumanApproval, requestActionToken } from './engine';
|
|
21
|
+
import { emitWalletEvent } from '../events';
|
|
22
|
+
import { getTokenHash } from '../auth';
|
|
23
|
+
import { getSessionBudget } from '../sessions';
|
|
24
|
+
import { processEmits } from './emits';
|
|
25
|
+
import { getDefaultSync } from '../defaults';
|
|
26
|
+
import {
|
|
27
|
+
startTickSession,
|
|
28
|
+
logTickEvent,
|
|
29
|
+
logError as sessionLogError,
|
|
30
|
+
endTickSession,
|
|
31
|
+
} from './session-logger';
|
|
32
|
+
import { getErrorMessage } from '../error';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Emit a strategy event via the existing event system.
|
|
36
|
+
*/
|
|
37
|
+
function emitStrategyEvent(type: string, strategyId: string, data: Record<string, unknown>): void {
|
|
38
|
+
emitWalletEvent(type, { strategyId, ...data });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getMaxFollowupDepth(): number {
|
|
42
|
+
return getDefaultSync<number>('ai.max_followup_depth', 3);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Last context hash per strategy — used to skip duplicate LLM calls */
|
|
46
|
+
const lastContextHash = new Map<string, string>();
|
|
47
|
+
|
|
48
|
+
/** Hash a string with SHA-256 (fast, collision-resistant) */
|
|
49
|
+
function hashContext(contextStr: string): string {
|
|
50
|
+
return createHash('sha256').update(contextStr).digest('hex').slice(0, 16);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Clear context hash for a strategy (e.g. on disable/reset) */
|
|
54
|
+
export function clearContextHash(id: string): void {
|
|
55
|
+
lastContextHash.delete(id);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Clear all context hashes (e.g. on engine shutdown) */
|
|
59
|
+
export function clearAllContextHashes(): void {
|
|
60
|
+
lastContextHash.clear();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Run a single tick for a strategy.
|
|
65
|
+
*/
|
|
66
|
+
export async function runTick(
|
|
67
|
+
manifest: StrategyManifest,
|
|
68
|
+
token?: string,
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const startTime = Date.now();
|
|
71
|
+
const tag = `[strategy:${manifest.id}]`;
|
|
72
|
+
const sessionId = startTickSession(manifest.id);
|
|
73
|
+
|
|
74
|
+
// Re-read state from DB to pick up changes from app UI (e.g. human moves)
|
|
75
|
+
await restoreState(manifest.id);
|
|
76
|
+
const state = getState(manifest.id);
|
|
77
|
+
const configOverrides = await getConfigOverrides(manifest.id);
|
|
78
|
+
const config: StrategyConfig = { ...manifest.config, ...configOverrides };
|
|
79
|
+
|
|
80
|
+
console.log(`${tag} ── tick start (sources=${manifest.sources.length})`);
|
|
81
|
+
|
|
82
|
+
// 1. Fetch sources
|
|
83
|
+
let sourceData: Record<string, unknown[]>;
|
|
84
|
+
try {
|
|
85
|
+
const srcStart = Date.now();
|
|
86
|
+
sourceData = await fetchAllSources(manifest, config, null, token);
|
|
87
|
+
const srcKeys = Object.keys(sourceData);
|
|
88
|
+
const srcCounts = srcKeys.map(k => `${k}:${sourceData[k].length}`).join(', ');
|
|
89
|
+
console.log(`${tag} sources fetched in ${Date.now() - srcStart}ms → {${srcCounts}}`);
|
|
90
|
+
logTickEvent(sessionId, 'Sources', `${srcCounts} (${Date.now() - srcStart}ms)`);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
const errorAction = config.errors?.sourceFail || 'skip';
|
|
93
|
+
const errMsg = getErrorMessage(err);
|
|
94
|
+
console.error(`${tag} source fetch FAILED: ${errMsg} (policy=${errorAction})`);
|
|
95
|
+
emitStrategyEvent('strategy:error', manifest.id, { error: errMsg, phase: 'sources' });
|
|
96
|
+
sessionLogError(sessionId, err);
|
|
97
|
+
|
|
98
|
+
if (errorAction === 'pause') {
|
|
99
|
+
endTickSession(sessionId, 'error', Date.now() - startTime);
|
|
100
|
+
throw err; // Let engine handle pause
|
|
101
|
+
}
|
|
102
|
+
// skip or retry — for skip, just return; retry handled by engine
|
|
103
|
+
if (errorAction === 'skip') {
|
|
104
|
+
endTickSession(sessionId, 'error', Date.now() - startTime);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
endTickSession(sessionId, 'error', Date.now() - startTime);
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 2. Build context and check if it changed since last tick
|
|
112
|
+
const context = {
|
|
113
|
+
sources: sourceData,
|
|
114
|
+
positions: state.positions || [],
|
|
115
|
+
state,
|
|
116
|
+
config,
|
|
117
|
+
permissions: manifest.permissions,
|
|
118
|
+
budget: token ? getSessionBudget(getTokenHash(token)) : { limits: {}, spent: {}, remaining: {} },
|
|
119
|
+
};
|
|
120
|
+
const contextStr = JSON.stringify(context);
|
|
121
|
+
const contextHash = hashContext(contextStr);
|
|
122
|
+
const prevHash = lastContextHash.get(manifest.id);
|
|
123
|
+
|
|
124
|
+
if (prevHash === contextHash) {
|
|
125
|
+
const dur = Date.now() - startTime;
|
|
126
|
+
console.log(`${tag} ── tick skipped in ${dur}ms (context unchanged, hash=${contextHash})`);
|
|
127
|
+
logTickEvent(sessionId, 'Context', `unchanged (hash=${contextHash}), skipped AI call`);
|
|
128
|
+
endTickSession(sessionId, 'completed', dur);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 3. Call tick hook
|
|
133
|
+
console.log(`${tag} calling tick hook...`);
|
|
134
|
+
const hookStart = Date.now();
|
|
135
|
+
const tickResult = await callHook(manifest, 'tick', context, token);
|
|
136
|
+
lastContextHash.set(manifest.id, contextHash);
|
|
137
|
+
const hookDur = Date.now() - hookStart;
|
|
138
|
+
console.log(`${tag} tick hook returned in ${hookDur}ms → intents=${tickResult.intents.length}, stateKeys=${Object.keys(tickResult.state).join(',') || '(none)'}`);
|
|
139
|
+
logTickEvent(sessionId, 'Hook', `${hookDur}ms, intents=${tickResult.intents.length}`);
|
|
140
|
+
|
|
141
|
+
// Update state from tick hook
|
|
142
|
+
if (tickResult.state && Object.keys(tickResult.state).length > 0) {
|
|
143
|
+
updateState(manifest.id, tickResult.state);
|
|
144
|
+
await persistState(manifest.id);
|
|
145
|
+
console.log(`${tag} state updated + persisted: ${JSON.stringify(tickResult.state).slice(0, 200)}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Broadcast any emit events from the tick hook
|
|
149
|
+
processEmits(manifest.id, tickResult);
|
|
150
|
+
|
|
151
|
+
if (tickResult.log) {
|
|
152
|
+
console.log(`${tag} hook log: ${tickResult.log}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!tickResult.intents || tickResult.intents.length === 0) {
|
|
156
|
+
const dur = Date.now() - startTime;
|
|
157
|
+
console.log(`${tag} ── tick done in ${dur}ms (no intents)`);
|
|
158
|
+
logTickEvent(sessionId, 'Intents', 'none');
|
|
159
|
+
endTickSession(sessionId, 'completed', dur);
|
|
160
|
+
emitStrategyEvent('strategy:tick', manifest.id, {
|
|
161
|
+
intents: 0,
|
|
162
|
+
duration: dur,
|
|
163
|
+
state: getState(manifest.id),
|
|
164
|
+
});
|
|
165
|
+
return; // Nothing to do
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log(`${tag} processing ${tickResult.intents.length} intent(s): ${tickResult.intents.map(i => i.type || 'unknown').join(', ')}`);
|
|
169
|
+
|
|
170
|
+
// Process intents (with follow-up support)
|
|
171
|
+
await processIntents(manifest, tickResult.intents, config, token, 0);
|
|
172
|
+
|
|
173
|
+
const dur = Date.now() - startTime;
|
|
174
|
+
console.log(`${tag} ── tick done in ${dur}ms (${tickResult.intents.length} intents processed)`);
|
|
175
|
+
logTickEvent(sessionId, 'Intents', `${tickResult.intents.length} processed`);
|
|
176
|
+
endTickSession(sessionId, 'completed', dur);
|
|
177
|
+
emitStrategyEvent('strategy:tick', manifest.id, {
|
|
178
|
+
intents: tickResult.intents.length,
|
|
179
|
+
duration: dur,
|
|
180
|
+
state: getState(manifest.id),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Process intents through approval → execute → result pipeline.
|
|
186
|
+
* Supports recursive follow-ups with depth limit.
|
|
187
|
+
*/
|
|
188
|
+
export async function processIntents(
|
|
189
|
+
manifest: StrategyManifest,
|
|
190
|
+
intents: Intent[],
|
|
191
|
+
config: StrategyConfig,
|
|
192
|
+
token?: string,
|
|
193
|
+
depth: number = 0,
|
|
194
|
+
): Promise<void> {
|
|
195
|
+
const tag = `[strategy:${manifest.id}]`;
|
|
196
|
+
|
|
197
|
+
const maxDepth = getMaxFollowupDepth();
|
|
198
|
+
if (depth >= maxDepth) {
|
|
199
|
+
console.warn(`${tag} follow-up depth limit reached (${maxDepth}), stopping`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (depth > 0) {
|
|
204
|
+
console.log(`${tag} processing ${intents.length} follow-up intent(s) at depth ${depth}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 3. Batch approve (if config.approve and no per-intent permissions)
|
|
208
|
+
// Intents with `permissions` array use per-action tokens instead of batch approval
|
|
209
|
+
const batchIntents = intents.filter(i => !i.permissions || !Array.isArray(i.permissions));
|
|
210
|
+
const actionIntents = intents.filter(i => i.permissions && Array.isArray(i.permissions));
|
|
211
|
+
|
|
212
|
+
let batchApproved = true;
|
|
213
|
+
if (config.approve && batchIntents.length > 0) {
|
|
214
|
+
console.log(`${tag} waiting for batch approval of ${batchIntents.length} intent(s)...`);
|
|
215
|
+
emitStrategyEvent('strategy:approve', manifest.id, { intents: batchIntents });
|
|
216
|
+
batchApproved = await requestHumanApproval(manifest.id, batchIntents);
|
|
217
|
+
if (!batchApproved) {
|
|
218
|
+
console.log(`${tag} batch intents REJECTED or timed out`);
|
|
219
|
+
// Still process action intents (they get their own approval)
|
|
220
|
+
if (actionIntents.length === 0) return;
|
|
221
|
+
} else {
|
|
222
|
+
console.log(`${tag} batch intents APPROVED`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Build the ordered list: approved batch intents + per-action intents
|
|
227
|
+
const toProcess: Array<{ intent: Intent; intentToken?: string }> = [];
|
|
228
|
+
|
|
229
|
+
// Add batch-approved intents (use strategy token). If approval was required and rejected, skip.
|
|
230
|
+
const approvedBatchIntents = batchApproved ? batchIntents : [];
|
|
231
|
+
for (const intent of approvedBatchIntents) {
|
|
232
|
+
toProcess.push({ intent, intentToken: token });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Per-action intents: each gets its own approval + scoped token
|
|
236
|
+
for (const intent of actionIntents) {
|
|
237
|
+
console.log(`${tag} [${intent.type}] requesting per-action token...`);
|
|
238
|
+
const result = await requestActionToken(manifest.id, intent);
|
|
239
|
+
if (!result.approved) {
|
|
240
|
+
console.log(`${tag} [${intent.type}] action REJECTED or timed out`);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
console.log(`${tag} [${intent.type}] action APPROVED (temp token)`);
|
|
244
|
+
toProcess.push({ intent, intentToken: result.token });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// 4-6. Execute each intent
|
|
248
|
+
const followUps: Intent[] = [];
|
|
249
|
+
let stateUpdated = false;
|
|
250
|
+
|
|
251
|
+
for (let i = 0; i < toProcess.length; i++) {
|
|
252
|
+
const { intent, intentToken } = toProcess[i];
|
|
253
|
+
const intentLabel = intent.type || `#${i}`;
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
// 4. Determine action: pre-computed or via execute hook
|
|
257
|
+
let action: Action | null;
|
|
258
|
+
const intentAction = intent.action as Record<string, unknown> | undefined;
|
|
259
|
+
|
|
260
|
+
if (intentAction && typeof intentAction.endpoint === 'string' && typeof intentAction.method === 'string') {
|
|
261
|
+
// Pre-computed action — skip execute hook
|
|
262
|
+
action = {
|
|
263
|
+
endpoint: intentAction.endpoint,
|
|
264
|
+
method: intentAction.method,
|
|
265
|
+
body: intentAction.body as Record<string, unknown> | undefined,
|
|
266
|
+
headers: intentAction.headers as Record<string, string> | undefined,
|
|
267
|
+
};
|
|
268
|
+
console.log(`${tag} [${intentLabel}] using pre-computed action`);
|
|
269
|
+
} else if (manifest.hooks.execute) {
|
|
270
|
+
// Call execute hook
|
|
271
|
+
console.log(`${tag} [${intentLabel}] calling execute hook...`);
|
|
272
|
+
const execStart = Date.now();
|
|
273
|
+
const execResult = await callHook(manifest, 'execute', {
|
|
274
|
+
intent,
|
|
275
|
+
config,
|
|
276
|
+
});
|
|
277
|
+
console.log(`${tag} [${intentLabel}] execute hook returned in ${Date.now() - execStart}ms`);
|
|
278
|
+
action = extractAction(execResult);
|
|
279
|
+
} else {
|
|
280
|
+
console.warn(`${tag} [${intentLabel}] no action and no execute hook, skipping`);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!action) {
|
|
285
|
+
console.warn(`${tag} [${intentLabel}] execute hook returned NO action, skipping`);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
console.log(`${tag} [${intentLabel}] action: ${action.method} ${action.endpoint}${action.body ? ' (has body)' : ''}`);
|
|
290
|
+
|
|
291
|
+
// 5. Execute action (use intentToken which may be a per-action temp token)
|
|
292
|
+
let outcome: ActionOutcome;
|
|
293
|
+
try {
|
|
294
|
+
const actionStart = Date.now();
|
|
295
|
+
outcome = await executeAction(action, manifest.id, intentToken, manifest.allowedHosts);
|
|
296
|
+
const actionMs = Date.now() - actionStart;
|
|
297
|
+
if (outcome.success) {
|
|
298
|
+
console.log(`${tag} [${intentLabel}] action OK in ${actionMs}ms`);
|
|
299
|
+
} else {
|
|
300
|
+
console.error(`${tag} [${intentLabel}] action FAILED in ${actionMs}ms: ${outcome.error}`);
|
|
301
|
+
}
|
|
302
|
+
} catch (err) {
|
|
303
|
+
const errMsg = getErrorMessage(err);
|
|
304
|
+
outcome = { success: false, error: errMsg };
|
|
305
|
+
const errorAction = config.errors?.executeFail || 'skip';
|
|
306
|
+
|
|
307
|
+
console.error(`${tag} [${intentLabel}] action threw: ${errMsg} (policy=${errorAction})`);
|
|
308
|
+
emitStrategyEvent('strategy:error', manifest.id, {
|
|
309
|
+
error: errMsg,
|
|
310
|
+
phase: 'execute',
|
|
311
|
+
intent,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
if (errorAction === 'pause') {
|
|
315
|
+
throw err;
|
|
316
|
+
}
|
|
317
|
+
if (errorAction === 'skip') continue;
|
|
318
|
+
// retry handled by engine
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// 6. Call result hook
|
|
322
|
+
if (manifest.hooks.result) {
|
|
323
|
+
console.log(`${tag} [${intentLabel}] calling result hook...`);
|
|
324
|
+
const resStart = Date.now();
|
|
325
|
+
const resultResult = await callHook(manifest, 'result', {
|
|
326
|
+
intent,
|
|
327
|
+
action,
|
|
328
|
+
outcome,
|
|
329
|
+
state: getState(manifest.id),
|
|
330
|
+
});
|
|
331
|
+
console.log(`${tag} [${intentLabel}] result hook returned in ${Date.now() - resStart}ms → followUps=${resultResult.intents.length}, stateKeys=${Object.keys(resultResult.state).join(',') || '(none)'}`);
|
|
332
|
+
|
|
333
|
+
if (resultResult.state && Object.keys(resultResult.state).length > 0) {
|
|
334
|
+
updateState(manifest.id, resultResult.state);
|
|
335
|
+
stateUpdated = true;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Collect follow-up intents
|
|
339
|
+
if (resultResult.intents && resultResult.intents.length > 0) {
|
|
340
|
+
followUps.push(...resultResult.intents);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Broadcast any emit events from the result hook
|
|
344
|
+
processEmits(manifest.id, resultResult);
|
|
345
|
+
|
|
346
|
+
if (resultResult.log) {
|
|
347
|
+
console.log(`${tag} [${intentLabel}] result log: ${resultResult.log}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
} catch (err) {
|
|
351
|
+
const errMsg = getErrorMessage(err);
|
|
352
|
+
console.error(`${tag} [${intentLabel}] processing error: ${errMsg}`);
|
|
353
|
+
emitStrategyEvent('strategy:error', manifest.id, {
|
|
354
|
+
error: errMsg,
|
|
355
|
+
phase: 'intent',
|
|
356
|
+
intent,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Process follow-up intents (recursive with depth limit)
|
|
362
|
+
if (followUps.length > 0) {
|
|
363
|
+
console.log(`${tag} ${followUps.length} follow-up intent(s) queued`);
|
|
364
|
+
await processIntents(manifest, followUps, config, token, depth + 1);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (stateUpdated) {
|
|
368
|
+
await persistState(manifest.id).catch((err) => {
|
|
369
|
+
console.warn(`${tag} state persistence failed after intents:`, err);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Extract an Action from the execute hook result.
|
|
376
|
+
* The hook might return the action in intents[0] or directly in the response.
|
|
377
|
+
*/
|
|
378
|
+
function extractAction(hookResult: HookResult): Action | null {
|
|
379
|
+
// Try intents[0] first (agent returned action as an intent)
|
|
380
|
+
if (hookResult.intents && hookResult.intents.length > 0) {
|
|
381
|
+
const intent = hookResult.intents[0];
|
|
382
|
+
if (intent.endpoint && intent.method) {
|
|
383
|
+
return {
|
|
384
|
+
endpoint: intent.endpoint as string,
|
|
385
|
+
method: intent.method as string,
|
|
386
|
+
body: intent.body as Record<string, unknown> | undefined,
|
|
387
|
+
headers: intent.headers as Record<string, string> | undefined,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Try state as action (agent put action params in state)
|
|
393
|
+
const state = hookResult.state;
|
|
394
|
+
if (state && state.endpoint && state.method) {
|
|
395
|
+
return {
|
|
396
|
+
endpoint: state.endpoint as string,
|
|
397
|
+
method: state.method as string,
|
|
398
|
+
body: state.body as Record<string, unknown> | undefined,
|
|
399
|
+
headers: state.headers as Record<string, string> | undefined,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strategy Engine Types
|
|
3
|
+
* =====================
|
|
4
|
+
* Core type definitions for the cron-based strategy engine.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Tick tier determines how often a strategy runs */
|
|
8
|
+
export type TickTier = 'sniper' | 'active' | 'standard' | 'slow' | 'maintenance';
|
|
9
|
+
|
|
10
|
+
/** Interval in ms for each tick tier */
|
|
11
|
+
export const TICK_INTERVALS: Record<TickTier, number> = {
|
|
12
|
+
sniper: 10_000,
|
|
13
|
+
active: 30_000,
|
|
14
|
+
standard: 60_000,
|
|
15
|
+
slow: 300_000,
|
|
16
|
+
maintenance: 3_600_000,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** External data source definition from app.md manifest */
|
|
20
|
+
export interface SourceDef {
|
|
21
|
+
id: string;
|
|
22
|
+
url: string;
|
|
23
|
+
method: 'GET' | 'POST';
|
|
24
|
+
body?: Record<string, unknown>;
|
|
25
|
+
auth?: 'none' | 'header' | 'query' | 'bearer';
|
|
26
|
+
header?: string;
|
|
27
|
+
query?: string;
|
|
28
|
+
key?: string;
|
|
29
|
+
depends?: string;
|
|
30
|
+
job?: string;
|
|
31
|
+
optional?: boolean;
|
|
32
|
+
rateLimit?: string;
|
|
33
|
+
select?: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** API key definition from app.md manifest */
|
|
37
|
+
export interface KeyDef {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
required?: boolean;
|
|
41
|
+
description?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Job definition for multi-interval strategies */
|
|
45
|
+
export interface JobDef {
|
|
46
|
+
id: string;
|
|
47
|
+
ticker: TickTier;
|
|
48
|
+
sources?: string[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Hook instructions from app.md manifest */
|
|
52
|
+
export interface HooksDef {
|
|
53
|
+
init?: string;
|
|
54
|
+
tick?: string;
|
|
55
|
+
execute?: string;
|
|
56
|
+
result?: string;
|
|
57
|
+
shutdown?: string;
|
|
58
|
+
message?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Error handling config */
|
|
62
|
+
export interface ErrorConfig {
|
|
63
|
+
sourceFail?: 'skip' | 'retry' | 'pause';
|
|
64
|
+
executeFail?: 'skip' | 'retry' | 'pause';
|
|
65
|
+
maxRetries?: number;
|
|
66
|
+
cooldown?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Strategy config from app.md manifest */
|
|
70
|
+
export interface StrategyConfig {
|
|
71
|
+
wallet?: string;
|
|
72
|
+
approve?: boolean;
|
|
73
|
+
errors?: ErrorConfig;
|
|
74
|
+
[key: string]: unknown;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Parsed strategy manifest from app.md */
|
|
78
|
+
export interface StrategyManifest {
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
icon?: string;
|
|
82
|
+
category?: string;
|
|
83
|
+
size?: string;
|
|
84
|
+
autoStart?: boolean;
|
|
85
|
+
ticker?: TickTier;
|
|
86
|
+
jobs?: JobDef[];
|
|
87
|
+
sources: SourceDef[];
|
|
88
|
+
keys?: KeyDef[];
|
|
89
|
+
hooks: HooksDef;
|
|
90
|
+
config: StrategyConfig;
|
|
91
|
+
permissions: string[];
|
|
92
|
+
limits?: { fund?: number; send?: number };
|
|
93
|
+
allowedHosts?: string[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Runtime state for an active strategy */
|
|
97
|
+
export interface StrategyRuntime {
|
|
98
|
+
manifest: StrategyManifest;
|
|
99
|
+
enabled: boolean;
|
|
100
|
+
running: boolean;
|
|
101
|
+
token?: string;
|
|
102
|
+
tokenHash?: string;
|
|
103
|
+
lastTick?: number;
|
|
104
|
+
lastError?: string;
|
|
105
|
+
errorCount: number;
|
|
106
|
+
pausedUntil?: number;
|
|
107
|
+
authFailureCount?: number;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Intent — what the agent wants to do (high-level) */
|
|
111
|
+
export interface Intent {
|
|
112
|
+
type: string;
|
|
113
|
+
[key: string]: unknown;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Action — how to do it (API call the engine executes) */
|
|
117
|
+
export interface Action {
|
|
118
|
+
endpoint: string;
|
|
119
|
+
method: string;
|
|
120
|
+
body?: Record<string, unknown>;
|
|
121
|
+
headers?: Record<string, string>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Result of executing an action */
|
|
125
|
+
export interface ActionOutcome {
|
|
126
|
+
success: boolean;
|
|
127
|
+
data?: unknown;
|
|
128
|
+
error?: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** A single emission from a hook to push data to the app iframe */
|
|
132
|
+
export interface HookEmit {
|
|
133
|
+
channel: string;
|
|
134
|
+
data: unknown;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Metadata from the AI provider, attached by callHook() */
|
|
138
|
+
export interface HookMeta {
|
|
139
|
+
model: string;
|
|
140
|
+
provider: string;
|
|
141
|
+
tokens: { input: number; output: number; cacheRead?: number };
|
|
142
|
+
durationMs: number;
|
|
143
|
+
costUsd?: number;
|
|
144
|
+
toolCallCount: number;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Result from calling a hook (LLM response) */
|
|
148
|
+
export interface HookResult {
|
|
149
|
+
intents: Intent[];
|
|
150
|
+
state: Record<string, unknown>;
|
|
151
|
+
log?: string;
|
|
152
|
+
reply?: string;
|
|
153
|
+
emit?: HookEmit | HookEmit[];
|
|
154
|
+
/** AI provider metadata — model, tokens, timing. Attached by callHook(). */
|
|
155
|
+
_meta?: HookMeta;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Context passed to the tick hook */
|
|
159
|
+
export interface TickContext {
|
|
160
|
+
sources: Record<string, unknown[]>;
|
|
161
|
+
positions?: unknown[];
|
|
162
|
+
state: Record<string, unknown>;
|
|
163
|
+
config: StrategyConfig;
|
|
164
|
+
wallets?: unknown[];
|
|
165
|
+
permissions: string[];
|
|
166
|
+
budget: { limits: Record<string, number>; spent: Record<string, number>; remaining: Record<string, number> };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Context passed to the execute hook */
|
|
170
|
+
export interface ExecuteContext {
|
|
171
|
+
intent: Intent;
|
|
172
|
+
wallet?: unknown;
|
|
173
|
+
config: StrategyConfig;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Context passed to the result hook */
|
|
177
|
+
export interface ResultContext {
|
|
178
|
+
intent: Intent;
|
|
179
|
+
action: Action;
|
|
180
|
+
outcome: ActionOutcome;
|
|
181
|
+
state: Record<string, unknown>;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Context passed to the init hook */
|
|
185
|
+
export interface InitContext {
|
|
186
|
+
config: StrategyConfig;
|
|
187
|
+
wallets?: unknown[];
|
|
188
|
+
state: Record<string, unknown>;
|
|
189
|
+
storage?: Record<string, unknown>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Context passed to the shutdown hook */
|
|
193
|
+
export interface ShutdownContext {
|
|
194
|
+
positions?: unknown[];
|
|
195
|
+
state: Record<string, unknown>;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Context passed to the message hook */
|
|
199
|
+
export interface MessageContext {
|
|
200
|
+
message: string;
|
|
201
|
+
appId: string;
|
|
202
|
+
state: Record<string, unknown>;
|
|
203
|
+
config: StrategyConfig;
|
|
204
|
+
permissions: string[];
|
|
205
|
+
budget: { limits: Record<string, number>; spent: Record<string, number>; remaining: Record<string, number> };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Strategy status for REST API */
|
|
209
|
+
export interface StrategyStatus {
|
|
210
|
+
id: string;
|
|
211
|
+
name: string;
|
|
212
|
+
icon?: string;
|
|
213
|
+
ticker?: TickTier;
|
|
214
|
+
enabled: boolean;
|
|
215
|
+
running: boolean;
|
|
216
|
+
lastTick?: number;
|
|
217
|
+
lastError?: string;
|
|
218
|
+
errorCount: number;
|
|
219
|
+
pausedUntil?: number;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Pending approval for dashboard/REST */
|
|
223
|
+
export interface PendingApproval {
|
|
224
|
+
id: string;
|
|
225
|
+
strategyId: string;
|
|
226
|
+
intents: Intent[];
|
|
227
|
+
createdAt: number;
|
|
228
|
+
resolve: (approved: boolean) => void;
|
|
229
|
+
timer: NodeJS.Timeout;
|
|
230
|
+
}
|