neoagent 2.4.1-beta.9 → 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.
Files changed (234) hide show
  1. package/.env.example +33 -3
  2. package/LICENSE +111 -56
  3. package/README.md +8 -3
  4. package/docs/configuration.md +8 -0
  5. package/docs/getting-started.md +9 -3
  6. package/docs/index.md +4 -0
  7. package/extensions/chrome-browser/background.mjs +36 -4
  8. package/extensions/chrome-browser/icons/icon128.png +0 -0
  9. package/extensions/chrome-browser/icons/icon16.png +0 -0
  10. package/extensions/chrome-browser/icons/icon48.png +0 -0
  11. package/extensions/chrome-browser/icons/logo.svg +39 -8
  12. package/extensions/chrome-browser/manifest.json +3 -3
  13. package/extensions/chrome-browser/popup.html +5 -1
  14. package/extensions/chrome-browser/popup.js +13 -0
  15. package/flutter_app/android/app/src/main/AndroidManifest.xml +2 -1
  16. package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  17. package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  18. package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  19. package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  20. package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  21. package/flutter_app/assets/branding/app_icon_1024.png +0 -0
  22. package/flutter_app/assets/branding/app_icon_128.png +0 -0
  23. package/flutter_app/assets/branding/app_icon_192.png +0 -0
  24. package/flutter_app/assets/branding/app_icon_256.png +0 -0
  25. package/flutter_app/assets/branding/app_icon_32.png +0 -0
  26. package/flutter_app/assets/branding/app_icon_512.png +0 -0
  27. package/flutter_app/assets/branding/app_icon_64.png +0 -0
  28. package/flutter_app/assets/branding/app_icon_light_1024.png +0 -0
  29. package/flutter_app/assets/branding/app_icon_light_128.png +0 -0
  30. package/flutter_app/assets/branding/app_icon_light_192.png +0 -0
  31. package/flutter_app/assets/branding/app_icon_light_256.png +0 -0
  32. package/flutter_app/assets/branding/app_icon_light_32.png +0 -0
  33. package/flutter_app/assets/branding/app_icon_light_512.png +0 -0
  34. package/flutter_app/assets/branding/app_icon_light_64.png +0 -0
  35. package/flutter_app/assets/branding/onboarding_intro.mp4 +0 -0
  36. package/flutter_app/assets/branding/tray_icon_light_template.png +0 -0
  37. package/flutter_app/assets/branding/tray_icon_template.png +0 -0
  38. package/flutter_app/lib/features/location/location_service.dart +3 -0
  39. package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +391 -382
  40. package/flutter_app/lib/features/onboarding/onboarding_companion_step.dart +743 -0
  41. package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +18 -16
  42. package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +19 -18
  43. package/flutter_app/lib/features/onboarding/onboarding_shell.dart +8 -1
  44. package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +16 -13
  45. package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +17 -13
  46. package/flutter_app/lib/main.dart +2 -0
  47. package/flutter_app/lib/main_account_settings.dart +10 -34
  48. package/flutter_app/lib/main_admin.dart +14 -1
  49. package/flutter_app/lib/main_app_shell.dart +377 -340
  50. package/flutter_app/lib/main_chat.dart +707 -227
  51. package/flutter_app/lib/main_controller.dart +197 -42
  52. package/flutter_app/lib/main_devices.dart +436 -4
  53. package/flutter_app/lib/main_integrations.dart +255 -6
  54. package/flutter_app/lib/main_launcher.dart +1 -1
  55. package/flutter_app/lib/main_model_picker.dart +685 -0
  56. package/flutter_app/lib/main_models.dart +212 -0
  57. package/flutter_app/lib/main_navigation.dart +1 -9
  58. package/flutter_app/lib/main_operations.dart +1417 -614
  59. package/flutter_app/lib/main_settings.dart +673 -871
  60. package/flutter_app/lib/main_shared.dart +971 -443
  61. package/flutter_app/lib/main_spacing.dart +4 -4
  62. package/flutter_app/lib/main_theme.dart +22 -14
  63. package/flutter_app/lib/main_unified.dart +5 -72
  64. package/flutter_app/lib/src/android_apk_drop_zone.dart +24 -0
  65. package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +13 -0
  66. package/flutter_app/lib/src/android_apk_drop_zone_web.dart +219 -0
  67. package/flutter_app/lib/src/backend_client.dart +46 -0
  68. package/flutter_app/lib/src/desktop_companion_actions.dart +30 -7
  69. package/flutter_app/lib/src/desktop_companion_io.dart +71 -1
  70. package/flutter_app/lib/src/security/password_strength.dart +84 -0
  71. package/flutter_app/lib/src/stream_renderer.dart +42 -3
  72. package/flutter_app/lib/src/theme/palette.dart +76 -34
  73. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  74. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  75. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  76. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  77. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  78. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  79. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  80. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  81. package/flutter_app/pubspec.lock +2 -2
  82. package/flutter_app/pubspec.yaml +7 -1
  83. package/flutter_app/tool/branding_source/neoagent-icon-1024.png +0 -0
  84. package/flutter_app/tool/branding_source/neoagent-icon-128.png +0 -0
  85. package/flutter_app/tool/branding_source/neoagent-icon-16.png +0 -0
  86. package/flutter_app/tool/branding_source/neoagent-icon-180.png +0 -0
  87. package/flutter_app/tool/branding_source/neoagent-icon-192.png +0 -0
  88. package/flutter_app/tool/branding_source/neoagent-icon-256.png +0 -0
  89. package/flutter_app/tool/branding_source/neoagent-icon-32.png +0 -0
  90. package/flutter_app/tool/branding_source/neoagent-icon-48.png +0 -0
  91. package/flutter_app/tool/branding_source/neoagent-icon-512.png +0 -0
  92. package/flutter_app/tool/branding_source/neoagent-icon-64.png +0 -0
  93. package/flutter_app/tool/branding_source/neoagent-icon.svg +43 -0
  94. package/flutter_app/tool/generate_desktop_branding.py +154 -152
  95. package/flutter_app/web/favicon.png +0 -0
  96. package/flutter_app/web/favicon.svg +40 -9
  97. package/flutter_app/web/favicon_light.svg +43 -0
  98. package/flutter_app/web/icons/Icon-192-light.png +0 -0
  99. package/flutter_app/web/icons/Icon-192.png +0 -0
  100. package/flutter_app/web/icons/Icon-512-light.png +0 -0
  101. package/flutter_app/web/icons/Icon-512.png +0 -0
  102. package/flutter_app/web/icons/Icon-maskable-192-light.png +0 -0
  103. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  104. package/flutter_app/web/icons/Icon-maskable-512-light.png +0 -0
  105. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  106. package/flutter_app/windows/runner/main.cpp +7 -1
  107. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  108. package/lib/manager.js +445 -83
  109. package/package.json +17 -3
  110. package/runtime/paths.js +3 -1
  111. package/server/admin/access.js +198 -0
  112. package/server/admin/admin.css +268 -0
  113. package/server/admin/admin.js +348 -0
  114. package/server/admin/analytics.js +128 -0
  115. package/server/admin/index.html +1015 -0
  116. package/server/admin/login.html +290 -0
  117. package/server/admin/logo.svg +43 -0
  118. package/server/admin/sql.js +134 -0
  119. package/server/admin/users.js +147 -0
  120. package/server/config/origins.js +3 -1
  121. package/server/db/database.js +92 -0
  122. package/server/db/ftsQuery.js +27 -0
  123. package/server/http/routes.js +1 -0
  124. package/server/http/static.js +23 -6
  125. package/server/index.js +1 -1
  126. package/server/middleware/adminAuth.js +48 -0
  127. package/server/middleware/auth.js +1 -40
  128. package/server/public/.last_build_id +1 -1
  129. package/server/public/app_icon.png +0 -0
  130. package/server/public/assets/AssetManifest.bin +1 -1
  131. package/server/public/assets/AssetManifest.bin.json +1 -1
  132. package/server/public/assets/assets/branding/app_icon_1024.png +0 -0
  133. package/server/public/assets/assets/branding/app_icon_256.png +0 -0
  134. package/server/public/assets/assets/branding/app_icon_512.png +0 -0
  135. package/server/public/assets/assets/branding/app_icon_light_1024.png +0 -0
  136. package/server/public/assets/assets/branding/app_icon_light_256.png +0 -0
  137. package/server/public/assets/assets/branding/app_icon_light_512.png +0 -0
  138. package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
  139. package/server/public/assets/assets/branding/tray_icon_light_template.png +0 -0
  140. package/server/public/assets/assets/branding/tray_icon_template.png +0 -0
  141. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  142. package/server/public/assets/web/icons/Icon-192.png +0 -0
  143. package/server/public/favicon.png +0 -0
  144. package/server/public/favicon.svg +40 -9
  145. package/server/public/favicon_light.svg +43 -0
  146. package/server/public/flutter_bootstrap.js +2 -2
  147. package/server/public/icons/Icon-192-light.png +0 -0
  148. package/server/public/icons/Icon-192.png +0 -0
  149. package/server/public/icons/Icon-512-light.png +0 -0
  150. package/server/public/icons/Icon-512.png +0 -0
  151. package/server/public/icons/Icon-maskable-192-light.png +0 -0
  152. package/server/public/icons/Icon-maskable-192.png +0 -0
  153. package/server/public/icons/Icon-maskable-512-light.png +0 -0
  154. package/server/public/icons/Icon-maskable-512.png +0 -0
  155. package/server/public/main.dart.js +88537 -85936
  156. package/server/routes/admin.js +632 -0
  157. package/server/routes/agent_profiles.js +3 -0
  158. package/server/routes/agents.js +1 -1
  159. package/server/routes/auth.js +3 -1
  160. package/server/routes/mcp.js +29 -13
  161. package/server/routes/memory.js +23 -1
  162. package/server/routes/messaging.js +2 -0
  163. package/server/routes/screenHistory.js +14 -8
  164. package/server/routes/settings.js +10 -2
  165. package/server/routes/stream.js +1 -1
  166. package/server/routes/triggers.js +4 -4
  167. package/server/routes/voice_assistant.js +36 -1
  168. package/server/routes/workspace.js +86 -0
  169. package/server/services/account/admin_two_factor.js +132 -0
  170. package/server/services/account/password_policy.js +6 -1
  171. package/server/services/ai/completion.js +44 -0
  172. package/server/services/ai/engine.js +321 -500
  173. package/server/services/ai/imageAnalysis.js +9 -5
  174. package/server/services/ai/logFormat.js +46 -0
  175. package/server/services/ai/loopPolicy.js +11 -0
  176. package/server/services/ai/messagingFallback.js +228 -0
  177. package/server/services/ai/models.js +194 -55
  178. package/server/services/ai/providerRetry.js +169 -0
  179. package/server/services/ai/providers/anthropic.js +15 -4
  180. package/server/services/ai/providers/google.js +38 -11
  181. package/server/services/ai/providers/grok.js +19 -68
  182. package/server/services/ai/providers/grokOauth.js +141 -0
  183. package/server/services/ai/providers/nvidia.js +154 -0
  184. package/server/services/ai/providers/ollama.js +76 -39
  185. package/server/services/ai/providers/openai.js +20 -31
  186. package/server/services/ai/providers/openaiCodex.js +6 -2
  187. package/server/services/ai/providers/openaiCompatible.js +70 -0
  188. package/server/services/ai/providers/openrouter.js +162 -0
  189. package/server/services/ai/settings.js +30 -0
  190. package/server/services/ai/systemPrompt.js +51 -29
  191. package/server/services/ai/taskAnalysis.js +60 -1
  192. package/server/services/ai/toolEvidence.js +207 -0
  193. package/server/services/ai/toolSelector.js +8 -1
  194. package/server/services/ai/tools.js +78 -13
  195. package/server/services/browser/extension/registry.js +94 -9
  196. package/server/services/desktop/registry.js +104 -1
  197. package/server/services/desktop/screenRecorder.js +208 -98
  198. package/server/services/desktop/screen_recorder_support.js +46 -0
  199. package/server/services/integrations/google/provider.js +13 -0
  200. package/server/services/integrations/home_assistant/constants.js +88 -0
  201. package/server/services/integrations/home_assistant/network.js +207 -0
  202. package/server/services/integrations/home_assistant/provider.js +249 -0
  203. package/server/services/integrations/home_assistant/snapshot.js +98 -0
  204. package/server/services/integrations/home_assistant/tools.js +101 -0
  205. package/server/services/integrations/manager.js +5 -0
  206. package/server/services/integrations/registry.js +2 -0
  207. package/server/services/integrations/trello/provider.js +8 -2
  208. package/server/services/manager.js +51 -53
  209. package/server/services/mcp/client.js +208 -268
  210. package/server/services/mcp/client_support.js +172 -0
  211. package/server/services/mcp/recovery.js +116 -0
  212. package/server/services/mcp/tool_operations.js +123 -0
  213. package/server/services/memory/ingestion.js +185 -370
  214. package/server/services/memory/ingestion_coverage.js +129 -0
  215. package/server/services/memory/ingestion_documents.js +123 -0
  216. package/server/services/memory/ingestion_support.js +171 -0
  217. package/server/services/memory/intelligence.js +181 -0
  218. package/server/services/memory/manager.js +476 -32
  219. package/server/services/messaging/automation.js +71 -134
  220. package/server/services/messaging/formatting_guides.js +26 -1
  221. package/server/services/messaging/inbound_queue.js +111 -0
  222. package/server/services/messaging/manager.js +25 -8
  223. package/server/services/messaging/typing_keepalive.js +110 -0
  224. package/server/services/streaming/android-stream.js +293 -40
  225. package/server/services/tasks/integration_runtime.js +4 -1
  226. package/server/services/tasks/runtime.js +415 -56
  227. package/server/services/tasks/task_repository.js +48 -6
  228. package/server/services/websocket.js +8 -2
  229. package/server/services/widgets/service.js +17 -1
  230. package/server/services/workspace/manager.js +116 -0
  231. package/server/utils/logger.js +44 -6
  232. package/server/utils/security.js +3 -0
  233. package/server/utils/version.js +29 -19
  234. package/server/services/memory/openhuman_uplift.test.js +0 -98
