auramaxx 0.0.17 → 0.0.19
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 -1
- package/.next/app-build-manifest.json +70 -70
- package/.next/app-path-routes-manifest.json +2 -2
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +30 -30
- package/.next/react-loadable-manifest.json +16 -16
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +5 -5
- package/.next/server/app/api/[...doc]/page.js.nft.json +1 -1
- package/.next/server/app/api/[...doc]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agent-requests/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/apps/install/route.js.nft.json +1 -1
- package/.next/server/app/api/apps/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/apps/manifests/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/apps/static/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/docs/plain/route.js.nft.json +1 -1
- package/.next/server/app/api/docs/plain/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/import-from-openclaw/[channel]/route.js.nft.json +1 -1
- package/.next/server/app/api/import-from-openclaw/[channel]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/import-from-openclaw/route.js.nft.json +1 -1
- package/.next/server/app/api/import-from-openclaw/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/import-from-openclaw/validate/[channel]/route.js.nft.json +1 -1
- package/.next/server/app/api/import-from-openclaw/validate/[channel]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/page.js.nft.json +1 -1
- package/.next/server/app/api/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/apps/[wid]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/export/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/import/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/route_client-reference-manifest.js +1 -1
- package/.next/server/app/app-legacy-do-not-use/page.js +3 -3
- package/.next/server/app/app-legacy-do-not-use/page.js.nft.json +1 -1
- package/.next/server/app/app-legacy-do-not-use/page_client-reference-manifest.js +1 -1
- package/.next/server/app/app-legacy-do-not-use.html +1 -1
- package/.next/server/app/app-legacy-do-not-use.rsc +6 -6
- package/.next/server/app/approve/[actionId]/page.js.nft.json +1 -1
- package/.next/server/app/approve/[actionId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/docs/[...doc]/page.js.nft.json +1 -1
- package/.next/server/app/docs/[...doc]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/docs/page.js.nft.json +1 -1
- package/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/health/page.js.nft.json +1 -1
- package/.next/server/app/health/page_client-reference-manifest.js +1 -1
- package/.next/server/app/health.html +1 -1
- package/.next/server/app/health.rsc +5 -5
- package/.next/server/app/hello/page.js.nft.json +1 -1
- package/.next/server/app/hello/page_client-reference-manifest.js +1 -1
- package/.next/server/app/hello.html +1 -1
- package/.next/server/app/hello.rsc +5 -5
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +6 -6
- package/.next/server/app/page.js +9 -3
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/privacy/page.js.nft.json +1 -1
- package/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
- package/.next/server/app/privacy.html +1 -1
- package/.next/server/app/privacy.rsc +5 -5
- package/.next/server/app/share/[token]/page.js.nft.json +1 -1
- package/.next/server/app/share/[token]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/terms/page.js.nft.json +1 -1
- package/.next/server/app/terms/page_client-reference-manifest.js +1 -1
- package/.next/server/app/terms.html +1 -1
- package/.next/server/app/terms.rsc +5 -5
- package/.next/server/app/yo/page.js +1 -1
- package/.next/server/app/yo/page.js.nft.json +1 -1
- package/.next/server/app/yo/page_client-reference-manifest.js +1 -1
- package/.next/server/app/yo.html +1 -1
- package/.next/server/app/yo.rsc +6 -6
- package/.next/server/app-paths-manifest.json +2 -2
- package/.next/server/chunks/1196.js +1 -1
- package/.next/server/chunks/{6415.js → 2123.js} +2 -2
- package/.next/server/chunks/2234.js +1 -1
- package/.next/server/chunks/4224.js +1 -0
- package/.next/server/chunks/4600.js +1 -1
- package/.next/server/chunks/5678.js +1 -1
- package/.next/server/chunks/5991.js +7 -0
- package/.next/server/chunks/6470.js +1 -1
- package/.next/server/chunks/7585.js +1 -1
- package/.next/server/chunks/7935.js +19 -11
- package/.next/server/chunks/8468.js +1 -1
- package/.next/server/chunks/{1350.js → 9323.js} +3 -3
- package/.next/server/chunks/9971.js +1 -1
- package/.next/server/functions-config-manifest.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{1168.aaac1edbb597fe5a.js → 1168.bb1c93965872e980.js} +1 -1
- package/.next/static/chunks/2891-bf010357841c9ce9.js +1 -0
- package/.next/static/chunks/{2927.7e00cc878d9a3f52.js → 2927.3976471e61df966e.js} +1 -1
- package/.next/static/chunks/{3573-1b41d7b8a000d015.js → 3573-667bc4c8f56afcff.js} +1 -1
- package/.next/static/chunks/{3a91511d-ba215c0b5dc21ba9.js → 3a91511d-da2c74cad6c6fc33.js} +2 -2
- package/.next/static/chunks/4114-a375178fd94c4d8a.js +1 -0
- package/.next/static/chunks/{4256.48407d9abad5ea33.js → 4256.aa831e4d8c3f65bc.js} +1 -1
- package/.next/static/chunks/{4919-7e7cdd5efc9f2110.js → 4919-0e698cd95504e355.js} +1 -1
- package/.next/static/chunks/{5336-233ec7ab3807267c.js → 5336-b775f449d7433604.js} +1 -1
- package/.next/static/chunks/{7338-3ce17a93614f1d77.js → 5362-2e8fcdd0bc6273ca.js} +4 -4
- package/.next/static/chunks/67-cb9bbb430499e803.js +1 -0
- package/.next/static/chunks/{8273-8e92d34180669ca9.js → 8273-3b9d882c5dd6a9a8.js} +1 -1
- package/.next/static/chunks/8291-8f6fb6554e692552.js +1 -0
- package/.next/static/chunks/8370-6537b6b27df58b23.js +1 -0
- package/.next/static/chunks/app/app-legacy-do-not-use/page-efa348da049c5873.js +1 -0
- package/.next/static/chunks/app/{error-63cbe72522239cff.js → error-04a18fd49a89ee17.js} +1 -1
- package/.next/static/chunks/app/layout-7093dda0d106f34d.js +1 -0
- package/.next/static/chunks/app/page-0ec7cf48550f71e6.js +1 -0
- package/.next/static/chunks/app/yo/{page-cf5d6540ea31c31c.js → page-48930746b135037e.js} +1 -1
- package/.next/static/chunks/{webpack-79ad58260e9b10b4.js → webpack-15ec0114c9d658c2.js} +1 -1
- package/.next/static/css/35991998d1b5eff0.css +3 -0
- package/.next/trace +28 -28
- package/README.md +2 -2
- package/bin/auramaxx.js +87 -3
- package/package.json +8 -4
- package/prisma/migrations/20260301225214_social_tables/migration.sql +81 -0
- package/prisma/migrations/20260302120000_add_notification_hash/migration.sql +8 -0
- package/prisma/migrations/20260302160000_add_public_key_hex/migration.sql +5 -0
- package/prisma/migrations/20260302170000_add_inbound_author_public_key/migration.sql +5 -0
- package/prisma/schema.prisma +272 -177
- package/shared/credential-field-schema.ts +10 -0
- package/skills/auramaxx/SKILL.md +33 -4
- package/skills/auramaxx/docs/AGENT_SETUP.md +7 -2
- package/src/app/UnlockPageClient.tsx +448 -43
- package/src/app/app-legacy-do-not-use/page.tsx +5 -3
- package/src/app/globals.css +1 -1
- package/src/components/AgentPicker.tsx +278 -0
- package/src/components/CreateAgentModal.tsx +192 -0
- package/src/components/NotificationDrawer.tsx +15 -13
- package/src/components/agent/AgentSidebar.tsx +2 -19
- package/src/components/agent/CredentialAgent.tsx +70 -37
- package/src/components/agent/CredentialForm.tsx +32 -7
- package/src/components/agent/CredentialList.tsx +149 -72
- package/src/components/agents/AgentsView.tsx +1035 -0
- package/src/components/design-system/TextAreaInput.tsx +78 -0
- package/src/components/design-system/index.ts +1 -0
- package/src/components/hub/HubView.tsx +58 -0
- package/src/components/layout/LeftRail.tsx +333 -40
- package/src/components/layout/ViewShell.tsx +125 -0
- package/src/components/layout/index.ts +1 -0
- package/src/components/social/PrimaryHubRegistrationGate.tsx +260 -0
- package/src/components/social/SocialView.tsx +904 -0
- package/src/hooks/useSocialNotifications.ts +123 -0
- package/src/lib/events.ts +10 -1
- package/src/lib/social-client.ts +319 -0
- package/src/lib/view-registry.ts +22 -4
- package/src/server/cli/commands/agent.ts +33 -7
- package/src/server/cli/commands/create.ts +209 -0
- package/src/server/cli/commands/onboard.ts +39 -0
- package/src/server/cli/commands/play.ts +68 -0
- package/src/server/cli/commands/register-agent.ts +181 -0
- package/src/server/cli/commands/social.ts +648 -0
- package/src/server/cli/commands/start.ts +4 -3
- package/src/server/cron/index.ts +5 -9
- package/src/server/cron/jobs/social-inbound.ts +596 -0
- package/src/server/cron/jobs/social-outbound.ts +70 -0
- package/src/server/index.ts +14 -0
- package/src/server/lib/agent-profiles.ts +10 -1
- package/src/server/lib/cold.ts +0 -45
- package/src/server/lib/credential-import.ts +53 -47
- package/src/server/lib/defaults.ts +11 -0
- package/src/server/lib/feature-flags.ts +3 -0
- package/src/server/lib/hub-auth.ts +159 -0
- package/src/server/lib/migrate-agent-profiles.ts +96 -0
- package/src/server/lib/notifications.ts +12 -1
- package/src/server/lib/permissions.ts +10 -0
- package/src/server/lib/project-scope.ts +33 -5
- package/src/server/lib/social/create.ts +176 -0
- package/src/server/lib/social/global-aura-id.ts +115 -0
- package/src/server/lib/social/hub-rpc-client.ts +99 -0
- package/src/server/lib/social/hub-session.ts +6 -0
- package/src/server/lib/social/public-key.ts +32 -0
- package/src/server/lib/social/register.ts +162 -0
- package/src/server/lib/social/sign.ts +95 -0
- package/src/server/lib/social/sync.ts +301 -0
- package/src/server/mcp/server.ts +142 -18
- package/src/server/mcp/tools.ts +552 -0
- package/src/server/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/src/server/routes/agent-hub.ts +276 -0
- package/src/server/routes/agent-profiles.ts +145 -19
- package/src/server/routes/credentials.ts +49 -15
- package/src/server/routes/heartbeat.ts +3 -7
- package/src/server/routes/passkey.ts +7 -1
- package/src/server/routes/social.ts +869 -0
- package/src/server/routes/unlock.ts +17 -1
- package/src/server/routes/verified-credentials.ts +312 -0
- package/src/server/test-data/template.db +0 -0
- package/src/server/test-data/worker-1/agent-primary.json +12 -0
- package/src/server/test-data/worker-1/auramaxx.db +0 -0
- package/src/server/test-data/worker-1/backups/auramaxx.db.20260305_011404.bak +0 -0
- package/src/server/test-data/worker-1/backups/credentials.20260305_011404.cred-00ntf5h3.json +24 -0
- package/src/server/test-data/worker-1/backups/credentials.20260305_011404.cred-dh8fa9k3.json +24 -0
- package/src/server/test-data/worker-1/backups/credentials.20260305_011404.cred-prfhlyow.json +25 -0
- package/src/server/test-data/worker-1/backups/credentials.20260305_011404.cred-w26jd6zi.json +22 -0
- package/src/server/test-data/worker-1/config.json +33 -0
- package/src/server/test-data/worker-1/test.db +0 -0
- package/src/server/test-data/worker-10/agent-primary.json +12 -0
- package/src/server/test-data/worker-10/config.json +33 -0
- package/src/server/test-data/worker-10/test.db +0 -0
- package/src/server/test-data/worker-11/agent-primary.json +12 -0
- package/src/server/test-data/worker-11/config.json +33 -0
- package/src/server/test-data/worker-11/test.db +0 -0
- package/src/server/test-data/worker-12/agent-primary.json +12 -0
- package/src/server/test-data/worker-12/config.json +33 -0
- package/src/server/test-data/worker-12/credentials/cred-hboagned.json +25 -0
- package/src/server/test-data/worker-12/credentials/cred-nt14xd9t.json +24 -0
- package/src/server/test-data/worker-12/credentials/cred-qn59xefc.json +24 -0
- package/src/server/test-data/worker-12/test.db +0 -0
- package/src/server/test-data/worker-13/agent-primary.json +12 -0
- package/src/server/test-data/worker-13/approval-context.json +56 -0
- package/src/server/test-data/worker-13/approval-context.key +1 -0
- package/src/server/test-data/worker-13/config.json +33 -0
- package/src/server/test-data/worker-13/credentials-recently-deleted/cred-jn9yqy2m.json +20 -0
- package/src/server/test-data/worker-13/test.db +0 -0
- package/src/server/test-data/worker-14/agent-primary.json +12 -0
- package/src/server/test-data/worker-14/config.json +33 -0
- package/src/server/test-data/worker-14/test.db +0 -0
- package/src/server/test-data/worker-15/agent-primary.json +12 -0
- package/src/server/test-data/worker-15/config.json +33 -0
- package/src/server/test-data/worker-15/test.db +0 -0
- package/src/server/test-data/worker-15/update-check-4b305e76.json +5 -0
- package/src/server/test-data/worker-2/agent-primary.json +12 -0
- package/src/server/test-data/worker-2/config.json +33 -0
- package/src/server/test-data/worker-2/test.db +0 -0
- package/src/server/test-data/worker-3/agent-primary.json +12 -0
- package/src/server/test-data/worker-3/config.json +33 -0
- package/src/server/test-data/worker-3/test.db +0 -0
- package/src/server/test-data/worker-4/agent-primary.json +12 -0
- package/src/server/test-data/worker-4/config.json +33 -0
- package/src/server/test-data/worker-4/credentials/cred-bm6p74u5.json +24 -0
- package/src/server/test-data/worker-4/credentials/cred-r8eqb07i.json +25 -0
- package/src/server/test-data/worker-4/credentials/cred-ziv49y9h.json +24 -0
- package/src/server/test-data/worker-4/test.db +0 -0
- package/src/server/test-data/worker-5/agent-primary.json +12 -0
- package/src/server/test-data/worker-5/config.json +33 -0
- package/src/server/test-data/worker-5/credentials/cred-15gyfeht.json +25 -0
- package/src/server/test-data/worker-5/credentials/cred-lp0ocnfc.json +24 -0
- package/src/server/test-data/worker-5/credentials/cred-zfbwfxw0.json +24 -0
- package/src/server/test-data/worker-5/test.db +0 -0
- package/src/server/test-data/worker-6/agent-primary.json +12 -0
- package/src/server/test-data/worker-6/config.json +33 -0
- package/src/server/test-data/worker-6/credentials/cred-dx8li3ue.json +24 -0
- package/src/server/test-data/worker-6/credentials/cred-myeskqky.json +24 -0
- package/src/server/test-data/worker-6/credentials/cred-tam01qdt.json +25 -0
- package/src/server/test-data/worker-6/credentials/cred-wdh6rslw.json +22 -0
- package/src/server/test-data/worker-6/credentials-archive/cred-4wg53v1y.json +25 -0
- package/src/server/test-data/worker-6/test.db +0 -0
- package/src/server/test-data/worker-7/agent-primary.json +12 -0
- package/src/server/test-data/worker-7/config.json +33 -0
- package/src/server/test-data/worker-7/credentials/cred-ji7ec57d.json +25 -0
- package/src/server/test-data/worker-7/credentials/cred-mmgj0ypo.json +24 -0
- package/src/server/test-data/worker-7/credentials/cred-nb0ic93x.json +24 -0
- package/src/server/test-data/worker-7/test.db +0 -0
- package/src/server/test-data/worker-8/agent-primary.json +12 -0
- package/src/server/test-data/worker-8/config.json +33 -0
- package/src/server/test-data/worker-8/test.db +0 -0
- package/src/server/test-data/worker-9/agent-primary.json +12 -0
- package/src/server/test-data/worker-9/test.db +0 -0
- package/src/server/tests/cli/bin-entrypoint.test.ts +99 -0
- package/src/server/tests/cli/social.test.ts +83 -0
- package/src/server/tests/cron/social-inbound-followers.unit.test.ts +164 -0
- package/src/server/tests/cron/social-inbound-staleness.test.ts +193 -0
- package/src/server/tests/cron/social-outbound.test.ts +252 -0
- package/src/server/tests/endpoints/agent.test.ts +0 -16
- package/src/server/tests/lib/credential-field-schema.test.ts +448 -0
- package/src/server/tests/lib/project-scope.test.ts +49 -0
- package/src/server/tests/lib/social/create.test.ts +207 -0
- package/src/server/tests/lib/social/sign.test.ts +163 -0
- package/src/server/tests/lib/social/sync.test.ts +198 -0
- package/src/server/tests/mcp/server.test.ts +1 -3
- package/src/server/tests/mcp/tools.test.ts +219 -7
- package/src/server/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.json +1 -0
- package/.next/server/chunks/2460.js +0 -7
- package/.next/server/chunks/5246.js +0 -1
- package/.next/static/chunks/3667-1db7bd03948e60df.js +0 -1
- package/.next/static/chunks/5442-b5bb869e832e8967.js +0 -1
- package/.next/static/chunks/6872-a8f1ad5fc35a1c35.js +0 -1
- package/.next/static/chunks/7394-4bdb1feefad1a74a.js +0 -1
- package/.next/static/chunks/7587-8542eae6e5139d27.js +0 -1
- package/.next/static/chunks/app/app-legacy-do-not-use/page-569fed5d1a2bfe79.js +0 -1
- package/.next/static/chunks/app/layout-af8d9969c7aeb758.js +0 -1
- package/.next/static/chunks/app/page-9bd0ec3ba4aa6cea.js +0 -1
- package/.next/static/css/88f92e1578b1e5d9.css +0 -3
- package/shared/agent-profile-schema.ts +0 -81
- package/src/internal/security/frontend-api-authorization-audit.md +0 -206
- package/src/server/lib/agent-profile-records.ts +0 -72
- /package/.next/static/{QPzVnl7GToqgYBq14V_iC → yEruVJH_cuht5hu5_1R00}/_buildManifest.js +0 -0
- /package/.next/static/{QPzVnl7GToqgYBq14V_iC → yEruVJH_cuht5hu5_1R00}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
4
|
+
import { useWebSocket } from '@/context/WebSocketContext';
|
|
5
|
+
import { WALLET_EVENTS, type WalletEvent, type NotificationCreatedData } from '@/lib/events';
|
|
6
|
+
import { api, Api } from '@/lib/api';
|
|
7
|
+
|
|
8
|
+
export interface SocialNotification {
|
|
9
|
+
id: string;
|
|
10
|
+
type: string;
|
|
11
|
+
category: string;
|
|
12
|
+
title: string;
|
|
13
|
+
message: string;
|
|
14
|
+
read: boolean;
|
|
15
|
+
dismissed: boolean;
|
|
16
|
+
metadata: string | null;
|
|
17
|
+
hash: string | null;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
agentId: string | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface SocialNotificationMeta {
|
|
23
|
+
socialType?: 'reaction' | 'reply' | 'follow';
|
|
24
|
+
actorAuraId?: number;
|
|
25
|
+
actorPublicKey?: string;
|
|
26
|
+
eventHash?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface FetchResponse {
|
|
30
|
+
success: boolean;
|
|
31
|
+
notifications: SocialNotification[];
|
|
32
|
+
total: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface UpdateResponse {
|
|
36
|
+
success: boolean;
|
|
37
|
+
updated: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function parseSocialMeta(raw: string | null): SocialNotificationMeta {
|
|
41
|
+
if (!raw) return {};
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw) as SocialNotificationMeta;
|
|
44
|
+
} catch {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function useSocialNotifications(agentId: string | null) {
|
|
50
|
+
const [notifications, setNotifications] = useState<SocialNotification[]>([]);
|
|
51
|
+
const [loading, setLoading] = useState(false);
|
|
52
|
+
const mountedRef = useRef(true);
|
|
53
|
+
const { subscribe, connected } = useWebSocket();
|
|
54
|
+
|
|
55
|
+
const fetchNotifications = useCallback(async () => {
|
|
56
|
+
setLoading(true);
|
|
57
|
+
try {
|
|
58
|
+
const qs = agentId ? `agentId=${encodeURIComponent(agentId)}&limit=50` : 'limit=50';
|
|
59
|
+
const data = await api.get<FetchResponse>(Api.Wallet, `/social/notifications?${qs}`);
|
|
60
|
+
if (mountedRef.current && data.success) {
|
|
61
|
+
setNotifications(data.notifications);
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// Silently ignore - social may not be enabled
|
|
65
|
+
} finally {
|
|
66
|
+
if (mountedRef.current) setLoading(false);
|
|
67
|
+
}
|
|
68
|
+
}, [agentId]);
|
|
69
|
+
|
|
70
|
+
// Initial fetch
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
mountedRef.current = true;
|
|
73
|
+
fetchNotifications();
|
|
74
|
+
return () => { mountedRef.current = false; };
|
|
75
|
+
}, [agentId, fetchNotifications]);
|
|
76
|
+
|
|
77
|
+
// Refetch on reconnect
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (connected) fetchNotifications();
|
|
80
|
+
}, [connected, agentId, fetchNotifications]);
|
|
81
|
+
|
|
82
|
+
// Listen for real-time notification:created events
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const unsub = subscribe(WALLET_EVENTS.NOTIFICATION_CREATED, (event) => {
|
|
85
|
+
const data = (event as WalletEvent).data as NotificationCreatedData;
|
|
86
|
+
if (data.category !== 'social') return;
|
|
87
|
+
if (agentId && data.agentId !== agentId) return;
|
|
88
|
+
// Refetch to get full notification data
|
|
89
|
+
fetchNotifications();
|
|
90
|
+
});
|
|
91
|
+
return unsub;
|
|
92
|
+
}, [subscribe, agentId, fetchNotifications]);
|
|
93
|
+
|
|
94
|
+
const unreadCount = useMemo(
|
|
95
|
+
() => notifications.filter((n) => !n.read && !n.dismissed).length,
|
|
96
|
+
[notifications],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const markRead = useCallback(async (ids: string[]) => {
|
|
100
|
+
if (ids.length === 0) return;
|
|
101
|
+
setNotifications((prev) => prev.map((n) => ids.includes(n.id) ? { ...n, read: true } : n));
|
|
102
|
+
try {
|
|
103
|
+
await api.post<UpdateResponse>(Api.Wallet, '/social/notifications/read', { ids });
|
|
104
|
+
} catch { /* best-effort */ }
|
|
105
|
+
}, []);
|
|
106
|
+
|
|
107
|
+
const dismiss = useCallback(async (ids: string[]) => {
|
|
108
|
+
if (ids.length === 0) return;
|
|
109
|
+
setNotifications((prev) => prev.map((n) => ids.includes(n.id) ? { ...n, dismissed: true, read: true } : n));
|
|
110
|
+
try {
|
|
111
|
+
await api.post<UpdateResponse>(Api.Wallet, '/social/notifications/dismiss', { ids });
|
|
112
|
+
} catch { /* best-effort */ }
|
|
113
|
+
}, []);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
notifications,
|
|
117
|
+
unreadCount,
|
|
118
|
+
loading,
|
|
119
|
+
markRead,
|
|
120
|
+
dismiss,
|
|
121
|
+
refresh: fetchNotifications,
|
|
122
|
+
};
|
|
123
|
+
}
|
package/src/lib/events.ts
CHANGED
|
@@ -216,6 +216,13 @@ export interface CredentialAccessedData {
|
|
|
216
216
|
tokenHash?: string;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
export interface NotificationCreatedData {
|
|
220
|
+
agentId: string;
|
|
221
|
+
notificationId: string;
|
|
222
|
+
category: string;
|
|
223
|
+
title: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
219
226
|
export interface BalanceUpdatedData {
|
|
220
227
|
chain: string;
|
|
221
228
|
type: 'native' | 'token';
|
|
@@ -234,7 +241,8 @@ export type WalletEventData =
|
|
|
234
241
|
| ActionCreatedData
|
|
235
242
|
| ActionResolvedData
|
|
236
243
|
| CredentialChangedData
|
|
237
|
-
| CredentialAccessedData
|
|
244
|
+
| CredentialAccessedData
|
|
245
|
+
| NotificationCreatedData;
|
|
238
246
|
|
|
239
247
|
// Event types as const for type safety
|
|
240
248
|
export const WALLET_EVENTS = {
|
|
@@ -251,6 +259,7 @@ export const WALLET_EVENTS = {
|
|
|
251
259
|
CREDENTIAL_CHANGED: 'credential:changed',
|
|
252
260
|
CREDENTIAL_ACCESSED: 'credential:accessed',
|
|
253
261
|
SECRET_ACCESSED: 'secret:accessed',
|
|
262
|
+
NOTIFICATION_CREATED: 'notification:created',
|
|
254
263
|
} as const;
|
|
255
264
|
|
|
256
265
|
export type WalletEventType = (typeof WALLET_EVENTS)[keyof typeof WALLET_EVENTS];
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { api, Api } from './api';
|
|
2
|
+
|
|
3
|
+
export interface SocialAgentInfo {
|
|
4
|
+
id: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
isPrimary: boolean;
|
|
7
|
+
parentAgentId?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface SocialMessageItem {
|
|
11
|
+
id: string;
|
|
12
|
+
agentId: string;
|
|
13
|
+
hash: string;
|
|
14
|
+
type: string;
|
|
15
|
+
body: string;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
syncStatus?: string;
|
|
18
|
+
createdAt?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface InboundMessageItem {
|
|
22
|
+
id: string;
|
|
23
|
+
agentId: string;
|
|
24
|
+
hash: string;
|
|
25
|
+
authorAuraId: number;
|
|
26
|
+
type: string;
|
|
27
|
+
body: string;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface FollowerItem {
|
|
32
|
+
id: string;
|
|
33
|
+
authorAuraId: number;
|
|
34
|
+
timestamp: number;
|
|
35
|
+
body: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface FollowingItem {
|
|
39
|
+
auraId: number;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SyncStatus {
|
|
44
|
+
pending: number;
|
|
45
|
+
accepted: number;
|
|
46
|
+
rejected: number;
|
|
47
|
+
failed: number;
|
|
48
|
+
total: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface AgentProfile {
|
|
52
|
+
pfp: string;
|
|
53
|
+
handle: string;
|
|
54
|
+
displayName: string;
|
|
55
|
+
pfpIsSprite?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface HubSubscriptionInfo {
|
|
59
|
+
id: string;
|
|
60
|
+
agentId: string;
|
|
61
|
+
hubUrl: string;
|
|
62
|
+
frontendUrl: string | null;
|
|
63
|
+
label: string | null;
|
|
64
|
+
auraId: number | null;
|
|
65
|
+
inboundSeq: number | null;
|
|
66
|
+
inboundMode: string | null;
|
|
67
|
+
joinedAt: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface ProfileMessageItem {
|
|
71
|
+
body: string;
|
|
72
|
+
createdAt?: string;
|
|
73
|
+
timestamp?: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const DEFAULT_AGENT_AVATAR = 'https://auramaxx.sh/agent7.png';
|
|
77
|
+
|
|
78
|
+
function parseLatestProfile(messages: ProfileMessageItem[]): AgentProfile {
|
|
79
|
+
const latest: Record<string, { value: string; rank: number }> = {};
|
|
80
|
+
for (const msg of messages) {
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(msg.body) as { type?: string; value?: string };
|
|
83
|
+
if (!parsed.type) continue;
|
|
84
|
+
const rank = msg.createdAt
|
|
85
|
+
? Date.parse(msg.createdAt)
|
|
86
|
+
: typeof msg.timestamp === 'number'
|
|
87
|
+
? msg.timestamp * 1000
|
|
88
|
+
: 0;
|
|
89
|
+
const existing = latest[parsed.type];
|
|
90
|
+
if (!existing || rank >= existing.rank) {
|
|
91
|
+
latest[parsed.type] = { value: parsed.value ?? '', rank };
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
// ignore malformed profile rows
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const pfpVal = latest.pfp?.value || DEFAULT_AGENT_AVATAR;
|
|
99
|
+
return {
|
|
100
|
+
pfp: pfpVal,
|
|
101
|
+
handle: latest.handle?.value || '',
|
|
102
|
+
displayName: latest.display_name?.value || '',
|
|
103
|
+
pfpIsSprite: latest.pfp_is_sprite?.value === 'true'
|
|
104
|
+
|| (!latest.pfp_is_sprite && /\/agent\d+\.png$/.test(pfpVal)),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function tryParseBody(body: string): Record<string, unknown> {
|
|
109
|
+
try {
|
|
110
|
+
return JSON.parse(body) as Record<string, unknown>;
|
|
111
|
+
} catch {
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function shouldApplyPostRemove(syncStatus?: string): boolean {
|
|
117
|
+
return syncStatus !== 'failed' && syncStatus !== 'rejected';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function extractRemovedPostHash(message: SocialMessageItem): string | null {
|
|
121
|
+
const parsed = tryParseBody(message.body);
|
|
122
|
+
const raw = parsed.targetPostHash ?? parsed.postHash ?? parsed.targetHash;
|
|
123
|
+
if (typeof raw !== 'string') return null;
|
|
124
|
+
const trimmed = raw.trim();
|
|
125
|
+
return trimmed ? trimmed : null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function fetchSocialAgents(): Promise<SocialAgentInfo[]> {
|
|
129
|
+
const res = await api.get<{ agents: SocialAgentInfo[] }>(Api.Wallet, '/agents/credential');
|
|
130
|
+
return res.agents || [];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface GlobalFeedAuthorProfile {
|
|
134
|
+
handle: string | null;
|
|
135
|
+
displayName: string | null;
|
|
136
|
+
pfp: string | null;
|
|
137
|
+
pfpIsSprite: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface GlobalFeedItem {
|
|
141
|
+
postHash: string;
|
|
142
|
+
authorAuraId: number;
|
|
143
|
+
text: string;
|
|
144
|
+
updatedTs: number;
|
|
145
|
+
authorScore: number;
|
|
146
|
+
authorProfile: GlobalFeedAuthorProfile | null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function fetchGlobalFeed(cursor?: string, hubUrl?: string): Promise<{ items: GlobalFeedItem[]; nextCursor: string | null }> {
|
|
150
|
+
const params: Record<string, string | number> = { limit: 50 };
|
|
151
|
+
if (cursor) params.cursor = cursor;
|
|
152
|
+
if (hubUrl) params.hubUrl = hubUrl;
|
|
153
|
+
const res = await api.get<{ ok: boolean; items: GlobalFeedItem[]; nextCursor: string | null }>(
|
|
154
|
+
Api.Wallet,
|
|
155
|
+
'/social/global-feed',
|
|
156
|
+
params,
|
|
157
|
+
);
|
|
158
|
+
return { items: res.items || [], nextCursor: res.nextCursor ?? null };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function fetchSocialFeed(agentId: string, hubUrl?: string): Promise<InboundMessageItem[]> {
|
|
162
|
+
const params: Record<string, string | number> = { agentId, type: 'post_add', limit: 50 };
|
|
163
|
+
if (hubUrl) params.hubUrl = hubUrl;
|
|
164
|
+
|
|
165
|
+
const [feedRes, ownPosts] = await Promise.all([
|
|
166
|
+
api.get<{ messages: InboundMessageItem[] }>(
|
|
167
|
+
Api.Wallet,
|
|
168
|
+
'/social/feed',
|
|
169
|
+
params,
|
|
170
|
+
),
|
|
171
|
+
fetchSocialPosts(agentId, hubUrl),
|
|
172
|
+
]);
|
|
173
|
+
|
|
174
|
+
const byHash = new Map<string, InboundMessageItem>();
|
|
175
|
+
for (const message of feedRes.messages || []) {
|
|
176
|
+
byHash.set(message.hash, message);
|
|
177
|
+
}
|
|
178
|
+
for (const post of ownPosts) {
|
|
179
|
+
if (byHash.has(post.hash)) continue;
|
|
180
|
+
byHash.set(post.hash, {
|
|
181
|
+
id: post.id,
|
|
182
|
+
agentId: post.agentId,
|
|
183
|
+
hash: post.hash,
|
|
184
|
+
authorAuraId: 0,
|
|
185
|
+
type: post.type,
|
|
186
|
+
body: post.body,
|
|
187
|
+
timestamp: post.timestamp,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return Array.from(byHash.values()).sort((a, b) => b.timestamp - a.timestamp);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export async function fetchSocialPosts(agentId: string, hubUrl?: string): Promise<SocialMessageItem[]> {
|
|
195
|
+
const params: Record<string, string | number> = { agentId, type: 'post_add', limit: 200 };
|
|
196
|
+
if (hubUrl) params.hubUrl = hubUrl;
|
|
197
|
+
const removeParams: Record<string, string | number> = { agentId, type: 'post_remove', limit: 200 };
|
|
198
|
+
if (hubUrl) removeParams.hubUrl = hubUrl;
|
|
199
|
+
|
|
200
|
+
const [addsRes, removesRes] = await Promise.all([
|
|
201
|
+
api.get<{ messages: SocialMessageItem[] }>(Api.Wallet, '/social/messages', params),
|
|
202
|
+
api.get<{ messages: SocialMessageItem[] }>(Api.Wallet, '/social/messages', removeParams),
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
const posts = addsRes.messages || [];
|
|
206
|
+
const removals = removesRes.messages || [];
|
|
207
|
+
if (removals.length === 0) return posts;
|
|
208
|
+
|
|
209
|
+
const removedHashes = new Set<string>();
|
|
210
|
+
for (const removeMessage of removals) {
|
|
211
|
+
if (!shouldApplyPostRemove(removeMessage.syncStatus)) continue;
|
|
212
|
+
const targetHash = extractRemovedPostHash(removeMessage);
|
|
213
|
+
if (targetHash) removedHashes.add(targetHash);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (removedHashes.size === 0) return posts;
|
|
217
|
+
return posts.filter((post) => !removedHashes.has(post.hash));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export async function fetchSocialFollowers(agentId: string, hubUrl?: string): Promise<FollowerItem[]> {
|
|
221
|
+
const params: Record<string, string> = { agentId };
|
|
222
|
+
if (hubUrl) params.hubUrl = hubUrl;
|
|
223
|
+
const res = await api.get<{ followers: FollowerItem[] }>(Api.Wallet, '/social/followers', params);
|
|
224
|
+
return res.followers || [];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export async function fetchSocialFollowing(agentId: string, hubUrl?: string): Promise<FollowingItem[]> {
|
|
228
|
+
const params: Record<string, string> = { agentId };
|
|
229
|
+
if (hubUrl) params.hubUrl = hubUrl;
|
|
230
|
+
const res = await api.get<{ following: FollowingItem[] }>(Api.Wallet, '/social/following', params);
|
|
231
|
+
return res.following || [];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export async function fetchSocialStatus(agentId: string, hubUrl?: string): Promise<SyncStatus | null> {
|
|
235
|
+
const params: Record<string, string> = { agentId };
|
|
236
|
+
if (hubUrl) params.hubUrl = hubUrl;
|
|
237
|
+
const res = await api.get<{ status: SyncStatus | null }>(Api.Wallet, '/social/status', params);
|
|
238
|
+
return res.status || null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export async function fetchSocialProfile(agentId: string): Promise<AgentProfile> {
|
|
242
|
+
const res = await api.get<{ messages: ProfileMessageItem[] }>(
|
|
243
|
+
Api.Wallet,
|
|
244
|
+
'/social/messages',
|
|
245
|
+
{ agentId, type: 'user_data_add', limit: 200 },
|
|
246
|
+
);
|
|
247
|
+
return parseLatestProfile(res.messages || []);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function buildLocalPendingPost(agentId: string, text: string): SocialMessageItem {
|
|
251
|
+
const nowMs = Date.now();
|
|
252
|
+
const nowIso = new Date(nowMs).toISOString();
|
|
253
|
+
const localId = `local:${agentId}:${nowMs}:${Math.random().toString(16).slice(2, 8)}`;
|
|
254
|
+
return {
|
|
255
|
+
id: localId,
|
|
256
|
+
agentId,
|
|
257
|
+
hash: localId,
|
|
258
|
+
type: 'post_add',
|
|
259
|
+
body: JSON.stringify({ text }),
|
|
260
|
+
timestamp: Math.floor(nowMs / 1000),
|
|
261
|
+
syncStatus: 'pending',
|
|
262
|
+
createdAt: nowIso,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function submitPostLocalFirst(agentId: string, text: string, hubUrl?: string): {
|
|
267
|
+
localMessage: SocialMessageItem;
|
|
268
|
+
submit: Promise<SocialMessageItem>;
|
|
269
|
+
} {
|
|
270
|
+
const normalizedText = text.trim();
|
|
271
|
+
if (!normalizedText) {
|
|
272
|
+
throw new Error('text is required and must be a non-empty string');
|
|
273
|
+
}
|
|
274
|
+
const localMessage = buildLocalPendingPost(agentId, normalizedText);
|
|
275
|
+
const postBody: Record<string, string> = { agentId, text: normalizedText };
|
|
276
|
+
if (hubUrl) postBody.hubUrl = hubUrl;
|
|
277
|
+
|
|
278
|
+
const submit = api
|
|
279
|
+
.post<{ success: boolean; message: SocialMessageItem }>(Api.Wallet, '/social/post', postBody)
|
|
280
|
+
.then((res) => res.message);
|
|
281
|
+
|
|
282
|
+
return { localMessage, submit };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export async function removeSocialPost(agentId: string, targetPostHash: string, hubUrl?: string): Promise<void> {
|
|
286
|
+
const body: Record<string, string> = { agentId, targetPostHash };
|
|
287
|
+
if (hubUrl) body.hubUrl = hubUrl;
|
|
288
|
+
await api.post(Api.Wallet, '/social/post/remove', body);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export async function likeSocialPost(agentId: string, postHash: string, hubUrl?: string): Promise<void> {
|
|
292
|
+
const body: Record<string, string> = { agentId, postHash, reactionType: 'like' };
|
|
293
|
+
if (hubUrl) body.hubUrl = hubUrl;
|
|
294
|
+
await api.post(Api.Wallet, '/social/react', body);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ─── Hub management ──────────────────────────────────────────────────
|
|
298
|
+
|
|
299
|
+
export async function fetchPrimaryHubUrl(): Promise<string> {
|
|
300
|
+
const res = await api.get<{ hubUrl?: string }>(Api.Wallet, '/agent-hub/default');
|
|
301
|
+
const hubUrl = typeof res.hubUrl === 'string' ? res.hubUrl.trim() : '';
|
|
302
|
+
return hubUrl;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export async function fetchHubSubscriptions(agentId: string): Promise<HubSubscriptionInfo[]> {
|
|
306
|
+
const res = await api.get<{ hubs: HubSubscriptionInfo[] }>(Api.Wallet, `/agent-hub/${agentId}/hubs`);
|
|
307
|
+
return res.hubs || [];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export async function joinHub(agentId: string, hubUrl: string, label?: string): Promise<HubSubscriptionInfo> {
|
|
311
|
+
const body: Record<string, string> = { hubUrl };
|
|
312
|
+
if (label) body.label = label;
|
|
313
|
+
const res = await api.post<{ hub: HubSubscriptionInfo }>(Api.Wallet, `/agent-hub/${agentId}/join`, body);
|
|
314
|
+
return res.hub;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export async function leaveHub(agentId: string, hubUrl: string): Promise<void> {
|
|
318
|
+
await api.post(Api.Wallet, `/agent-hub/${agentId}/leave`, { hubUrl });
|
|
319
|
+
}
|
package/src/lib/view-registry.ts
CHANGED
|
@@ -22,14 +22,32 @@ export const DEFAULT_VIEWS: ViewDefinition[] = [
|
|
|
22
22
|
pinned: true,
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
id: '
|
|
26
|
-
label: '
|
|
27
|
-
icon: '
|
|
28
|
-
description: '
|
|
25
|
+
id: 'agents',
|
|
26
|
+
label: 'Verify',
|
|
27
|
+
icon: 'ShieldCheck',
|
|
28
|
+
description: 'Verified credentials and identity attestations',
|
|
29
29
|
pinned: true,
|
|
30
30
|
},
|
|
31
31
|
];
|
|
32
32
|
|
|
33
|
+
/** Social view — only shown when SOCIAL feature flag is enabled */
|
|
34
|
+
export const SOCIAL_VIEW: ViewDefinition = {
|
|
35
|
+
id: 'social',
|
|
36
|
+
label: 'Social',
|
|
37
|
+
icon: 'MessageCircle',
|
|
38
|
+
description: 'Social feed, posts, reactions, and follows',
|
|
39
|
+
pinned: true,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** Hub view — renders a hub's frontend in an iframe */
|
|
43
|
+
export const HUB_VIEW: ViewDefinition = {
|
|
44
|
+
id: 'hub',
|
|
45
|
+
label: 'Hub',
|
|
46
|
+
icon: 'Globe',
|
|
47
|
+
description: 'Browse hub frontends',
|
|
48
|
+
pinned: true,
|
|
49
|
+
};
|
|
50
|
+
|
|
33
51
|
/** Views that can be created from the + button */
|
|
34
52
|
export const CREATABLE_VIEWS: ViewDefinition[] = [
|
|
35
53
|
{
|
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
normalizeCredentialFieldsForType,
|
|
30
30
|
getCredentialFieldValue,
|
|
31
31
|
NOTE_CONTENT_KEY,
|
|
32
|
+
CREDENTIAL_FIELD_SCHEMA,
|
|
33
|
+
type CredentialType,
|
|
32
34
|
} from '../../../../shared/credential-field-schema';
|
|
33
35
|
import {
|
|
34
36
|
createSecretGist,
|
|
@@ -718,8 +720,7 @@ export function parseArgs(args: string[]): {
|
|
|
718
720
|
const flagTotp = parseableArgs.includes('--totp');
|
|
719
721
|
const flagOneTime = parseableArgs.includes('--one-time');
|
|
720
722
|
const flagDangerPlaintext = parseableArgs.includes('--danger-plaintext');
|
|
721
|
-
|
|
722
|
-
const fieldName = fieldIdx !== -1 ? parseableArgs[fieldIdx + 1] : undefined;
|
|
723
|
+
let fieldName: string | undefined;
|
|
723
724
|
const secretEnvIdx = parseableArgs.indexOf('--env');
|
|
724
725
|
const legacySecretEnvIdx = parseableArgs.indexOf('--name');
|
|
725
726
|
const secretEnvName = secretEnvIdx !== -1
|
|
@@ -752,7 +753,7 @@ export function parseArgs(args: string[]): {
|
|
|
752
753
|
: undefined;
|
|
753
754
|
|
|
754
755
|
const knownValueFlags = new Set([
|
|
755
|
-
'--
|
|
756
|
+
'--name', '--env', '--agent', '--expires-after', '--password', '--location', '--reqId', '--req-id', '--requestId', '--request-id', '--profile', '--profile-version', '--profile-overrides', '--type', '--tags',
|
|
756
757
|
]);
|
|
757
758
|
const knownBooleanFlags = new Set(['--json', '--first', '--totp', '--one-time', '--danger-plaintext']);
|
|
758
759
|
|
|
@@ -766,6 +767,21 @@ export function parseArgs(args: string[]): {
|
|
|
766
767
|
continue;
|
|
767
768
|
}
|
|
768
769
|
|
|
770
|
+
// Handle --field specially: supports --field key=value and --field key
|
|
771
|
+
if (arg === '--field') {
|
|
772
|
+
const nextArg = parseableArgs[i + 1];
|
|
773
|
+
if (nextArg && !nextArg.startsWith('--')) {
|
|
774
|
+
const eqIdx = nextArg.indexOf('=');
|
|
775
|
+
if (eqIdx > 0) {
|
|
776
|
+
extraFields.push({ key: nextArg.slice(0, eqIdx), value: nextArg.slice(eqIdx + 1) });
|
|
777
|
+
} else {
|
|
778
|
+
fieldName = fieldName || nextArg;
|
|
779
|
+
}
|
|
780
|
+
i++;
|
|
781
|
+
}
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
|
|
769
785
|
if (knownValueFlags.has(arg)) {
|
|
770
786
|
i++;
|
|
771
787
|
continue;
|
|
@@ -1050,6 +1066,14 @@ function resolveSetType(typeName: string | undefined): { requestType: string; no
|
|
|
1050
1066
|
return { requestType, normalizedType, defaultFieldKey };
|
|
1051
1067
|
}
|
|
1052
1068
|
|
|
1069
|
+
function resolveFieldSensitivity(credentialType: string, fieldKey: string): boolean {
|
|
1070
|
+
const schema = CREDENTIAL_FIELD_SCHEMA[credentialType as CredentialType];
|
|
1071
|
+
if (!schema) return false;
|
|
1072
|
+
const spec = schema.find((f) => f.key.toLowerCase() === fieldKey.toLowerCase()
|
|
1073
|
+
|| (f.aliases || []).some((a) => a.toLowerCase() === fieldKey.toLowerCase()));
|
|
1074
|
+
return spec ? spec.sensitive : false;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1053
1077
|
// ── Output formatting ──────────────────────────────────────────────────
|
|
1054
1078
|
|
|
1055
1079
|
export function formatCredential(
|
|
@@ -1456,7 +1480,7 @@ export async function runAgentCli(args: string[]): Promise<number> {
|
|
|
1456
1480
|
|
|
1457
1481
|
const setFields: Array<{ key: string; value: string; sensitive?: boolean }> = [
|
|
1458
1482
|
{ key: fieldKey, value, sensitive: true },
|
|
1459
|
-
...extraFields.map((f) => ({ key: f.key, value: f.value, sensitive:
|
|
1483
|
+
...extraFields.map((f) => ({ key: f.key, value: f.value, sensitive: resolveFieldSensitivity(resolvedType.requestType, f.key) })),
|
|
1460
1484
|
];
|
|
1461
1485
|
const nextMeta = tags ? { tags } : undefined;
|
|
1462
1486
|
|
|
@@ -1487,13 +1511,15 @@ export async function runAgentCli(args: string[]): Promise<number> {
|
|
|
1487
1511
|
retryCommandTemplate,
|
|
1488
1512
|
originalCommand,
|
|
1489
1513
|
});
|
|
1514
|
+
const effectiveType = decrypted.type || resolvedType.requestType;
|
|
1490
1515
|
const existing = [...decrypted.fields];
|
|
1491
1516
|
for (const next of setFields) {
|
|
1492
1517
|
const index = existing.findIndex((f) => f.key.toLowerCase() === next.key.toLowerCase());
|
|
1518
|
+
const sensitive = next.sensitive ?? resolveFieldSensitivity(effectiveType, next.key);
|
|
1493
1519
|
if (index >= 0) {
|
|
1494
|
-
existing[index] = { ...existing[index], key: next.key, value: next.value, sensitive
|
|
1520
|
+
existing[index] = { ...existing[index], key: next.key, value: next.value, sensitive };
|
|
1495
1521
|
} else {
|
|
1496
|
-
existing.push({ key: next.key, value: next.value, sensitive
|
|
1522
|
+
existing.push({ key: next.key, value: next.value, sensitive });
|
|
1497
1523
|
}
|
|
1498
1524
|
}
|
|
1499
1525
|
nextFields = existing;
|
|
@@ -1505,7 +1531,7 @@ export async function runAgentCli(args: string[]): Promise<number> {
|
|
|
1505
1531
|
}
|
|
1506
1532
|
|
|
1507
1533
|
const updated = await updateCredential(token, target.id, {
|
|
1508
|
-
sensitiveFields: nextFields.map((f) => ({ key: f.key, value: f.value, sensitive:
|
|
1534
|
+
sensitiveFields: nextFields.map((f) => ({ key: f.key, value: f.value, sensitive: f.sensitive ?? false })),
|
|
1509
1535
|
...(nextMeta ? { meta: nextMeta } : {}),
|
|
1510
1536
|
});
|
|
1511
1537
|
|