neoagent 2.4.1-beta.8 → 2.4.1
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/.env.example +33 -3
- package/LICENSE +111 -56
- package/README.md +8 -3
- package/docs/configuration.md +8 -0
- package/docs/getting-started.md +9 -3
- package/docs/index.md +4 -0
- package/extensions/chrome-browser/background.mjs +45 -7
- package/extensions/chrome-browser/icons/icon128.png +0 -0
- package/extensions/chrome-browser/icons/icon16.png +0 -0
- package/extensions/chrome-browser/icons/icon48.png +0 -0
- package/extensions/chrome-browser/icons/logo.svg +39 -8
- package/extensions/chrome-browser/manifest.json +3 -2
- package/extensions/chrome-browser/popup.html +5 -1
- package/extensions/chrome-browser/popup.js +15 -2
- package/flutter_app/android/app/src/main/AndroidManifest.xml +2 -1
- package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/flutter_app/assets/branding/app_icon_1024.png +0 -0
- package/flutter_app/assets/branding/app_icon_128.png +0 -0
- package/flutter_app/assets/branding/app_icon_192.png +0 -0
- package/flutter_app/assets/branding/app_icon_256.png +0 -0
- package/flutter_app/assets/branding/app_icon_32.png +0 -0
- package/flutter_app/assets/branding/app_icon_512.png +0 -0
- package/flutter_app/assets/branding/app_icon_64.png +0 -0
- package/flutter_app/assets/branding/app_icon_light_1024.png +0 -0
- package/flutter_app/assets/branding/app_icon_light_128.png +0 -0
- package/flutter_app/assets/branding/app_icon_light_192.png +0 -0
- package/flutter_app/assets/branding/app_icon_light_256.png +0 -0
- package/flutter_app/assets/branding/app_icon_light_32.png +0 -0
- package/flutter_app/assets/branding/app_icon_light_512.png +0 -0
- package/flutter_app/assets/branding/app_icon_light_64.png +0 -0
- package/flutter_app/assets/branding/onboarding_intro.mp4 +0 -0
- package/flutter_app/assets/branding/tray_icon_light_template.png +0 -0
- package/flutter_app/assets/branding/tray_icon_template.png +0 -0
- package/flutter_app/lib/features/location/location_service.dart +3 -0
- package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +391 -382
- package/flutter_app/lib/features/onboarding/onboarding_companion_step.dart +743 -0
- package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +18 -16
- package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +19 -18
- package/flutter_app/lib/features/onboarding/onboarding_shell.dart +8 -1
- package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +16 -13
- package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +17 -13
- package/flutter_app/lib/main.dart +3 -0
- package/flutter_app/lib/main_account_settings.dart +10 -34
- package/flutter_app/lib/main_admin.dart +14 -1
- package/flutter_app/lib/main_app_shell.dart +377 -340
- package/flutter_app/lib/main_chat.dart +707 -227
- package/flutter_app/lib/main_controller.dart +338 -46
- package/flutter_app/lib/main_devices.dart +851 -122
- package/flutter_app/lib/main_integrations.dart +255 -6
- package/flutter_app/lib/main_launcher.dart +1 -1
- package/flutter_app/lib/main_model_picker.dart +685 -0
- package/flutter_app/lib/main_models.dart +212 -0
- package/flutter_app/lib/main_navigation.dart +1 -9
- package/flutter_app/lib/main_operations.dart +1417 -614
- package/flutter_app/lib/main_settings.dart +764 -887
- package/flutter_app/lib/main_shared.dart +971 -443
- package/flutter_app/lib/main_spacing.dart +4 -4
- package/flutter_app/lib/main_theme.dart +22 -14
- package/flutter_app/lib/main_unified.dart +5 -72
- package/flutter_app/lib/src/android_apk_drop_zone.dart +24 -0
- package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +13 -0
- package/flutter_app/lib/src/android_apk_drop_zone_web.dart +219 -0
- package/flutter_app/lib/src/backend_client.dart +79 -0
- package/flutter_app/lib/src/desktop_companion_actions.dart +56 -7
- package/flutter_app/lib/src/desktop_companion_io.dart +77 -1
- package/flutter_app/lib/src/desktop_native_bridge.dart +13 -0
- package/flutter_app/lib/src/security/password_strength.dart +84 -0
- package/flutter_app/lib/src/stream_renderer.dart +205 -35
- package/flutter_app/lib/src/theme/palette.dart +76 -34
- package/flutter_app/linux/runner/resources/app_icon.png +0 -0
- package/flutter_app/macos/Runner/AppDelegate.swift +44 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
- package/flutter_app/pubspec.lock +2 -2
- package/flutter_app/pubspec.yaml +7 -1
- package/flutter_app/tool/branding_source/neoagent-icon-1024.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-128.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-16.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-180.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-192.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-256.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-32.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-48.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-512.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon-64.png +0 -0
- package/flutter_app/tool/branding_source/neoagent-icon.svg +43 -0
- package/flutter_app/tool/generate_desktop_branding.py +154 -152
- package/flutter_app/web/favicon.png +0 -0
- package/flutter_app/web/favicon.svg +40 -9
- package/flutter_app/web/favicon_light.svg +43 -0
- package/flutter_app/web/icons/Icon-192-light.png +0 -0
- package/flutter_app/web/icons/Icon-192.png +0 -0
- package/flutter_app/web/icons/Icon-512-light.png +0 -0
- package/flutter_app/web/icons/Icon-512.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-192-light.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-512-light.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
- package/flutter_app/windows/runner/main.cpp +7 -1
- package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
- package/lib/manager.js +445 -83
- package/package.json +17 -3
- package/runtime/paths.js +3 -1
- package/server/admin/access.js +198 -0
- package/server/admin/admin.css +268 -0
- package/server/admin/admin.js +348 -0
- package/server/admin/analytics.js +128 -0
- package/server/admin/index.html +1015 -0
- package/server/admin/login.html +290 -0
- package/server/admin/logo.svg +43 -0
- package/server/admin/sql.js +134 -0
- package/server/admin/users.js +147 -0
- package/server/config/origins.js +3 -1
- package/server/db/database.js +92 -0
- package/server/db/ftsQuery.js +27 -0
- package/server/http/routes.js +1 -0
- package/server/http/static.js +23 -6
- package/server/index.js +1 -1
- package/server/middleware/adminAuth.js +48 -0
- package/server/middleware/auth.js +1 -40
- package/server/public/.last_build_id +1 -1
- package/server/public/app_icon.png +0 -0
- package/server/public/assets/AssetManifest.bin +1 -1
- package/server/public/assets/AssetManifest.bin.json +1 -1
- package/server/public/assets/assets/branding/app_icon_1024.png +0 -0
- package/server/public/assets/assets/branding/app_icon_256.png +0 -0
- package/server/public/assets/assets/branding/app_icon_512.png +0 -0
- package/server/public/assets/assets/branding/app_icon_light_1024.png +0 -0
- package/server/public/assets/assets/branding/app_icon_light_256.png +0 -0
- package/server/public/assets/assets/branding/app_icon_light_512.png +0 -0
- package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
- package/server/public/assets/assets/branding/tray_icon_light_template.png +0 -0
- package/server/public/assets/assets/branding/tray_icon_template.png +0 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/assets/web/icons/Icon-192.png +0 -0
- package/server/public/favicon.png +0 -0
- package/server/public/favicon.svg +40 -9
- package/server/public/favicon_light.svg +43 -0
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/icons/Icon-192-light.png +0 -0
- package/server/public/icons/Icon-192.png +0 -0
- package/server/public/icons/Icon-512-light.png +0 -0
- package/server/public/icons/Icon-512.png +0 -0
- package/server/public/icons/Icon-maskable-192-light.png +0 -0
- package/server/public/icons/Icon-maskable-192.png +0 -0
- package/server/public/icons/Icon-maskable-512-light.png +0 -0
- package/server/public/icons/Icon-maskable-512.png +0 -0
- package/server/public/main.dart.js +88944 -85720
- package/server/routes/admin.js +632 -0
- package/server/routes/agent_profiles.js +3 -0
- package/server/routes/agents.js +1 -1
- package/server/routes/auth.js +3 -1
- package/server/routes/browser.js +14 -0
- package/server/routes/browser_extension.js +21 -4
- package/server/routes/desktop.js +10 -0
- package/server/routes/mcp.js +29 -13
- package/server/routes/memory.js +23 -1
- package/server/routes/messaging.js +2 -0
- package/server/routes/screenHistory.js +14 -8
- package/server/routes/settings.js +14 -2
- package/server/routes/stream.js +12 -3
- package/server/routes/triggers.js +4 -4
- package/server/routes/voice_assistant.js +36 -1
- package/server/routes/workspace.js +86 -0
- package/server/services/account/admin_two_factor.js +132 -0
- package/server/services/account/password_policy.js +6 -1
- package/server/services/ai/completion.js +44 -0
- package/server/services/ai/engine.js +321 -500
- package/server/services/ai/imageAnalysis.js +9 -5
- package/server/services/ai/logFormat.js +46 -0
- package/server/services/ai/loopPolicy.js +11 -0
- package/server/services/ai/messagingFallback.js +228 -0
- package/server/services/ai/models.js +194 -55
- package/server/services/ai/providerRetry.js +169 -0
- package/server/services/ai/providers/anthropic.js +15 -4
- package/server/services/ai/providers/google.js +38 -11
- package/server/services/ai/providers/grok.js +19 -68
- package/server/services/ai/providers/grokOauth.js +141 -0
- package/server/services/ai/providers/nvidia.js +154 -0
- package/server/services/ai/providers/ollama.js +76 -39
- package/server/services/ai/providers/openai.js +20 -31
- package/server/services/ai/providers/openaiCodex.js +6 -2
- package/server/services/ai/providers/openaiCompatible.js +70 -0
- package/server/services/ai/providers/openrouter.js +162 -0
- package/server/services/ai/settings.js +30 -0
- package/server/services/ai/systemPrompt.js +51 -29
- package/server/services/ai/taskAnalysis.js +60 -1
- package/server/services/ai/toolEvidence.js +207 -0
- package/server/services/ai/toolSelector.js +8 -1
- package/server/services/ai/tools.js +80 -15
- package/server/services/android/controller.js +36 -1
- package/server/services/browser/controller.js +18 -0
- package/server/services/browser/extension/manifest.js +33 -0
- package/server/services/browser/extension/provider.js +12 -6
- package/server/services/browser/extension/registry.js +229 -18
- package/server/services/desktop/protocol.js +1 -0
- package/server/services/desktop/provider.js +4 -0
- package/server/services/desktop/registry.js +104 -1
- package/server/services/desktop/screenRecorder.js +208 -98
- package/server/services/desktop/screen_recorder_support.js +46 -0
- package/server/services/integrations/google/provider.js +13 -0
- package/server/services/integrations/home_assistant/constants.js +88 -0
- package/server/services/integrations/home_assistant/network.js +207 -0
- package/server/services/integrations/home_assistant/provider.js +249 -0
- package/server/services/integrations/home_assistant/snapshot.js +98 -0
- package/server/services/integrations/home_assistant/tools.js +101 -0
- package/server/services/integrations/manager.js +5 -0
- package/server/services/integrations/registry.js +2 -0
- package/server/services/integrations/trello/provider.js +8 -2
- package/server/services/manager.js +51 -47
- package/server/services/mcp/client.js +208 -268
- package/server/services/mcp/client_support.js +172 -0
- package/server/services/mcp/recovery.js +116 -0
- package/server/services/mcp/tool_operations.js +123 -0
- package/server/services/memory/ingestion.js +185 -370
- package/server/services/memory/ingestion_coverage.js +129 -0
- package/server/services/memory/ingestion_documents.js +123 -0
- package/server/services/memory/ingestion_support.js +171 -0
- package/server/services/memory/intelligence.js +181 -0
- package/server/services/memory/manager.js +476 -32
- package/server/services/messaging/automation.js +71 -134
- package/server/services/messaging/formatting_guides.js +26 -1
- package/server/services/messaging/inbound_queue.js +111 -0
- package/server/services/messaging/manager.js +25 -8
- package/server/services/messaging/typing_keepalive.js +110 -0
- package/server/services/runtime/manager.js +7 -3
- package/server/services/runtime/settings.js +17 -0
- package/server/services/streaming/android-stream.js +296 -32
- package/server/services/streaming/stream-hub.js +1 -1
- package/server/services/tasks/integration_runtime.js +4 -1
- package/server/services/tasks/runtime.js +415 -56
- package/server/services/tasks/task_repository.js +48 -6
- package/server/services/websocket.js +8 -2
- package/server/services/widgets/service.js +17 -1
- package/server/services/workspace/manager.js +116 -0
- package/server/utils/logger.js +44 -6
- package/server/utils/security.js +3 -0
- package/server/utils/version.js +29 -19
- package/server/services/memory/openhuman_uplift.test.js +0 -98
package/server/db/database.js
CHANGED
|
@@ -581,6 +581,9 @@ db.exec(`
|
|
|
581
581
|
metadata_json TEXT DEFAULT '{}',
|
|
582
582
|
content TEXT NOT NULL,
|
|
583
583
|
importance INTEGER DEFAULT 5,
|
|
584
|
+
confidence REAL DEFAULT 0.7,
|
|
585
|
+
summary TEXT,
|
|
586
|
+
memory_hash TEXT,
|
|
584
587
|
embedding TEXT,
|
|
585
588
|
access_count INTEGER DEFAULT 0,
|
|
586
589
|
archived INTEGER DEFAULT 0,
|
|
@@ -686,6 +689,62 @@ db.exec(`
|
|
|
686
689
|
CREATE INDEX IF NOT EXISTS idx_memory_ingestion_documents_provider ON memory_ingestion_documents(user_id, agent_id, provider_key, connection_id, updated_at DESC);
|
|
687
690
|
CREATE INDEX IF NOT EXISTS idx_materialized_knowledge_views_user ON materialized_knowledge_views(user_id, agent_id, view_type, updated_at DESC);
|
|
688
691
|
|
|
692
|
+
CREATE TABLE IF NOT EXISTS memory_facts (
|
|
693
|
+
id TEXT PRIMARY KEY,
|
|
694
|
+
memory_id TEXT NOT NULL,
|
|
695
|
+
user_id INTEGER NOT NULL,
|
|
696
|
+
agent_id TEXT,
|
|
697
|
+
subject TEXT NOT NULL,
|
|
698
|
+
predicate TEXT NOT NULL,
|
|
699
|
+
object TEXT NOT NULL,
|
|
700
|
+
category TEXT DEFAULT 'episodic',
|
|
701
|
+
confidence REAL DEFAULT 0.7,
|
|
702
|
+
event_time TEXT,
|
|
703
|
+
metadata_json TEXT DEFAULT '{}',
|
|
704
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
705
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
706
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
707
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
708
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
CREATE TABLE IF NOT EXISTS memory_entities (
|
|
712
|
+
id TEXT PRIMARY KEY,
|
|
713
|
+
user_id INTEGER NOT NULL,
|
|
714
|
+
agent_id TEXT,
|
|
715
|
+
entity_key TEXT NOT NULL,
|
|
716
|
+
name TEXT NOT NULL,
|
|
717
|
+
kind TEXT DEFAULT 'concept',
|
|
718
|
+
aliases_json TEXT DEFAULT '[]',
|
|
719
|
+
summary TEXT DEFAULT '',
|
|
720
|
+
mention_count INTEGER DEFAULT 0,
|
|
721
|
+
first_seen_at TEXT DEFAULT (datetime('now')),
|
|
722
|
+
last_seen_at TEXT DEFAULT (datetime('now')),
|
|
723
|
+
metadata_json TEXT DEFAULT '{}',
|
|
724
|
+
UNIQUE(user_id, agent_id, entity_key),
|
|
725
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
726
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
CREATE TABLE IF NOT EXISTS memory_entity_mentions (
|
|
730
|
+
entity_id TEXT NOT NULL,
|
|
731
|
+
memory_id TEXT NOT NULL,
|
|
732
|
+
user_id INTEGER NOT NULL,
|
|
733
|
+
agent_id TEXT,
|
|
734
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
735
|
+
PRIMARY KEY (entity_id, memory_id),
|
|
736
|
+
FOREIGN KEY (entity_id) REFERENCES memory_entities(id) ON DELETE CASCADE,
|
|
737
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
738
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
739
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
CREATE INDEX IF NOT EXISTS idx_memory_facts_memory ON memory_facts(memory_id);
|
|
743
|
+
CREATE INDEX IF NOT EXISTS idx_memory_facts_user ON memory_facts(user_id, agent_id, category, updated_at DESC);
|
|
744
|
+
CREATE INDEX IF NOT EXISTS idx_memory_entities_user ON memory_entities(user_id, agent_id, mention_count DESC, last_seen_at DESC);
|
|
745
|
+
CREATE INDEX IF NOT EXISTS idx_memory_entity_mentions_memory ON memory_entity_mentions(memory_id);
|
|
746
|
+
CREATE INDEX IF NOT EXISTS idx_memory_entity_mentions_entity ON memory_entity_mentions(entity_id);
|
|
747
|
+
|
|
689
748
|
CREATE TABLE IF NOT EXISTS agent_run_events (
|
|
690
749
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
691
750
|
run_id TEXT NOT NULL,
|
|
@@ -984,6 +1043,16 @@ try {
|
|
|
984
1043
|
INSERT INTO messages_fts(rowid, content, role, user_id, agent_id, run_id, platform, platform_chat_id)
|
|
985
1044
|
VALUES (new.id, COALESCE(new.content, ''), new.role, new.user_id, COALESCE(new.agent_id, ''), COALESCE(new.run_id, ''), COALESCE(new.platform, ''), COALESCE(new.platform_chat_id, ''));
|
|
986
1045
|
END;
|
|
1046
|
+
|
|
1047
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
1048
|
+
memory_id UNINDEXED,
|
|
1049
|
+
user_id UNINDEXED,
|
|
1050
|
+
agent_id UNINDEXED,
|
|
1051
|
+
content,
|
|
1052
|
+
category,
|
|
1053
|
+
entities,
|
|
1054
|
+
tokenize = 'porter unicode61'
|
|
1055
|
+
);
|
|
987
1056
|
`);
|
|
988
1057
|
} catch {
|
|
989
1058
|
// FTS5 is optional. The app still works with LIKE-based fallbacks if unavailable.
|
|
@@ -1005,6 +1074,25 @@ try {
|
|
|
1005
1074
|
// Ignore cleanup failures for obsolete wearable tables.
|
|
1006
1075
|
}
|
|
1007
1076
|
|
|
1077
|
+
// Admin 2FA tables (singleton — no foreign key, no user_id)
|
|
1078
|
+
db.exec(`
|
|
1079
|
+
CREATE TABLE IF NOT EXISTS admin_two_factor (
|
|
1080
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
1081
|
+
enabled INTEGER NOT NULL DEFAULT 0,
|
|
1082
|
+
secret TEXT,
|
|
1083
|
+
pending_secret TEXT,
|
|
1084
|
+
enabled_at TEXT,
|
|
1085
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1086
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1087
|
+
);
|
|
1088
|
+
CREATE TABLE IF NOT EXISTS admin_recovery_codes (
|
|
1089
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1090
|
+
code_hash TEXT NOT NULL,
|
|
1091
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1092
|
+
used_at TEXT
|
|
1093
|
+
);
|
|
1094
|
+
`);
|
|
1095
|
+
|
|
1008
1096
|
// Migrations for existing databases
|
|
1009
1097
|
for (const col of [
|
|
1010
1098
|
"ALTER TABLE agent_runs ADD COLUMN agent_id TEXT",
|
|
@@ -1035,6 +1123,9 @@ for (const col of [
|
|
|
1035
1123
|
"ALTER TABLE memories ADD COLUMN source_label TEXT",
|
|
1036
1124
|
"ALTER TABLE memories ADD COLUMN stale_after_days INTEGER",
|
|
1037
1125
|
"ALTER TABLE memories ADD COLUMN metadata_json TEXT DEFAULT '{}'",
|
|
1126
|
+
"ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7",
|
|
1127
|
+
"ALTER TABLE memories ADD COLUMN summary TEXT",
|
|
1128
|
+
"ALTER TABLE memories ADD COLUMN memory_hash TEXT",
|
|
1038
1129
|
"ALTER TABLE scheduled_tasks ADD COLUMN run_at TEXT",
|
|
1039
1130
|
"ALTER TABLE scheduled_tasks ADD COLUMN one_time INTEGER DEFAULT 0",
|
|
1040
1131
|
"ALTER TABLE scheduled_tasks ADD COLUMN execution_mode TEXT DEFAULT 'prompt'",
|
|
@@ -1094,6 +1185,7 @@ function createAgentScopedIndexes() {
|
|
|
1094
1185
|
['conversation_history', 'CREATE INDEX IF NOT EXISTS idx_conv_history_agent ON conversation_history(user_id, agent_id, created_at DESC)'],
|
|
1095
1186
|
['memories', 'CREATE INDEX IF NOT EXISTS idx_memories_agent ON memories(user_id, agent_id, archived, updated_at DESC)'],
|
|
1096
1187
|
['memories', 'CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(user_id, agent_id, scope_type, scope_id, archived, updated_at DESC)'],
|
|
1188
|
+
['memories', 'CREATE INDEX IF NOT EXISTS idx_memories_hash ON memories(user_id, agent_id, memory_hash, archived)'],
|
|
1097
1189
|
['core_memory', 'CREATE INDEX IF NOT EXISTS idx_core_memory_agent ON core_memory(user_id, agent_id, key)'],
|
|
1098
1190
|
['ai_widgets', 'CREATE UNIQUE INDEX IF NOT EXISTS idx_ai_widgets_system_key ON ai_widgets(user_id, agent_id, system_key) WHERE system_key IS NOT NULL'],
|
|
1099
1191
|
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Shared builder for SQLite FTS5 MATCH expressions. Any code path that feeds a
|
|
4
|
+
// user-supplied string into a `... MATCH ?` query must route it through here:
|
|
5
|
+
// raw input regularly contains characters that are special in FTS5's query
|
|
6
|
+
// grammar and would otherwise throw at query time.
|
|
7
|
+
//
|
|
8
|
+
// Two pitfalls are handled:
|
|
9
|
+
// 1. Hyphens — inside a MATCH a `-` is the NOT/column operator, so a bareword
|
|
10
|
+
// like `covid-19*` parses as `covid AND NOT column "19"` and throws
|
|
11
|
+
// "no such column: 19". The token regex excludes `-`, splitting on it.
|
|
12
|
+
// 2. Bareword operators — an uppercase token such as AND/OR/NOT/NEAR is parsed
|
|
13
|
+
// as an operator ("syntax error near AND"). FTS5's tokenizer is
|
|
14
|
+
// case-insensitive, so lowercasing each token neutralizes the collision
|
|
15
|
+
// while preserving matches.
|
|
16
|
+
//
|
|
17
|
+
// Returns a prefix-matched AND query (e.g. `covid* AND 19*`), or null when the
|
|
18
|
+
// input yields no usable tokens — callers should treat null as "no FTS filter".
|
|
19
|
+
|
|
20
|
+
function buildFtsQuery(query) {
|
|
21
|
+
const tokens = String(query || '')
|
|
22
|
+
.match(/[\p{L}\p{N}_]{2,}/gu) || [];
|
|
23
|
+
if (!tokens.length) return null;
|
|
24
|
+
return tokens.map((token) => `${token.toLowerCase().replace(/"/g, '')}*`).join(' AND ');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { buildFtsQuery };
|
package/server/http/routes.js
CHANGED
|
@@ -18,6 +18,7 @@ const routeRegistry = [
|
|
|
18
18
|
{ basePath: '/api/skills', modulePath: '../routes/skills' },
|
|
19
19
|
{ basePath: '/api/store', modulePath: '../routes/store' },
|
|
20
20
|
{ basePath: '/api/artifacts', modulePath: '../routes/artifacts' },
|
|
21
|
+
{ basePath: '/api/workspace', modulePath: '../routes/workspace' },
|
|
21
22
|
{ basePath: '/api/memory', modulePath: '../routes/memory' },
|
|
22
23
|
{ basePath: '/api/tasks', modulePath: '../routes/tasks' },
|
|
23
24
|
{ basePath: '/api/widgets', modulePath: '../routes/widgets' },
|
package/server/http/static.js
CHANGED
|
@@ -7,6 +7,7 @@ const { DATA_DIR } = require('../../runtime/paths');
|
|
|
7
7
|
const { requireAuth } = require('../middleware/auth');
|
|
8
8
|
|
|
9
9
|
const FLUTTER_WEB_DIR = path.join(__dirname, '..', 'public');
|
|
10
|
+
const LANDING_DIR = path.join(__dirname, '..', '..', 'landing');
|
|
10
11
|
const BUILD_ID_PATH = path.join(FLUTTER_WEB_DIR, '.last_build_id');
|
|
11
12
|
|
|
12
13
|
function setNoStoreHeaders(res) {
|
|
@@ -63,11 +64,23 @@ function registerStaticRoutes(app) {
|
|
|
63
64
|
});
|
|
64
65
|
});
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
app.
|
|
67
|
+
const adminRouter = require('../routes/admin');
|
|
68
|
+
app.use('/admin', adminRouter);
|
|
69
|
+
|
|
70
|
+
// Flutter app at /app
|
|
71
|
+
app.use(
|
|
72
|
+
'/app',
|
|
73
|
+
express.static(FLUTTER_WEB_DIR, {
|
|
74
|
+
index: false,
|
|
75
|
+
setHeaders: setFlutterStaticHeaders,
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
app.get(/^\/app(\/.*)?$/, serveFlutterApp);
|
|
79
|
+
|
|
80
|
+
// Landing page at /
|
|
81
|
+
app.use(express.static(LANDING_DIR));
|
|
82
|
+
app.get('/', (req, res) => res.sendFile(path.join(LANDING_DIR, 'index.html')));
|
|
83
|
+
app.get('/legal.html', (req, res) => res.sendFile(path.join(LANDING_DIR, 'legal.html')));
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
function serveFlutterApp(req, res) {
|
|
@@ -80,11 +93,15 @@ function serveFlutterApp(req, res) {
|
|
|
80
93
|
);
|
|
81
94
|
}
|
|
82
95
|
setNoStoreHeaders(res);
|
|
83
|
-
|
|
96
|
+
// Rewrite <base href="/"> to <base href="/app/"> so Flutter asset paths resolve correctly
|
|
97
|
+
const html = fs.readFileSync(entry, 'utf8').replace('<base href="/">', '<base href="/app/">');
|
|
98
|
+
res.set('Content-Type', 'text/html');
|
|
99
|
+
return res.send(html);
|
|
84
100
|
}
|
|
85
101
|
|
|
86
102
|
module.exports = {
|
|
87
103
|
FLUTTER_WEB_DIR,
|
|
104
|
+
LANDING_DIR,
|
|
88
105
|
registerStaticRoutes,
|
|
89
106
|
serveFlutterApp
|
|
90
107
|
};
|
package/server/index.js
CHANGED
|
@@ -103,7 +103,7 @@ const sessionMiddleware = createSessionMiddleware({
|
|
|
103
103
|
});
|
|
104
104
|
const activeSockets = new Set();
|
|
105
105
|
|
|
106
|
-
setupConsoleInterceptor(io);
|
|
106
|
+
app.locals.logHistory = setupConsoleInterceptor(io);
|
|
107
107
|
applyHttpMiddleware(app, {
|
|
108
108
|
secureCookies: SECURE_COOKIES,
|
|
109
109
|
trustProxy: TRUST_PROXY,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Constant-time string comparison — prevents timing attacks on API key checks.
|
|
7
|
+
*/
|
|
8
|
+
function safeEqual(a, b) {
|
|
9
|
+
if (!a || !b) return false;
|
|
10
|
+
const bufA = Buffer.from(String(a));
|
|
11
|
+
const bufB = Buffer.from(String(b));
|
|
12
|
+
if (bufA.length !== bufB.length) {
|
|
13
|
+
// Lengths differ — do a dummy compare anyway to keep timing consistent
|
|
14
|
+
crypto.timingSafeEqual(bufA, Buffer.alloc(bufA.length));
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return crypto.timingSafeEqual(bufA, bufB);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Allows admin access via either:
|
|
22
|
+
* 1. Browser session (`req.session.isAdmin === true`)
|
|
23
|
+
* 2. API key (`Authorization: Bearer <ADMIN_API_KEY>`)
|
|
24
|
+
*
|
|
25
|
+
* When ADMIN_API_KEY is absent or empty, Bearer auth is disabled entirely.
|
|
26
|
+
*/
|
|
27
|
+
function requireAdminAuth(req, res, next) {
|
|
28
|
+
// 1. Session-based auth (admin web dashboard)
|
|
29
|
+
if (req.session?.isAdmin === true) return next();
|
|
30
|
+
|
|
31
|
+
// 2. API key auth (programmatic / scripts)
|
|
32
|
+
const configuredKey = process.env.ADMIN_API_KEY;
|
|
33
|
+
if (configuredKey) {
|
|
34
|
+
const authHeader = String(req.headers.authorization || '');
|
|
35
|
+
if (authHeader.startsWith('Bearer ')) {
|
|
36
|
+
const provided = authHeader.slice(7).trim();
|
|
37
|
+
if (safeEqual(provided, configuredKey)) return next();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 3. Reject
|
|
42
|
+
if (req.path.startsWith('/api/')) {
|
|
43
|
+
return res.status(401).json({ error: 'Admin authentication required' });
|
|
44
|
+
}
|
|
45
|
+
return res.redirect('/admin/login');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { requireAdminAuth };
|
|
@@ -18,43 +18,4 @@ function requireNoAuth(req, res, next) {
|
|
|
18
18
|
next();
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
if (req.session && req.session.userId) {
|
|
23
|
-
const db = require('../db/database');
|
|
24
|
-
const now = Date.now();
|
|
25
|
-
const cacheMaxAgeMs = 5 * 60 * 1000;
|
|
26
|
-
const cachedUser = req.session._cachedUser;
|
|
27
|
-
const cachedAt = Number(req.session._cachedUserAt || 0);
|
|
28
|
-
const cacheFresh = (
|
|
29
|
-
cachedUser
|
|
30
|
-
&& Number(cachedUser.id) === Number(req.session.userId)
|
|
31
|
-
&& cachedAt > 0
|
|
32
|
-
&& (now - cachedAt) < cacheMaxAgeMs
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
if (cacheFresh) {
|
|
36
|
-
req.user = { ...cachedUser };
|
|
37
|
-
return next();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const user = db.prepare('SELECT id, username, email, created_at FROM users WHERE id = ?').get(req.session.userId);
|
|
41
|
-
if (user) {
|
|
42
|
-
req.user = { ...user };
|
|
43
|
-
req.session._cachedUser = { ...user };
|
|
44
|
-
req.session._cachedUserAt = now;
|
|
45
|
-
console.log(`[Auth] Attached user ${user.id} (${user.username}) to ${req.method} ${req.originalUrl || req.url}`);
|
|
46
|
-
return next();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
console.warn(`[Auth] Session user ${req.session.userId} not found for ${req.method} ${req.originalUrl || req.url}; destroying session`);
|
|
50
|
-
req.session.destroy(() => {});
|
|
51
|
-
const requestPath = req.originalUrl || req.url || req.path || '';
|
|
52
|
-
if (requestPath.startsWith('/api/')) {
|
|
53
|
-
return res.status(401).json({ error: 'Session invalid' });
|
|
54
|
-
}
|
|
55
|
-
return res.redirect('/login');
|
|
56
|
-
}
|
|
57
|
-
next();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
module.exports = { requireAuth, requireNoAuth, attachUser };
|
|
21
|
+
module.exports = { requireAuth, requireNoAuth };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
dcad55b6198b066ebc14a3b7bb789972
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"
|
|
1
|
+
"DQ4HIWFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8xMDI0LnBuZwwBDQEHBWFzc2V0ByFhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fMTAyNC5wbmcHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nDAENAQcFYXNzZXQHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwwBDQEHBWFzc2V0ByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwcnYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzEwMjQucG5nDAENAQcFYXNzZXQHJ2Fzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF8xMDI0LnBuZwcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcMAQ0BBwVhc3NldAcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nDAENAQcFYXNzZXQHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nByRhc3NldHMvYnJhbmRpbmcvb25ib2FyZGluZ19pbnRyby5tcDQMAQ0BBwVhc3NldAckYXNzZXRzL2JyYW5kaW5nL29uYm9hcmRpbmdfaW50cm8ubXA0Byxhc3NldHMvYnJhbmRpbmcvdHJheV9pY29uX2xpZ2h0X3RlbXBsYXRlLnBuZwwBDQEHBWFzc2V0Byxhc3NldHMvYnJhbmRpbmcvdHJheV9pY29uX2xpZ2h0X3RlbXBsYXRlLnBuZwcmYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl90ZW1wbGF0ZS5wbmcMAQ0BBwVhc3NldAcmYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl90ZW1wbGF0ZS5wbmcHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmDAENAQcFYXNzZXQHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmByxwYWNrYWdlcy9taXhwYW5lbF9mbHV0dGVyL2Fzc2V0cy9taXhwYW5lbC5qcwwBDQEHBWFzc2V0ByxwYWNrYWdlcy9taXhwYW5lbF9mbHV0dGVyL2Fzc2V0cy9taXhwYW5lbC5qcwc3cGFja2FnZXMvcmVjb3JkX3dlYi9hc3NldHMvanMvcmVjb3JkLmZpeHdlYm1kdXJhdGlvbi5qcwwBDQEHBWFzc2V0BzdwYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQuZml4d2VibWR1cmF0aW9uLmpzBy9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwwBDQEHBWFzc2V0By9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwcWd2ViL2ljb25zL0ljb24tMTkyLnBuZwwBDQEHBWFzc2V0BxZ3ZWIvaWNvbnMvSWNvbi0xOTIucG5n"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,12 +1,43 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100">
|
|
2
2
|
<defs>
|
|
3
|
-
<linearGradient id="
|
|
4
|
-
<stop offset="0%" stop-color="#
|
|
5
|
-
<stop offset="100%" stop-color="#
|
|
3
|
+
<linearGradient id="tile" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#705331"></stop>
|
|
5
|
+
<stop offset="100%" stop-color="#22564c"></stop>
|
|
6
6
|
</linearGradient>
|
|
7
|
+
<radialGradient id="shine" cx="26%" cy="14%" r="72%">
|
|
8
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.22"></stop>
|
|
9
|
+
<stop offset="100%" stop-color="#ffffff" stop-opacity="0"></stop>
|
|
10
|
+
</radialGradient>
|
|
11
|
+
<radialGradient id="core" cx="38%" cy="32%" r="75%">
|
|
12
|
+
<stop offset="0%" stop-color="#fffdf6"></stop>
|
|
13
|
+
<stop offset="48%" stop-color="#eee3cc"></stop>
|
|
14
|
+
<stop offset="100%" stop-color="#b5a888"></stop>
|
|
15
|
+
</radialGradient>
|
|
16
|
+
<radialGradient id="node" cx="36%" cy="30%" r="80%">
|
|
17
|
+
<stop offset="0%" stop-color="#f8dca8"></stop>
|
|
18
|
+
<stop offset="52%" stop-color="#d3a85f"></stop>
|
|
19
|
+
<stop offset="100%" stop-color="#9b6f2f"></stop>
|
|
20
|
+
</radialGradient>
|
|
21
|
+
<linearGradient id="tube" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
22
|
+
<stop offset="0%" stop-color="#fffaf0"></stop>
|
|
23
|
+
<stop offset="52%" stop-color="#efe7d6"></stop>
|
|
24
|
+
<stop offset="100%" stop-color="#cabf9f"></stop>
|
|
25
|
+
</linearGradient>
|
|
26
|
+
<filter id="sh" x="-30%" y="-30%" width="160%" height="160%">
|
|
27
|
+
<feDropShadow dx="0" dy="1.1" stdDeviation="1.1" flood-color="#000000" flood-opacity="0.45"></feDropShadow>
|
|
28
|
+
</filter>
|
|
29
|
+
<clipPath id="tc"><rect x="0" y="0" width="100" height="100" rx="22.5"></rect></clipPath>
|
|
7
30
|
</defs>
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
31
|
+
<g clip-path="url(#tc)">
|
|
32
|
+
<rect x="0" y="0" width="100" height="100" fill="url(#tile)"></rect>
|
|
33
|
+
<rect x="0" y="0" width="100" height="100" fill="url(#shine)"></rect>
|
|
34
|
+
<g fill="none" stroke="url(#tube)" stroke-linecap="round" filter="url(#sh)">
|
|
35
|
+
<circle cx="50" cy="50" r="17" stroke-width="5" stroke-dasharray="78 29" transform="rotate(-35 50 50)" stroke-opacity="0.92"></circle>
|
|
36
|
+
<circle cx="50" cy="50" r="30" stroke-width="5" stroke-dasharray="150 39" transform="rotate(70 50 50)" stroke-opacity="0.8"></circle>
|
|
37
|
+
</g>
|
|
38
|
+
<circle cx="50" cy="50" r="7" fill="url(#core)"></circle>
|
|
39
|
+
<circle cx="50" cy="20" r="5.6" fill="url(#node)"></circle>
|
|
40
|
+
<circle cx="48" cy="18.4" r="1.7" fill="#fff7e6" fill-opacity="0.8"></circle>
|
|
41
|
+
</g>
|
|
42
|
+
<rect x="0.6" y="0.6" width="98.8" height="98.8" rx="22" fill="none" stroke="#ffffff" stroke-opacity="0.16" stroke-width="1.2"></rect>
|
|
43
|
+
</svg>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="tile" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#705331"></stop>
|
|
5
|
+
<stop offset="100%" stop-color="#22564c"></stop>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<radialGradient id="shine" cx="26%" cy="14%" r="72%">
|
|
8
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.22"></stop>
|
|
9
|
+
<stop offset="100%" stop-color="#ffffff" stop-opacity="0"></stop>
|
|
10
|
+
</radialGradient>
|
|
11
|
+
<radialGradient id="core" cx="38%" cy="32%" r="75%">
|
|
12
|
+
<stop offset="0%" stop-color="#fffdf6"></stop>
|
|
13
|
+
<stop offset="48%" stop-color="#eee3cc"></stop>
|
|
14
|
+
<stop offset="100%" stop-color="#b5a888"></stop>
|
|
15
|
+
</radialGradient>
|
|
16
|
+
<radialGradient id="node" cx="36%" cy="30%" r="80%">
|
|
17
|
+
<stop offset="0%" stop-color="#f8dca8"></stop>
|
|
18
|
+
<stop offset="52%" stop-color="#d3a85f"></stop>
|
|
19
|
+
<stop offset="100%" stop-color="#9b6f2f"></stop>
|
|
20
|
+
</radialGradient>
|
|
21
|
+
<linearGradient id="tube" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
22
|
+
<stop offset="0%" stop-color="#fffaf0"></stop>
|
|
23
|
+
<stop offset="52%" stop-color="#efe7d6"></stop>
|
|
24
|
+
<stop offset="100%" stop-color="#cabf9f"></stop>
|
|
25
|
+
</linearGradient>
|
|
26
|
+
<filter id="sh" x="-30%" y="-30%" width="160%" height="160%">
|
|
27
|
+
<feDropShadow dx="0" dy="1.1" stdDeviation="1.1" flood-color="#000000" flood-opacity="0.45"></feDropShadow>
|
|
28
|
+
</filter>
|
|
29
|
+
<clipPath id="tc"><rect x="0" y="0" width="100" height="100" rx="22.5"></rect></clipPath>
|
|
30
|
+
</defs>
|
|
31
|
+
<g clip-path="url(#tc)">
|
|
32
|
+
<rect x="0" y="0" width="100" height="100" fill="url(#tile)"></rect>
|
|
33
|
+
<rect x="0" y="0" width="100" height="100" fill="url(#shine)"></rect>
|
|
34
|
+
<g fill="none" stroke="url(#tube)" stroke-linecap="round" filter="url(#sh)">
|
|
35
|
+
<circle cx="50" cy="50" r="17" stroke-width="5" stroke-dasharray="78 29" transform="rotate(-35 50 50)" stroke-opacity="0.92"></circle>
|
|
36
|
+
<circle cx="50" cy="50" r="30" stroke-width="5" stroke-dasharray="150 39" transform="rotate(70 50 50)" stroke-opacity="0.8"></circle>
|
|
37
|
+
</g>
|
|
38
|
+
<circle cx="50" cy="50" r="7" fill="url(#core)"></circle>
|
|
39
|
+
<circle cx="50" cy="20" r="5.6" fill="url(#node)"></circle>
|
|
40
|
+
<circle cx="48" cy="18.4" r="1.7" fill="#fff7e6" fill-opacity="0.8"></circle>
|
|
41
|
+
</g>
|
|
42
|
+
<rect x="0.6" y="0.6" width="98.8" height="98.8" rx="22" fill="none" stroke="#ffffff" stroke-opacity="0.16" stroke-width="1.2"></rect>
|
|
43
|
+
</svg>
|
|
@@ -33,10 +33,10 @@ addEventListener("message", eventListener);
|
|
|
33
33
|
if (!window._flutter) {
|
|
34
34
|
window._flutter = {};
|
|
35
35
|
}
|
|
36
|
-
_flutter.buildConfig = {"engineRevision":"
|
|
36
|
+
_flutter.buildConfig = {"engineRevision":"c416acfeb8126e097f758c664aaa3da929e27da0","builds":[{"compileTarget":"dart2js","renderer":"canvaskit","mainJsPath":"main.dart.js"},{}]};
|
|
37
37
|
|
|
38
38
|
_flutter.loader.load({
|
|
39
39
|
serviceWorkerSettings: {
|
|
40
|
-
serviceWorkerVersion: "
|
|
40
|
+
serviceWorkerVersion: "141262336" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
|
41
41
|
}
|
|
42
42
|
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|