@@ -2,13 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import math
6
5
  from pathlib import Path
7
6
 
8
- from PIL import Image, ImageDraw, ImageFilter
7
+ from PIL import Image, ImageDraw
9
8
 
10
9
 
11
10
  ROOT = Path(__file__).resolve().parents[1]
11
+ SOURCE_DIR = ROOT / "tool" / "branding_source"
12
12
  BRANDING_DIR = ROOT / "assets" / "branding"
13
13
  WEB_DIR = ROOT / "web"
14
14
  WEB_ICONS_DIR = WEB_DIR / "icons"
@@ -18,172 +18,156 @@ LINUX_ICON_DIR = ROOT / "linux" / "runner" / "resources"
18
18
  ANDROID_RES_DIR = ROOT / "android" / "app" / "src" / "main" / "res"
19
19
  SERVER_PUBLIC_DIR = ROOT.parent / "server" / "public"
20
20
  SERVER_PUBLIC_ICONS_DIR = SERVER_PUBLIC_DIR / "icons"
21
+ STATIC_IMG_DIR = ROOT.parent / "static" / "img"
22
+ LANDING_LOGO_PATH = ROOT.parent / "landing" / "assets" / "logo.svg"
23
+ EXTENSION_ICON_DIR = ROOT.parent / "extensions" / "chrome-browser" / "icons"
24
+ EXTENSION_LOGO_PATH = EXTENSION_ICON_DIR / "logo.svg"
21
25
 
