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,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aurawallet mcp — Start the MCP server (stdio transport)
|
|
3
|
+
*
|
|
4
|
+
* Spawned by MCP clients (Claude Code, Claude Desktop, Cursor, etc.) via config:
|
|
5
|
+
* { "command": "npx", "args": ["aurawallet", "mcp"], "env": { "AURA_TOKEN": "<token>" } }
|
|
6
|
+
*
|
|
7
|
+
* Flags:
|
|
8
|
+
* --install Auto-detect IDEs and write MCP config entries
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import os from 'os';
|
|
14
|
+
import { getErrorMessage } from '../../lib/error';
|
|
15
|
+
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
|
|
18
|
+
if (args.includes('--install')) {
|
|
19
|
+
installMcpConfigs();
|
|
20
|
+
} else {
|
|
21
|
+
// The MCP server runs on import — connects stdio transport and registers tools
|
|
22
|
+
import('../../mcp/server.js');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface IdeTarget {
|
|
26
|
+
name: string;
|
|
27
|
+
configPath: string;
|
|
28
|
+
global: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function installMcpConfigs(): void {
|
|
32
|
+
const home = os.homedir();
|
|
33
|
+
|
|
34
|
+
const targets: IdeTarget[] = [
|
|
35
|
+
{
|
|
36
|
+
name: 'Claude Desktop',
|
|
37
|
+
configPath: path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
38
|
+
global: true,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Cursor',
|
|
42
|
+
configPath: path.join(home, '.cursor', 'mcp.json'),
|
|
43
|
+
global: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'VS Code',
|
|
47
|
+
configPath: path.join(process.cwd(), '.vscode', 'mcp.json'),
|
|
48
|
+
global: false,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'Windsurf',
|
|
52
|
+
configPath: path.join(home, '.windsurf', 'mcp.json'),
|
|
53
|
+
global: true,
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const mcpEntry = {
|
|
58
|
+
command: 'npx',
|
|
59
|
+
args: ['aurawallet', 'mcp'],
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
console.log('\n AuraWallet MCP Installer');
|
|
63
|
+
console.log(' ───────────────────────\n');
|
|
64
|
+
|
|
65
|
+
let updated = 0;
|
|
66
|
+
let skipped = 0;
|
|
67
|
+
let notFound = 0;
|
|
68
|
+
let errors = 0;
|
|
69
|
+
|
|
70
|
+
for (const target of targets) {
|
|
71
|
+
const configDir = path.dirname(target.configPath);
|
|
72
|
+
|
|
73
|
+
// Only touch configs for IDEs that are actually present.
|
|
74
|
+
// Do not create new IDE directories implicitly.
|
|
75
|
+
if (!fs.existsSync(configDir)) {
|
|
76
|
+
console.log(` ${target.name}: not found (${configDir} not found)`);
|
|
77
|
+
notFound++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Read existing config or start fresh. If the file is malformed, skip it
|
|
82
|
+
// instead of overwriting user data with {}.
|
|
83
|
+
let config: Record<string, unknown> = {};
|
|
84
|
+
if (fs.existsSync(target.configPath)) {
|
|
85
|
+
try {
|
|
86
|
+
const raw = fs.readFileSync(target.configPath, 'utf-8');
|
|
87
|
+
config = JSON.parse(raw);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
const message = getErrorMessage(error);
|
|
90
|
+
console.log(` ${target.name}: skipped (invalid JSON in ${target.configPath}: ${message})`);
|
|
91
|
+
errors++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Check if aurawallet entry already exists
|
|
97
|
+
if (
|
|
98
|
+
config.mcpServers !== undefined &&
|
|
99
|
+
(typeof config.mcpServers !== 'object' || config.mcpServers === null || Array.isArray(config.mcpServers))
|
|
100
|
+
) {
|
|
101
|
+
console.log(` ${target.name}: skipped (mcpServers must be an object in ${target.configPath})`);
|
|
102
|
+
errors++;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const mcpServers = (config.mcpServers || {}) as Record<string, unknown>;
|
|
107
|
+
if (mcpServers.aurawallet) {
|
|
108
|
+
console.log(` ${target.name}: already configured`);
|
|
109
|
+
skipped++;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Merge the entry
|
|
114
|
+
mcpServers.aurawallet = mcpEntry;
|
|
115
|
+
config.mcpServers = mcpServers;
|
|
116
|
+
|
|
117
|
+
fs.writeFileSync(target.configPath, JSON.stringify(config, null, 2) + '\n');
|
|
118
|
+
console.log(` ${target.name}: configured (${target.configPath})`);
|
|
119
|
+
updated++;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log(` Done: ${updated} updated, ${skipped} already configured, ${notFound} not found, ${errors} skipped due to errors`);
|
|
124
|
+
console.log('');
|
|
125
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* npx aurawallet restore — Restore from a backup
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx aurawallet restore --list # List available backups
|
|
7
|
+
* npx aurawallet restore --latest # Restore most recent backup
|
|
8
|
+
* npx aurawallet restore <filename> # Restore specific backup
|
|
9
|
+
* npx aurawallet restore --dry-run <file> # Preview without modifying
|
|
10
|
+
* npx aurawallet restore --dry-run --latest # Preview latest restore
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { readdir, stat, copyFile, unlink, rename } from 'fs/promises';
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
16
|
+
import { execSync } from 'child_process';
|
|
17
|
+
import { createServer } from 'net';
|
|
18
|
+
import { getDbPath } from '../../lib/config';
|
|
19
|
+
import { getBackupsDir, ensureBackupsDir, verifyIntegrity } from '../../routes/backup';
|
|
20
|
+
|
|
21
|
+
const DATA_DIR = join(getDbPath(), '..');
|
|
22
|
+
const CREDENTIALS_DIR = join(DATA_DIR, 'credentials');
|
|
23
|
+
|
|
24
|
+
interface BackupEntry {
|
|
25
|
+
filename: string;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
size: number;
|
|
28
|
+
date: Date;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function listBackups(): Promise<BackupEntry[]> {
|
|
32
|
+
const backupsDir = getBackupsDir();
|
|
33
|
+
ensureBackupsDir();
|
|
34
|
+
|
|
35
|
+
const files = await readdir(backupsDir);
|
|
36
|
+
const backups: BackupEntry[] = [];
|
|
37
|
+
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
if (file.startsWith('aurawallet.db.') && file.endsWith('.bak')) {
|
|
40
|
+
const match = file.match(/aurawallet\.db\.(\d{8}_\d{6})\.bak/);
|
|
41
|
+
if (!match) continue;
|
|
42
|
+
const filePath = join(backupsDir, file);
|
|
43
|
+
const fileStat = await stat(filePath);
|
|
44
|
+
backups.push({
|
|
45
|
+
filename: file,
|
|
46
|
+
timestamp: match[1],
|
|
47
|
+
size: fileStat.size,
|
|
48
|
+
date: fileStat.mtime,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
backups.sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
54
|
+
return backups;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function formatSize(bytes: number): string {
|
|
58
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
59
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
60
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function formatTimestamp(ts: string): string {
|
|
64
|
+
// YYYYMMDD_HHMMSS -> YYYY-MM-DD HH:MM:SS
|
|
65
|
+
return `${ts.slice(0, 4)}-${ts.slice(4, 6)}-${ts.slice(6, 8)} ${ts.slice(9, 11)}:${ts.slice(11, 13)}:${ts.slice(13, 15)}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function checkServerRunning(): Promise<boolean> {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
const server = createServer();
|
|
71
|
+
server.once('error', (error: NodeJS.ErrnoException) => {
|
|
72
|
+
if (error.code === 'EADDRINUSE') {
|
|
73
|
+
resolve(true);
|
|
74
|
+
} else {
|
|
75
|
+
resolve(false);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
server.once('listening', () => {
|
|
79
|
+
server.close();
|
|
80
|
+
resolve(false);
|
|
81
|
+
});
|
|
82
|
+
server.listen(4242, '127.0.0.1');
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function createPreRestoreBackup(): Promise<string> {
|
|
87
|
+
const dbFile = getDbPath();
|
|
88
|
+
if (!existsSync(dbFile)) return '';
|
|
89
|
+
|
|
90
|
+
const backupsDir = getBackupsDir();
|
|
91
|
+
ensureBackupsDir();
|
|
92
|
+
|
|
93
|
+
const now = new Date();
|
|
94
|
+
const timestamp = now.toISOString().replace(/[-:]/g, '').replace('T', '_').split('.')[0];
|
|
95
|
+
const filename = `pre-restore.${timestamp}.bak`;
|
|
96
|
+
const backupPath = join(backupsDir, filename);
|
|
97
|
+
|
|
98
|
+
await copyFile(dbFile, backupPath);
|
|
99
|
+
return filename;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function restoreCredentials(backupsDir: string, timestamp: string): Promise<number> {
|
|
103
|
+
const allFiles = await readdir(backupsDir);
|
|
104
|
+
const credBackups = allFiles.filter(
|
|
105
|
+
(f) => f.startsWith(`credentials.${timestamp}.cred-`) && f.endsWith('.json')
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (credBackups.length === 0) return 0;
|
|
109
|
+
|
|
110
|
+
if (!existsSync(CREDENTIALS_DIR)) {
|
|
111
|
+
mkdirSync(CREDENTIALS_DIR, { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Remove existing credentials
|
|
115
|
+
if (existsSync(CREDENTIALS_DIR)) {
|
|
116
|
+
const existing = await readdir(CREDENTIALS_DIR);
|
|
117
|
+
for (const f of existing) {
|
|
118
|
+
if (f.startsWith('cred-') && f.endsWith('.json')) {
|
|
119
|
+
await unlink(join(CREDENTIALS_DIR, f));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Copy from backup
|
|
125
|
+
for (const f of credBackups) {
|
|
126
|
+
const destName = f.replace(`credentials.${timestamp}.`, '');
|
|
127
|
+
await copyFile(join(backupsDir, f), join(CREDENTIALS_DIR, destName));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return credBackups.length;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function runMigrations(): Promise<number> {
|
|
134
|
+
try {
|
|
135
|
+
const output = execSync('npx prisma migrate deploy', {
|
|
136
|
+
cwd: join(__dirname, '..', '..', '..'),
|
|
137
|
+
env: { ...process.env, DATABASE_URL: `file:${getDbPath()}` },
|
|
138
|
+
encoding: 'utf-8',
|
|
139
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Count applied migrations from output
|
|
143
|
+
const matches = output.match(/(\d+) migration/);
|
|
144
|
+
return matches ? parseInt(matches[1], 10) : 0;
|
|
145
|
+
} catch (error: any) {
|
|
146
|
+
const errMsg = error.stderr || error.message || 'Unknown error';
|
|
147
|
+
console.error(`\n ✗ Migration FAILED: ${errMsg}`);
|
|
148
|
+
console.error(' This is a critical error — the restored DB may have an incompatible schema.');
|
|
149
|
+
throw new Error(`Migration failed: ${errMsg}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function main() {
|
|
154
|
+
const args = process.argv.slice(2);
|
|
155
|
+
const listFlag = args.includes('--list');
|
|
156
|
+
const latestFlag = args.includes('--latest');
|
|
157
|
+
const dryRun = args.includes('--dry-run');
|
|
158
|
+
const filename = args.find((a) => !a.startsWith('--'));
|
|
159
|
+
|
|
160
|
+
if (!listFlag && !latestFlag && !filename) {
|
|
161
|
+
console.log(`
|
|
162
|
+
aurawallet restore — Restore from a backup
|
|
163
|
+
|
|
164
|
+
Usage:
|
|
165
|
+
npx aurawallet restore --list List available backups
|
|
166
|
+
npx aurawallet restore --latest Restore most recent backup
|
|
167
|
+
npx aurawallet restore <filename> Restore specific backup
|
|
168
|
+
npx aurawallet restore --dry-run --latest Preview without modifying
|
|
169
|
+
`);
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// --list: show backups and exit
|
|
174
|
+
if (listFlag) {
|
|
175
|
+
const backups = await listBackups();
|
|
176
|
+
if (backups.length === 0) {
|
|
177
|
+
console.log('No backups found.');
|
|
178
|
+
process.exit(0);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log(`\n Available backups (${backups.length}):\n`);
|
|
182
|
+
for (const b of backups) {
|
|
183
|
+
console.log(` ${b.filename} ${formatTimestamp(b.timestamp)} ${formatSize(b.size)}`);
|
|
184
|
+
}
|
|
185
|
+
console.log();
|
|
186
|
+
process.exit(0);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Determine which backup to restore
|
|
190
|
+
let targetFilename: string;
|
|
191
|
+
if (latestFlag) {
|
|
192
|
+
const backups = await listBackups();
|
|
193
|
+
if (backups.length === 0) {
|
|
194
|
+
console.error('No backups found.');
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
targetFilename = backups[0].filename;
|
|
198
|
+
} else {
|
|
199
|
+
targetFilename = filename!;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Validate filename
|
|
203
|
+
if (!targetFilename.match(/^aurawallet\.db\.\d{8}_\d{6}\.bak$/)) {
|
|
204
|
+
console.error(`Invalid backup filename: ${targetFilename}`);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const backupsDir = getBackupsDir();
|
|
209
|
+
const backupPath = join(backupsDir, targetFilename);
|
|
210
|
+
|
|
211
|
+
if (!existsSync(backupPath)) {
|
|
212
|
+
console.error(`Backup not found: ${targetFilename}`);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const backupStat = await stat(backupPath);
|
|
217
|
+
const tsMatch = targetFilename.match(/aurawallet\.db\.(\d{8}_\d{6})\.bak/)!;
|
|
218
|
+
const timestamp = tsMatch[1];
|
|
219
|
+
|
|
220
|
+
// Count matching credential backups
|
|
221
|
+
const allFiles = await readdir(backupsDir);
|
|
222
|
+
const credCount = allFiles.filter(
|
|
223
|
+
(f) => f.startsWith(`credentials.${timestamp}.cred-`) && f.endsWith('.json')
|
|
224
|
+
).length;
|
|
225
|
+
|
|
226
|
+
console.log(`\n Restore target: ${targetFilename}`);
|
|
227
|
+
console.log(` Created: ${formatTimestamp(timestamp)}`);
|
|
228
|
+
console.log(` Size: ${formatSize(backupStat.size)}`);
|
|
229
|
+
console.log(` Credentials: ${credCount} file(s)`);
|
|
230
|
+
|
|
231
|
+
// Verify backup integrity
|
|
232
|
+
console.log('\n Verifying backup integrity...');
|
|
233
|
+
if (!verifyIntegrity(backupPath)) {
|
|
234
|
+
console.error(' ✗ Backup FAILED integrity check. Aborting.');
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
console.log(' ✓ Backup integrity OK');
|
|
238
|
+
|
|
239
|
+
if (dryRun) {
|
|
240
|
+
console.log('\n --dry-run: No changes made.\n');
|
|
241
|
+
process.exit(0);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Check if server is running
|
|
245
|
+
const serverRunning = await checkServerRunning();
|
|
246
|
+
if (serverRunning) {
|
|
247
|
+
console.log('\n ⚠️ WARNING: Server appears to be running on port 4242.');
|
|
248
|
+
console.log(' Stop it first with `npx aurawallet stop` for clean restore.');
|
|
249
|
+
console.log(' Proceeding anyway...\n');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Pre-restore safety backup
|
|
253
|
+
const preRestoreName = await createPreRestoreBackup();
|
|
254
|
+
if (preRestoreName) {
|
|
255
|
+
console.log(` Pre-restore backup: ${preRestoreName}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Restore DB
|
|
259
|
+
const dbPath = getDbPath();
|
|
260
|
+
const tempPath = dbPath + '.restore-tmp';
|
|
261
|
+
await copyFile(backupPath, tempPath);
|
|
262
|
+
await rename(tempPath, dbPath);
|
|
263
|
+
console.log(' ✓ Database restored');
|
|
264
|
+
|
|
265
|
+
// Restore credentials
|
|
266
|
+
const restoredCreds = await restoreCredentials(backupsDir, timestamp);
|
|
267
|
+
console.log(` ✓ Credentials restored: ${restoredCreds} file(s)`);
|
|
268
|
+
|
|
269
|
+
// Run migrations
|
|
270
|
+
console.log(' Running schema migrations...');
|
|
271
|
+
let migrationsApplied: number;
|
|
272
|
+
try {
|
|
273
|
+
migrationsApplied = await runMigrations();
|
|
274
|
+
} catch {
|
|
275
|
+
if (preRestoreName) {
|
|
276
|
+
console.error(`\n Reverting to pre-restore backup: ${preRestoreName}`);
|
|
277
|
+
const revertTemp = dbPath + '.revert-tmp';
|
|
278
|
+
await copyFile(join(backupsDir, preRestoreName), revertTemp);
|
|
279
|
+
await rename(revertTemp, dbPath);
|
|
280
|
+
console.error(' ✓ Reverted to pre-restore state.');
|
|
281
|
+
}
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
console.log(` ✓ Migrations applied: ${migrationsApplied}`);
|
|
285
|
+
|
|
286
|
+
// Final integrity check
|
|
287
|
+
console.log(' Verifying restored database...');
|
|
288
|
+
if (!verifyIntegrity(dbPath)) {
|
|
289
|
+
console.error(' ✗ Restored DB FAILED integrity check!');
|
|
290
|
+
console.error(` Safety backup available: ${preRestoreName}`);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
console.log(' ✓ Restored database integrity OK');
|
|
294
|
+
|
|
295
|
+
// Clean up old pre-restore backups (keep last 3)
|
|
296
|
+
const allBackupFiles = await readdir(backupsDir);
|
|
297
|
+
const preRestoreFiles = allBackupFiles
|
|
298
|
+
.filter(f => f.startsWith('pre-restore.') && f.endsWith('.bak'))
|
|
299
|
+
.sort()
|
|
300
|
+
.reverse();
|
|
301
|
+
if (preRestoreFiles.length > 3) {
|
|
302
|
+
for (let i = 3; i < preRestoreFiles.length; i++) {
|
|
303
|
+
await unlink(join(backupsDir, preRestoreFiles[i]));
|
|
304
|
+
}
|
|
305
|
+
console.log(` ✓ Cleaned up ${preRestoreFiles.length - 3} old pre-restore backup(s)`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log(`\n ✅ Restore complete!\n`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
main().catch((err) => {
|
|
312
|
+
console.error('Restore failed:', err.message || err);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
});
|