22
- ACCENT = (143, 109, 62)
23
- ACCENT_ALT = (47, 125, 110)
24
- WHITE = (255, 255, 255, 255)
26
+ SOURCE_SVG = SOURCE_DIR / "neoagent-icon.svg"
27
+ SOURCE_PNG_SIZES = (16, 32, 48, 64, 128, 180, 192, 256, 512, 1024)
25
28
  TRANSPARENT = (0, 0, 0, 0)
29
+ WHITE = (255, 255, 255, 255)
30
+ BLACK = (0, 0, 0, 255)
31
+ TRAY_TEMPLATE_SIZE = 256
26
32
 
27
33
 
28
- def lerp(a: float, b: float, t: float) -> float:
29
- return a + (b - a) * t
30
-
31
-
32
- def gradient_background(size: int) -> Image.Image:
33
- img = Image.new("RGBA", (size, size), TRANSPARENT)
34
- px = img.load()
35
- for y in range(size):
36
- for x in range(size):
37
- tx = x / max(size - 1, 1)
38
- ty = y / max(size - 1, 1)
39
- t = (tx + ty) / 2
40
- px[x, y] = (
41
- int(lerp(ACCENT[0], ACCENT_ALT[0], t)),
42
- int(lerp(ACCENT[1], ACCENT_ALT[1], t)),
43
- int(lerp(ACCENT[2], ACCENT_ALT[2], t)),
44
- 255,
45
- )
46
- return img
34
+ def ensure_dirs() -> None:
35
+ BRANDING_DIR.mkdir(parents=True, exist_ok=True)
36
+ WEB_ICONS_DIR.mkdir(parents=True, exist_ok=True)
37
+ MAC_ICON_DIR.mkdir(parents=True, exist_ok=True)
38
+ LINUX_ICON_DIR.mkdir(parents=True, exist_ok=True)
39
+ SERVER_PUBLIC_ICONS_DIR.mkdir(parents=True, exist_ok=True)
40
+ STATIC_IMG_DIR.mkdir(parents=True, exist_ok=True)
41
+ LANDING_LOGO_PATH.parent.mkdir(parents=True, exist_ok=True)
42
+ EXTENSION_ICON_DIR.mkdir(parents=True, exist_ok=True)
47
43
 
48
44
 
49
- def logo_paths(size: int, padding_ratio: float = 0.18):
50
- pad = size * padding_ratio
51
- inner = size - pad * 2
52
- def point(x: float, y: float) -> tuple[float, float]:
53
- return (pad + inner * x, pad + inner * y)
45
+ def source_png_path(size: int) -> Path:
46
+ return SOURCE_DIR / f"neoagent-icon-{size}.png"
54
47
 
55
- top = [point(0.5, 0.08), point(0.1, 0.3), point(0.5, 0.52), point(0.9, 0.3)]
56
- middle = [point(0.1, 0.52), point(0.5, 0.74), point(0.9, 0.52)]
57
- bottom = [point(0.1, 0.72), point(0.5, 0.94), point(0.9, 0.72)]
58
- return top, middle, bottom, inner
59
48
 
49
+ def load_source_icon(size: int) -> Image.Image:
50
+ if size in SOURCE_PNG_SIZES and source_png_path(size).exists():
51
+ return Image.open(source_png_path(size)).convert("RGBA")
52
+ source = Image.open(source_png_path(1024)).convert("RGBA")
53
+ return source.resize((size, size), Image.Resampling.LANCZOS)
60
54
 
61
- def draw_logo(draw: ImageDraw.ImageDraw, size: int, color: tuple[int, int, int, int]) -> None:
62
- top, middle, bottom, inner = logo_paths(size)
63
- stroke = max(2, round(inner * 0.08))
64
- draw.polygon(top, fill=color)
65
- draw.line(middle, fill=color, width=stroke, joint="curve")
66
- draw.line(bottom, fill=color, width=stroke, joint="curve")
67
55
 
56
+ def save_icon(path: Path, size: int) -> None:
57
+ path.parent.mkdir(parents=True, exist_ok=True)
58
+ image = load_source_icon(size)
59
+ if image.size != (size, size):
60
+ image = image.resize((size, size), Image.Resampling.LANCZOS)
61
+ image.save(path, format="PNG")
68
62
 
69
- def make_app_icon(size: int) -> Image.Image:
70
- canvas = Image.new("RGBA", (size, size), TRANSPARENT)
71
63
 
72
- shadow = Image.new("RGBA", (size, size), TRANSPARENT)
73
- shadow_draw = ImageDraw.Draw(shadow)
74
- offset_y = size * 0.02
75
- corner = round(size * 0.34)
76
- shadow_draw.rounded_rectangle(
77
- (size * 0.07, size * 0.07 + offset_y, size * 0.93, size * 0.93 + offset_y),
78
- radius=corner,
79
- fill=(0, 0, 0, 72),
64
+ def write_source_svg(path: Path) -> None:
65
+ path.parent.mkdir(parents=True, exist_ok=True)
66
+ svg = SOURCE_SVG.read_text(encoding="utf-8")
67
+ svg = svg.replace(
68
+ 'stroke="rgba(255,255,255,0.16)"',
69
+ 'stroke="#ffffff" stroke-opacity="0.16"',
80
70
  )
81
- shadow = shadow.filter(ImageFilter.GaussianBlur(radius=max(2, size * 0.04)))
82
- canvas.alpha_composite(shadow)
83
-
84
- base_mask = Image.new("L", (size, size), 0)
85
- mask_draw = ImageDraw.Draw(base_mask)
86
- base_rect = (size * 0.08, size * 0.08, size * 0.92, size * 0.92)
87
- mask_draw.rounded_rectangle(base_rect, radius=corner, fill=255)
88
-
89
- base = gradient_background(size)
90
- clipped = Image.new("RGBA", (size, size), TRANSPARENT)
91
- clipped.paste(base, mask=base_mask)
92
- canvas.alpha_composite(clipped)
93
-
94
- ring = Image.new("RGBA", (size, size), TRANSPARENT)
95
- ring_draw = ImageDraw.Draw(ring)
96
- ring_draw.rounded_rectangle(
97
- base_rect,
98
- radius=corner,
99
- outline=(255, 255, 255, 36),
100
- width=max(1, round(size * 0.012)),
71
+ path.write_text(svg, encoding="utf-8")
72
+
73
+
74
+ def draw_scaled_circle(
75
+ draw: ImageDraw.ImageDraw,
76
+ size: int,
77
+ center_x: float,
78
+ center_y: float,
79
+ radius: float,
80
+ color: tuple[int, int, int, int],
81
+ ) -> None:
82
+ scale = size / 100
83
+ draw.ellipse(
84
+ (
85
+ (center_x - radius) * scale,
86
+ (center_y - radius) * scale,
87
+ (center_x + radius) * scale,
88
+ (center_y + radius) * scale,
89
+ ),
90
+ fill=color,
101
91
  )
102
- canvas.alpha_composite(ring)
103
-
104
- glyph = Image.new("RGBA", (size, size), TRANSPARENT)
105
- draw = ImageDraw.Draw(glyph)
106
- draw_logo(draw, size, WHITE)
107
- canvas.alpha_composite(glyph)
108
- return canvas
109
92
 
110
93
 
111
- def make_tray_template(size: int = 64) -> Image.Image:
94
+ def make_tray_template(
95
+ size: int = 64,
96
+ color: tuple[int, int, int, int] = BLACK,
97
+ ) -> Image.Image:
112
98
  img = Image.new("RGBA", (size, size), TRANSPARENT)
113
99
  draw = ImageDraw.Draw(img)
114
- draw_logo(draw, size, (0, 0, 0, 255))
115
- return img
116
-
117
-
118
- def ensure_dirs() -> None:
119
- BRANDING_DIR.mkdir(parents=True, exist_ok=True)
120
- WEB_ICONS_DIR.mkdir(parents=True, exist_ok=True)
121
- MAC_ICON_DIR.mkdir(parents=True, exist_ok=True)
122
- LINUX_ICON_DIR.mkdir(parents=True, exist_ok=True)
123
- SERVER_PUBLIC_ICONS_DIR.mkdir(parents=True, exist_ok=True)
124
-
125
-
126
- def write_text(path: Path, content: str) -> None:
127
- path.write_text(content, encoding="utf-8")
128
-
129
-
130
- def copy_png(image: Image.Image, path: Path, size: int) -> None:
131
- path.parent.mkdir(parents=True, exist_ok=True)
132
- save_png(image, path, size)
100
+ scale = size / 100
101
+ width = max(2, round(size * 0.078))
102
+ center = 50 * scale
103
+
104
+ draw.arc(
105
+ (
106
+ (50 - 30) * scale,
107
+ (50 - 30) * scale,
108
+ (50 + 30) * scale,
109
+ (50 + 30) * scale,
110
+ ),
111
+ start=158,
112
+ end=444,
113
+ fill=color,
114
+ width=width,
115
+ )
116
+ draw.arc(
117
+ (
118
+ (50 - 17) * scale,
119
+ (50 - 17) * scale,
120
+ (50 + 17) * scale,
121
+ (50 + 17) * scale,
122
+ ),
123
+ start=68,
124
+ end=330,
125
+ fill=color,
126
+ width=width,
127
+ )
128
+ draw_scaled_circle(draw, size, 50, 50, 7, color)
129
+ draw_scaled_circle(draw, size, 50, 20, 5.6, color)
130
+
131
+ # Slightly round arc ends so the template keeps the supplied logo's soft tube feel.
132
+ end_radius = width / 2
133
+ for x, y in ((77.2, 74.8), (80.0, 41.2), (32.0, 29.7), (68.8, 39.2)):
134
+ draw.ellipse(
135
+ (
136
+ x * scale - end_radius,
137
+ y * scale - end_radius,
138
+ x * scale + end_radius,
139
+ y * scale + end_radius,
140
+ ),
141
+ fill=color,
142
+ )
133
143
 
144
+ # Keep the symbol optically centered inside the menu-bar bounds.
145
+ vertical_offset = round(size * 0.03125)
146
+ return img.crop((0, vertical_offset, size, size + vertical_offset))
134
147
 
135
- def write_favicon_svg(path: Path) -> None:
136
- svg = f"""<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
137
- <defs>
138
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
139
- <stop offset="0%" stop-color="#{ACCENT[0]:02x}{ACCENT[1]:02x}{ACCENT[2]:02x}"/>
140
- <stop offset="100%" stop-color="#{ACCENT_ALT[0]:02x}{ACCENT_ALT[1]:02x}{ACCENT_ALT[2]:02x}"/>
141
- </linearGradient>
142
- </defs>
143
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#bg)" stroke="#ffffff" stroke-opacity="0.16" stroke-width="1"/>
144
- <polygon points="16,5.7 5.2,11.6 16,17.6 26.8,11.6" fill="white"/>
145
- <polyline points="5.2,17.6 16,23.5 26.8,17.6" fill="none" stroke="white" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
146
- <polyline points="5.2,22.7 16,28.1 26.8,22.7" fill="none" stroke="white" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
147
- </svg>
148
- """
149
- write_text(path, svg)
150
148
 
149
+ def main() -> None:
150
+ ensure_dirs()
151
151
 
152
- def save_png(image: Image.Image, path: Path, size: int) -> None:
153
- image.resize((size, size), Image.Resampling.LANCZOS).save(path, format="PNG")
152
+ for size in (1024, 512, 256, 192, 128, 64, 32):
153
+ save_icon(BRANDING_DIR / f"app_icon_{size}.png", size)
154
+ save_icon(BRANDING_DIR / f"app_icon_light_{size}.png", size)
154
155
 
156
+ make_tray_template(TRAY_TEMPLATE_SIZE).save(
157
+ BRANDING_DIR / "tray_icon_template.png",
158
+ format="PNG",
159
+ )
160
+ make_tray_template(TRAY_TEMPLATE_SIZE, WHITE).save(
161
+ BRANDING_DIR / "tray_icon_light_template.png",
162
+ format="PNG",
163
+ )
155
164
 
156
- def main() -> None:
157
- ensure_dirs()
158
- master = make_app_icon(1024)
159
-
160
- save_png(master, BRANDING_DIR / "app_icon_1024.png", 1024)
161
- save_png(master, BRANDING_DIR / "app_icon_512.png", 512)
162
- save_png(master, BRANDING_DIR / "app_icon_256.png", 256)
163
- save_png(master, BRANDING_DIR / "app_icon_192.png", 192)
164
- save_png(master, BRANDING_DIR / "app_icon_128.png", 128)
165
- save_png(master, BRANDING_DIR / "app_icon_64.png", 64)
166
- save_png(master, BRANDING_DIR / "app_icon_32.png", 32)
167
-
168
- tray = make_tray_template(64)
169
- save_png(tray, BRANDING_DIR / "tray_icon_template.png", 64)
170
-
171
- icon_sizes = {
172
- 16: "app_icon_16.png",
173
- 32: "app_icon_32.png",
174
- 64: "app_icon_64.png",
175
- 128: "app_icon_128.png",
176
- 256: "app_icon_256.png",
177
- 512: "app_icon_512.png",
178
- 1024: "app_icon_1024.png",
179
- }
180
- for size, filename in icon_sizes.items():
181
- save_png(master, MAC_ICON_DIR / filename, size)
165
+ for size in (16, 32, 64, 128, 256, 512, 1024):
166
+ save_icon(MAC_ICON_DIR / f"app_icon_{size}.png", size)
182
167
 
183
- save_png(master, LINUX_ICON_DIR / "app_icon.png", 256)
168
+ save_icon(LINUX_ICON_DIR / "app_icon.png", 256)
184
169
 
185
- master_for_ico = master.resize((256, 256), Image.Resampling.LANCZOS)
186
- master_for_ico.save(
170
+ load_source_icon(256).save(
187
171
  WINDOWS_ICON_PATH,
188
172
  format="ICO",
189
173
  sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)],
@@ -194,15 +178,33 @@ def main() -> None:
194
178
  512: "Icon-512.png",
195
179
  }
196
180
  for size, filename in web_icon_sizes.items():
197
- copy_png(master, WEB_ICONS_DIR / filename, size)
198
- copy_png(master, WEB_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
199
- copy_png(master, SERVER_PUBLIC_ICONS_DIR / filename, size)
200
- copy_png(master, SERVER_PUBLIC_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
201
-
202
- copy_png(master, WEB_DIR / "favicon.png", 32)
203
- copy_png(master, SERVER_PUBLIC_DIR / "favicon.png", 32)
204
- write_favicon_svg(WEB_DIR / "favicon.svg")
205
- write_favicon_svg(SERVER_PUBLIC_DIR / "favicon.svg")
181
+ save_icon(WEB_ICONS_DIR / filename, size)
182
+ save_icon(WEB_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
183
+ save_icon(WEB_ICONS_DIR / filename.replace(".png", "-light.png"), size)
184
+ save_icon(WEB_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-").replace(".png", "-light.png"), size)
185
+ save_icon(SERVER_PUBLIC_ICONS_DIR / filename, size)
186
+ save_icon(SERVER_PUBLIC_ICONS_DIR / filename.replace("Icon-", "Icon-maskable-"), size)
187
+
188
+ save_icon(WEB_DIR / "favicon.png", 32)
189
+ save_icon(SERVER_PUBLIC_DIR / "favicon.png", 32)
190
+ write_source_svg(WEB_DIR / "favicon.svg")
191
+ write_source_svg(WEB_DIR / "favicon_light.svg")
192
+ write_source_svg(SERVER_PUBLIC_DIR / "favicon.svg")
193
+ write_source_svg(SERVER_PUBLIC_DIR / "favicon_light.svg")
194
+ write_source_svg(LANDING_LOGO_PATH)
195
+ write_source_svg(EXTENSION_LOGO_PATH)
196
+
197
+ for size in (16, 48, 128):
198
+ save_icon(EXTENSION_ICON_DIR / f"icon{size}.png", size)
199
+
200
+ save_icon(STATIC_IMG_DIR / "app_icon.png", 512)
201
+ save_icon(STATIC_IMG_DIR / "app_icon_light.png", 512)
202
+ save_icon(SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "app_icon_256.png", 256)
203
+ make_tray_template(TRAY_TEMPLATE_SIZE).save(
204
+ SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "tray_icon_template.png",
205
+ format="PNG",
206
+ )
207
+ save_icon(SERVER_PUBLIC_DIR / "assets" / "web" / "icons" / "Icon-192.png", 192)
206
208
 
207
209
  android_icon_sizes = {
208
210
  "mipmap-mdpi": 48,
@@ -212,7 +214,7 @@ def main() -> None:
212
214
  "mipmap-xxxhdpi": 192,
213
215
  }
214
216
  for folder, size in android_icon_sizes.items():
215
- copy_png(master, ANDROID_RES_DIR / folder / "ic_launcher.png", size)
217
+ save_icon(ANDROID_RES_DIR / folder / "ic_launcher.png", size)
216
218
 
217
219
 
218
220
  if __name__ == "__main__":
Binary file
@@ -1,12 +1,43 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 100 100">
2
2
  <defs>
3
- <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
- <stop offset="0%" stop-color="#8f6d3e"/>
5
- <stop offset="100%" stop-color="#2f7d6e"/>
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
- <rect x="2.5" y="2.5" width="27" height="27" rx="9" ry="9" fill="url(#bg)" stroke="#ffffff" stroke-opacity="0.16" stroke-width="1"/>
9
- <polygon points="16,5.7 5.2,11.6 16,17.6 26.8,11.6" fill="white"/>
10
- <polyline points="5.2,17.6 16,23.5 26.8,17.6" fill="none" stroke="white" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
11
- <polyline points="5.2,22.7 16,28.1 26.8,22.7" fill="none" stroke="white" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
12
- </svg>
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>
Binary file
Binary file
@@ -28,10 +28,16 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
28
28
  Win32Window::Point origin(10, 10);
29
29
  Win32Window::Size size(1280, 720);
30
30
  if (!window.Create(L"NeoAgent", origin, size)) {
31
+ ::MessageBoxW(nullptr,
32
+ L"NeoAgent failed to start. The Flutter engine could not be "
33
+ L"initialized. Ensure the application was installed correctly "
34
+ L"and all required files are present.",
35
+ L"NeoAgent — Startup Error",
36
+ MB_OK | MB_ICONERROR);
31
37
  ::CoUninitialize();
32
38
  return EXIT_FAILURE;
33
39
  }
34
- window.SetQuitOnClose(false);
40
+ window.SetQuitOnClose(true);
35
41
 
36
42
  ::MSG msg;
37
43
  while (true) {