markupr 2.1.8

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 (299) hide show
  1. package/.claude/commands/review-feedback.md +47 -0
  2. package/.eslintrc.json +35 -0
  3. package/.github/CODEOWNERS +16 -0
  4. package/.github/FUNDING.yml +1 -0
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +56 -0
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +54 -0
  7. package/.github/PULL_REQUEST_TEMPLATE.md +89 -0
  8. package/.github/dependabot.yml +70 -0
  9. package/.github/workflows/ci.yml +184 -0
  10. package/.github/workflows/deploy-landing.yml +134 -0
  11. package/.github/workflows/nightly.yml +288 -0
  12. package/.github/workflows/release.yml +318 -0
  13. package/CHANGELOG.md +127 -0
  14. package/CLAUDE.md +137 -0
  15. package/CODE_OF_CONDUCT.md +9 -0
  16. package/CONTRIBUTING.md +390 -0
  17. package/LICENSE +21 -0
  18. package/PRODUCT_VISION.md +277 -0
  19. package/README.md +517 -0
  20. package/SECURITY.md +51 -0
  21. package/SIGNING_INSTRUCTIONS.md +284 -0
  22. package/assets/DMG_BACKGROUND_INSTRUCTIONS.md +130 -0
  23. package/assets/svg-source/dmg-background.svg +70 -0
  24. package/assets/svg-source/icon.svg +20 -0
  25. package/assets/svg-source/tray-icon-processing.svg +7 -0
  26. package/assets/svg-source/tray-icon-recording.svg +7 -0
  27. package/assets/svg-source/tray-icon.svg +6 -0
  28. package/assets/tray-complete.png +0 -0
  29. package/assets/tray-complete@2x.png +0 -0
  30. package/assets/tray-completeTemplate.png +0 -0
  31. package/assets/tray-completeTemplate@2x.png +0 -0
  32. package/assets/tray-error.png +0 -0
  33. package/assets/tray-error@2x.png +0 -0
  34. package/assets/tray-errorTemplate.png +0 -0
  35. package/assets/tray-errorTemplate@2x.png +0 -0
  36. package/assets/tray-icon-processing.png +0 -0
  37. package/assets/tray-icon-processing@2x.png +0 -0
  38. package/assets/tray-icon-processingTemplate.png +0 -0
  39. package/assets/tray-icon-processingTemplate@2x.png +0 -0
  40. package/assets/tray-icon-recording.png +0 -0
  41. package/assets/tray-icon-recording@2x.png +0 -0
  42. package/assets/tray-icon-recordingTemplate.png +0 -0
  43. package/assets/tray-icon-recordingTemplate@2x.png +0 -0
  44. package/assets/tray-icon.png +0 -0
  45. package/assets/tray-icon@2x.png +0 -0
  46. package/assets/tray-iconTemplate.png +0 -0
  47. package/assets/tray-iconTemplate@2x.png +0 -0
  48. package/assets/tray-idle.png +0 -0
  49. package/assets/tray-idle@2x.png +0 -0
  50. package/assets/tray-idleTemplate.png +0 -0
  51. package/assets/tray-idleTemplate@2x.png +0 -0
  52. package/assets/tray-processing-0.png +0 -0
  53. package/assets/tray-processing-0@2x.png +0 -0
  54. package/assets/tray-processing-0Template.png +0 -0
  55. package/assets/tray-processing-0Template@2x.png +0 -0
  56. package/assets/tray-processing-1.png +0 -0
  57. package/assets/tray-processing-1@2x.png +0 -0
  58. package/assets/tray-processing-1Template.png +0 -0
  59. package/assets/tray-processing-1Template@2x.png +0 -0
  60. package/assets/tray-processing-2.png +0 -0
  61. package/assets/tray-processing-2@2x.png +0 -0
  62. package/assets/tray-processing-2Template.png +0 -0
  63. package/assets/tray-processing-2Template@2x.png +0 -0
  64. package/assets/tray-processing-3.png +0 -0
  65. package/assets/tray-processing-3@2x.png +0 -0
  66. package/assets/tray-processing-3Template.png +0 -0
  67. package/assets/tray-processing-3Template@2x.png +0 -0
  68. package/assets/tray-processing.png +0 -0
  69. package/assets/tray-processing@2x.png +0 -0
  70. package/assets/tray-processingTemplate.png +0 -0
  71. package/assets/tray-processingTemplate@2x.png +0 -0
  72. package/assets/tray-recording.png +0 -0
  73. package/assets/tray-recording@2x.png +0 -0
  74. package/assets/tray-recordingTemplate.png +0 -0
  75. package/assets/tray-recordingTemplate@2x.png +0 -0
  76. package/build/DMG_BACKGROUND_SPEC.md +50 -0
  77. package/build/dmg-background.png +0 -0
  78. package/build/dmg-background@2x.png +0 -0
  79. package/build/entitlements.mac.inherit.plist +27 -0
  80. package/build/entitlements.mac.plist +41 -0
  81. package/build/favicon-16.png +0 -0
  82. package/build/favicon-180.png +0 -0
  83. package/build/favicon-192.png +0 -0
  84. package/build/favicon-32.png +0 -0
  85. package/build/favicon-48.png +0 -0
  86. package/build/favicon-512.png +0 -0
  87. package/build/favicon-64.png +0 -0
  88. package/build/icon-128.png +0 -0
  89. package/build/icon-16.png +0 -0
  90. package/build/icon-24.png +0 -0
  91. package/build/icon-256.png +0 -0
  92. package/build/icon-32.png +0 -0
  93. package/build/icon-48.png +0 -0
  94. package/build/icon-64.png +0 -0
  95. package/build/icon.icns +0 -0
  96. package/build/icon.ico +0 -0
  97. package/build/icon.iconset/icon_128x128.png +0 -0
  98. package/build/icon.iconset/icon_128x128@2x.png +0 -0
  99. package/build/icon.iconset/icon_16x16.png +0 -0
  100. package/build/icon.iconset/icon_16x16@2x.png +0 -0
  101. package/build/icon.iconset/icon_256x256.png +0 -0
  102. package/build/icon.iconset/icon_256x256@2x.png +0 -0
  103. package/build/icon.iconset/icon_32x32.png +0 -0
  104. package/build/icon.iconset/icon_32x32@2x.png +0 -0
  105. package/build/icon.iconset/icon_512x512.png +0 -0
  106. package/build/icon.iconset/icon_512x512@2x.png +0 -0
  107. package/build/icon.png +0 -0
  108. package/build/installer-header.bmp +0 -0
  109. package/build/installer-header.png +0 -0
  110. package/build/installer-sidebar.bmp +0 -0
  111. package/build/installer-sidebar.png +0 -0
  112. package/build/installer.nsh +45 -0
  113. package/build/overlay-processing.png +0 -0
  114. package/build/overlay-recording.png +0 -0
  115. package/build/toolbar-record.png +0 -0
  116. package/build/toolbar-screenshot.png +0 -0
  117. package/build/toolbar-settings.png +0 -0
  118. package/build/toolbar-stop.png +0 -0
  119. package/dist/main/index.mjs +12612 -0
  120. package/dist/preload/index.mjs +907 -0
  121. package/dist/renderer/assets/index-CCmUjl9K.js +19495 -0
  122. package/dist/renderer/assets/index-CUqz_Gs6.css +2270 -0
  123. package/dist/renderer/index.html +27 -0
  124. package/docs/AI_AGENT_QUICKSTART.md +42 -0
  125. package/docs/AI_PIPELINE_DESIGN.md +595 -0
  126. package/docs/API.md +514 -0
  127. package/docs/ARCHITECTURE.md +460 -0
  128. package/docs/CONFIGURATION.md +336 -0
  129. package/docs/DEVELOPMENT.md +508 -0
  130. package/docs/EXPORT_FORMATS.md +451 -0
  131. package/docs/GETTING_STARTED.md +236 -0
  132. package/docs/KEYBOARD_SHORTCUTS.md +334 -0
  133. package/docs/TROUBLESHOOTING.md +418 -0
  134. package/docs/landing/index.html +672 -0
  135. package/docs/landing/script.js +342 -0
  136. package/docs/landing/styles.css +1543 -0
  137. package/electron-builder.yml +140 -0
  138. package/electron.vite.config.ts +63 -0
  139. package/package.json +108 -0
  140. package/railway.json +12 -0
  141. package/scripts/build.mjs +51 -0
  142. package/scripts/generate-icons.mjs +314 -0
  143. package/scripts/generate-installer-images.cjs +253 -0
  144. package/scripts/generate-tray-icons.mjs +258 -0
  145. package/scripts/notarize.cjs +180 -0
  146. package/scripts/one-click-clean-test.sh +147 -0
  147. package/scripts/postinstall.mjs +36 -0
  148. package/scripts/setup-markupr.sh +55 -0
  149. package/setup +17 -0
  150. package/site/index.html +1835 -0
  151. package/site/package.json +11 -0
  152. package/site/railway.json +12 -0
  153. package/site/server.js +31 -0
  154. package/src/main/AutoUpdater.ts +392 -0
  155. package/src/main/CrashRecovery.ts +655 -0
  156. package/src/main/ErrorHandler.ts +703 -0
  157. package/src/main/HotkeyManager.ts +399 -0
  158. package/src/main/MenuManager.ts +529 -0
  159. package/src/main/PermissionManager.ts +420 -0
  160. package/src/main/SessionController.ts +1465 -0
  161. package/src/main/TrayManager.ts +540 -0
  162. package/src/main/ai/AIPipelineManager.ts +199 -0
  163. package/src/main/ai/ClaudeAnalyzer.ts +339 -0
  164. package/src/main/ai/ImageOptimizer.ts +176 -0
  165. package/src/main/ai/StructuredMarkdownBuilder.ts +379 -0
  166. package/src/main/ai/index.ts +16 -0
  167. package/src/main/ai/types.ts +258 -0
  168. package/src/main/analysis/ClarificationGenerator.ts +385 -0
  169. package/src/main/analysis/FeedbackAnalyzer.ts +531 -0
  170. package/src/main/analysis/index.ts +19 -0
  171. package/src/main/audio/AudioCapture.ts +978 -0
  172. package/src/main/audio/audioUtils.ts +100 -0
  173. package/src/main/audio/index.ts +20 -0
  174. package/src/main/capture/index.ts +1 -0
  175. package/src/main/index.ts +1693 -0
  176. package/src/main/ipc/captureHandlers.ts +272 -0
  177. package/src/main/ipc/index.ts +45 -0
  178. package/src/main/ipc/outputHandlers.ts +302 -0
  179. package/src/main/ipc/sessionHandlers.ts +56 -0
  180. package/src/main/ipc/settingsHandlers.ts +471 -0
  181. package/src/main/ipc/types.ts +56 -0
  182. package/src/main/ipc/windowHandlers.ts +277 -0
  183. package/src/main/output/ClipboardService.ts +369 -0
  184. package/src/main/output/ExportService.ts +539 -0
  185. package/src/main/output/FileManager.ts +416 -0
  186. package/src/main/output/MarkdownGenerator.ts +791 -0
  187. package/src/main/output/MarkdownPatcher.ts +299 -0
  188. package/src/main/output/index.ts +186 -0
  189. package/src/main/output/sessionAdapter.ts +207 -0
  190. package/src/main/output/templates/html-template.ts +553 -0
  191. package/src/main/pipeline/FrameExtractor.ts +330 -0
  192. package/src/main/pipeline/PostProcessor.ts +399 -0
  193. package/src/main/pipeline/TranscriptAnalyzer.ts +226 -0
  194. package/src/main/pipeline/index.ts +36 -0
  195. package/src/main/platform/WindowsTaskbar.ts +600 -0
  196. package/src/main/platform/index.ts +16 -0
  197. package/src/main/settings/SettingsManager.ts +730 -0
  198. package/src/main/settings/index.ts +19 -0
  199. package/src/main/transcription/ModelDownloadManager.ts +494 -0
  200. package/src/main/transcription/TierManager.ts +219 -0
  201. package/src/main/transcription/TranscriptionRecoveryService.ts +340 -0
  202. package/src/main/transcription/WhisperService.ts +748 -0
  203. package/src/main/transcription/index.ts +56 -0
  204. package/src/main/transcription/types.ts +135 -0
  205. package/src/main/windows/PopoverManager.ts +284 -0
  206. package/src/main/windows/TaskbarIntegration.ts +452 -0
  207. package/src/main/windows/index.ts +23 -0
  208. package/src/preload/index.ts +1047 -0
  209. package/src/renderer/App.tsx +515 -0
  210. package/src/renderer/AppWrapper.tsx +28 -0
  211. package/src/renderer/assets/logo-dark.svg +7 -0
  212. package/src/renderer/assets/logo.svg +7 -0
  213. package/src/renderer/audio/AudioCaptureRenderer.ts +454 -0
  214. package/src/renderer/capture/ScreenRecordingRenderer.ts +492 -0
  215. package/src/renderer/components/AnnotationOverlay.tsx +836 -0
  216. package/src/renderer/components/AudioWaveform.tsx +811 -0
  217. package/src/renderer/components/ClarificationQuestions.tsx +656 -0
  218. package/src/renderer/components/CountdownTimer.tsx +495 -0
  219. package/src/renderer/components/CrashRecoveryDialog.tsx +632 -0
  220. package/src/renderer/components/DonateButton.tsx +127 -0
  221. package/src/renderer/components/ErrorBoundary.tsx +308 -0
  222. package/src/renderer/components/ExportDialog.tsx +872 -0
  223. package/src/renderer/components/HotkeyHint.tsx +261 -0
  224. package/src/renderer/components/KeyboardShortcuts.tsx +787 -0
  225. package/src/renderer/components/ModelDownloadDialog.tsx +844 -0
  226. package/src/renderer/components/Onboarding.tsx +1830 -0
  227. package/src/renderer/components/ProcessingOverlay.tsx +157 -0
  228. package/src/renderer/components/RecordingOverlay.tsx +423 -0
  229. package/src/renderer/components/SessionHistory.tsx +1746 -0
  230. package/src/renderer/components/SessionReview.tsx +1321 -0
  231. package/src/renderer/components/SettingsPanel.tsx +217 -0
  232. package/src/renderer/components/Skeleton.tsx +347 -0
  233. package/src/renderer/components/StatusIndicator.tsx +86 -0
  234. package/src/renderer/components/ThemeProvider.tsx +429 -0
  235. package/src/renderer/components/Tooltip.tsx +370 -0
  236. package/src/renderer/components/TranscriptionPreview.tsx +183 -0
  237. package/src/renderer/components/TranscriptionTierSelector.tsx +640 -0
  238. package/src/renderer/components/UpdateNotification.tsx +377 -0
  239. package/src/renderer/components/WindowSelector.tsx +947 -0
  240. package/src/renderer/components/index.ts +99 -0
  241. package/src/renderer/components/primitives/ApiKeyInput.tsx +98 -0
  242. package/src/renderer/components/primitives/ColorPicker.tsx +65 -0
  243. package/src/renderer/components/primitives/DangerButton.tsx +45 -0
  244. package/src/renderer/components/primitives/DirectoryPicker.tsx +41 -0
  245. package/src/renderer/components/primitives/Dropdown.tsx +34 -0
  246. package/src/renderer/components/primitives/KeyRecorder.tsx +117 -0
  247. package/src/renderer/components/primitives/SettingsSection.tsx +32 -0
  248. package/src/renderer/components/primitives/Slider.tsx +43 -0
  249. package/src/renderer/components/primitives/Toggle.tsx +36 -0
  250. package/src/renderer/components/primitives/index.ts +10 -0
  251. package/src/renderer/components/settings/AdvancedTab.tsx +174 -0
  252. package/src/renderer/components/settings/AppearanceTab.tsx +77 -0
  253. package/src/renderer/components/settings/GeneralTab.tsx +40 -0
  254. package/src/renderer/components/settings/HotkeysTab.tsx +79 -0
  255. package/src/renderer/components/settings/RecordingTab.tsx +84 -0
  256. package/src/renderer/components/settings/index.ts +9 -0
  257. package/src/renderer/components/settings/settingsStyles.ts +673 -0
  258. package/src/renderer/components/settings/tabConfig.tsx +85 -0
  259. package/src/renderer/components/settings/useSettingsPanel.ts +447 -0
  260. package/src/renderer/contexts/ProcessingContext.tsx +227 -0
  261. package/src/renderer/contexts/RecordingContext.tsx +683 -0
  262. package/src/renderer/contexts/UIContext.tsx +326 -0
  263. package/src/renderer/contexts/index.ts +24 -0
  264. package/src/renderer/donateMessages.ts +69 -0
  265. package/src/renderer/hooks/index.ts +75 -0
  266. package/src/renderer/hooks/useAnimation.tsx +544 -0
  267. package/src/renderer/hooks/useTheme.ts +313 -0
  268. package/src/renderer/index.html +26 -0
  269. package/src/renderer/main.tsx +52 -0
  270. package/src/renderer/styles/animations.css +1093 -0
  271. package/src/renderer/styles/app-shell.css +662 -0
  272. package/src/renderer/styles/globals.css +515 -0
  273. package/src/renderer/styles/theme.ts +578 -0
  274. package/src/renderer/types/electron.d.ts +385 -0
  275. package/src/shared/hotkeys.ts +283 -0
  276. package/src/shared/types.ts +809 -0
  277. package/tests/clipboard.test.ts +228 -0
  278. package/tests/e2e/criticalPaths.test.ts +594 -0
  279. package/tests/feedbackAnalyzer.test.ts +303 -0
  280. package/tests/integration/sessionFlow.test.ts +583 -0
  281. package/tests/markdownGenerator.test.ts +418 -0
  282. package/tests/output.test.ts +96 -0
  283. package/tests/setup.ts +486 -0
  284. package/tests/unit/appIntegration.test.ts +676 -0
  285. package/tests/unit/appViewState.test.ts +281 -0
  286. package/tests/unit/audioIpcChannels.test.ts +17 -0
  287. package/tests/unit/exportService.test.ts +492 -0
  288. package/tests/unit/hotkeys.test.ts +92 -0
  289. package/tests/unit/navigationPreload.test.ts +94 -0
  290. package/tests/unit/onboardingFlow.test.ts +345 -0
  291. package/tests/unit/permissionManager.test.ts +175 -0
  292. package/tests/unit/permissionManagerExpanded.test.ts +296 -0
  293. package/tests/unit/screenRecordingRenderer.test.ts +368 -0
  294. package/tests/unit/sessionController.test.ts +515 -0
  295. package/tests/unit/tierManager.test.ts +61 -0
  296. package/tests/unit/tierManagerExpanded.test.ts +142 -0
  297. package/tests/unit/transcriptAnalyzer.test.ts +64 -0
  298. package/tsconfig.json +25 -0
  299. package/vitest.config.ts +46 -0
@@ -0,0 +1,140 @@
1
+ # electron-builder.yml
2
+ # macOS Distribution Configuration for markupr
3
+ # Version: 0.4.0
4
+
5
+ appId: com.eddiesanjuan.markupr
6
+ productName: markupr
7
+ executableName: markupr
8
+ copyright: Copyright 2026 Eddie San Juan
9
+
10
+ directories:
11
+ output: release
12
+ buildResources: build
13
+
14
+ # Rebuild native modules for Electron's Node.js version
15
+ npmRebuild: true
16
+
17
+ files:
18
+ - dist/**/*
19
+ - package.json
20
+
21
+ extraResources:
22
+ - from: assets
23
+ to: assets
24
+ filter:
25
+ - "**/*"
26
+ # Windows taskbar icons (overlay and thumbnail toolbar)
27
+ - from: build
28
+ to: build
29
+ filter:
30
+ - "overlay-*.png"
31
+ - "toolbar-*.png"
32
+
33
+ # =============================================================================
34
+ # macOS Configuration
35
+ # =============================================================================
36
+ mac:
37
+ category: public.app-category.productivity
38
+ icon: build/icon.icns
39
+ hardenedRuntime: true
40
+ gatekeeperAssess: false
41
+ entitlements: build/entitlements.mac.plist
42
+ entitlementsInherit: build/entitlements.mac.inherit.plist
43
+ # Hide from dock and Cmd+Tab - pure menu bar app
44
+ extendInfo:
45
+ LSUIElement: true
46
+ target:
47
+ - target: dmg
48
+ arch:
49
+ - x64
50
+ - arm64
51
+ - target: zip
52
+ arch:
53
+ - x64
54
+ - arm64
55
+
56
+ # =============================================================================
57
+ # DMG Installer Configuration
58
+ # =============================================================================
59
+ dmg:
60
+ background: build/dmg-background.png
61
+ iconSize: 100
62
+ iconTextSize: 12
63
+ window:
64
+ width: 660
65
+ height: 400
66
+ contents:
67
+ - x: 180
68
+ y: 170
69
+ type: file
70
+ - x: 480
71
+ y: 170
72
+ type: link
73
+ path: /Applications
74
+ title: "Install markupr"
75
+ artifactName: "markupr-${version}-${arch}.dmg"
76
+
77
+ # =============================================================================
78
+ # Windows Configuration
79
+ # =============================================================================
80
+ win:
81
+ icon: build/icon.ico
82
+ target:
83
+ - target: nsis
84
+ arch: [x64]
85
+ - target: portable
86
+ arch: [x64]
87
+ publisherName: "markupr"
88
+ verifyUpdateCodeSignature: false
89
+ # File associations
90
+ fileAssociations:
91
+ - ext: markupr
92
+ name: markupr Session
93
+ description: markupr feedback session file
94
+ icon: build/icon.ico
95
+ role: Editor
96
+
97
+ nsis:
98
+ oneClick: false
99
+ perMachine: true
100
+ allowElevation: true
101
+ allowToChangeInstallationDirectory: true
102
+ installerIcon: build/icon.ico
103
+ uninstallerIcon: build/icon.ico
104
+ installerHeader: build/installer-header.bmp
105
+ installerSidebar: build/installer-sidebar.bmp
106
+ license: LICENSE
107
+ createDesktopShortcut: true
108
+ createStartMenuShortcut: true
109
+ shortcutName: "markupr"
110
+ artifactName: "markupr-Setup-${version}.exe"
111
+ include: build/installer.nsh
112
+ deleteAppDataOnUninstall: false
113
+
114
+ # =============================================================================
115
+ # Linux Configuration (for future use)
116
+ # =============================================================================
117
+ linux:
118
+ target:
119
+ - target: AppImage
120
+ arch:
121
+ - x64
122
+ - target: deb
123
+ arch:
124
+ - x64
125
+ category: Development
126
+ icon: build/icons
127
+
128
+ # =============================================================================
129
+ # Code Signing & Notarization
130
+ # =============================================================================
131
+ afterSign: scripts/notarize.cjs
132
+
133
+ # =============================================================================
134
+ # Publishing Configuration
135
+ # =============================================================================
136
+ publish:
137
+ provider: github
138
+ owner: eddiesanjuan
139
+ repo: markupr
140
+ releaseType: release
@@ -0,0 +1,63 @@
1
+ import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import { resolve } from 'path'
4
+
5
+ export default defineConfig({
6
+ main: {
7
+ plugins: [externalizeDepsPlugin()],
8
+ build: {
9
+ outDir: 'dist/main',
10
+ lib: {
11
+ entry: resolve(__dirname, 'src/main/index.ts'),
12
+ formats: ['es']
13
+ },
14
+ rollupOptions: {
15
+ input: {
16
+ index: resolve(__dirname, 'src/main/index.ts')
17
+ },
18
+ output: {
19
+ format: 'es',
20
+ entryFileNames: '[name].mjs'
21
+ }
22
+ }
23
+ }
24
+ },
25
+ preload: {
26
+ plugins: [externalizeDepsPlugin()],
27
+ build: {
28
+ outDir: 'dist/preload',
29
+ lib: {
30
+ entry: resolve(__dirname, 'src/preload/index.ts'),
31
+ formats: ['es']
32
+ },
33
+ rollupOptions: {
34
+ input: {
35
+ index: resolve(__dirname, 'src/preload/index.ts')
36
+ },
37
+ output: {
38
+ format: 'es',
39
+ entryFileNames: '[name].mjs'
40
+ }
41
+ }
42
+ }
43
+ },
44
+ renderer: {
45
+ root: 'src/renderer',
46
+ build: {
47
+ outDir: 'dist/renderer',
48
+ rollupOptions: {
49
+ input: {
50
+ index: resolve(__dirname, 'src/renderer/index.html')
51
+ }
52
+ }
53
+ },
54
+ plugins: [react()],
55
+ resolve: {
56
+ alias: {
57
+ '@': resolve(__dirname, 'src'),
58
+ '@renderer': resolve(__dirname, 'src/renderer'),
59
+ '@shared': resolve(__dirname, 'src/shared')
60
+ }
61
+ }
62
+ }
63
+ })
package/package.json ADDED
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "markupr",
3
+ "version": "2.1.8",
4
+ "description": "AI-ready developer feedback capture tool with voice narration and intelligent screenshots",
5
+ "type": "module",
6
+ "main": "dist/main/index.mjs",
7
+ "author": "Eddie San Juan",
8
+ "license": "MIT",
9
+ "homepage": "https://markupr.com",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/eddiesanjuan/markupr.git"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/eddiesanjuan/markupr/issues"
16
+ },
17
+ "keywords": [
18
+ "markupr",
19
+ "feedback",
20
+ "voice",
21
+ "transcription",
22
+ "screenshot",
23
+ "electron",
24
+ "ai",
25
+ "developer-tools",
26
+ "menu-bar",
27
+ "macos",
28
+ "windows",
29
+ "whisper"
30
+ ],
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "scripts": {
35
+ "postinstall": "node scripts/postinstall.mjs",
36
+ "rebuild": "electron-rebuild",
37
+ "dev": "electron-vite dev",
38
+ "build": "node scripts/build.mjs",
39
+ "start": "node site/server.js",
40
+ "build:desktop": "electron-vite build",
41
+ "preview": "electron-vite preview",
42
+ "package": "electron-builder --config electron-builder.yml",
43
+ "package:mac": "electron-builder --mac --config electron-builder.yml",
44
+ "package:mac:unsigned": "CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --mac --config electron-builder.yml",
45
+ "package:win": "electron-builder --win --config electron-builder.yml",
46
+ "dist:mac": "npm run build && electron-builder --mac --config electron-builder.yml",
47
+ "dist:mac:universal": "npm run build && electron-builder --mac --universal --config electron-builder.yml",
48
+ "dist:mac:x64": "npm run build && electron-builder --mac --x64 --config electron-builder.yml",
49
+ "dist:mac:arm64": "npm run build && electron-builder --mac --arm64 --config electron-builder.yml",
50
+ "dist:win": "electron-builder --win",
51
+ "dist:win:portable": "electron-builder --win portable",
52
+ "dist:win:nsis": "electron-builder --win nsis",
53
+ "package:linux": "electron-builder --linux --config electron-builder.yml",
54
+ "release": "electron-builder --publish always --config electron-builder.yml",
55
+ "test": "vitest",
56
+ "test:unit": "vitest tests/unit",
57
+ "test:integration": "vitest tests/integration",
58
+ "test:e2e": "vitest tests/e2e",
59
+ "test:ci": "vitest run --coverage",
60
+ "test:coverage": "vitest --coverage",
61
+ "test:watch": "vitest --watch",
62
+ "test:ui": "vitest --ui",
63
+ "lint": "eslint src --ext .ts,.tsx",
64
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
65
+ "audit": "npm audit --omit=dev --audit-level=high",
66
+ "setup:markupr": "bash ./scripts/setup-markupr.sh",
67
+ "typecheck": "tsc --noEmit",
68
+ "generate:icons": "node scripts/generate-icons.mjs",
69
+ "generate:tray-icons": "node scripts/generate-tray-icons.mjs",
70
+ "generate:installer-images": "node scripts/generate-installer-images.cjs",
71
+ "prebuild:win": "npm run generate:installer-images"
72
+ },
73
+ "devDependencies": {
74
+ "@electron/notarize": "^2.2.0",
75
+ "@electron/rebuild": "^4.0.3",
76
+ "@types/node": "^20.10.0",
77
+ "@types/react": "^18.2.0",
78
+ "@types/react-dom": "^18.2.0",
79
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
80
+ "@typescript-eslint/parser": "^6.0.0",
81
+ "@vitejs/plugin-react": "^5.1.3",
82
+ "@vitest/coverage-v8": "^1.6.1",
83
+ "electron": "^28.0.0",
84
+ "electron-builder": "^24.0.0",
85
+ "electron-vite": "^2.0.0",
86
+ "eslint": "^8.0.0",
87
+ "eslint-plugin-react": "^7.0.0",
88
+ "eslint-plugin-react-hooks": "^4.0.0",
89
+ "png2icons": "^2.0.1",
90
+ "sharp": "^0.34.5",
91
+ "typescript": "^5.3.0",
92
+ "vite": "^5.0.0",
93
+ "vitest": "^1.0.0"
94
+ },
95
+ "dependencies": {
96
+ "@anthropic-ai/sdk": "^0.73.0",
97
+ "electron-log": "^5.4.3",
98
+ "electron-store": "^11.0.2",
99
+ "electron-updater": "^6.7.3",
100
+ "keytar": "^7.9.0",
101
+ "react": "^18.2.0",
102
+ "react-dom": "^18.2.0",
103
+ "whisper-node": "^1.1.1"
104
+ },
105
+ "build": {
106
+ "extends": null
107
+ }
108
+ }
package/railway.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://railway.com/railway.schema.json",
3
+ "build": {
4
+ "builder": "NIXPACKS"
5
+ },
6
+ "deploy": {
7
+ "startCommand": "node site/server.js",
8
+ "healthcheckPath": "/",
9
+ "restartPolicyType": "ON_FAILURE",
10
+ "restartPolicyMaxRetries": 3
11
+ }
12
+ }
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from 'node:child_process';
4
+ import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';
5
+ import { dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const repoRoot = join(__dirname, '..');
10
+ const siteDir = join(repoRoot, 'site');
11
+ const distDir = join(repoRoot, 'dist');
12
+
13
+ function isRailwayEnvironment() {
14
+ return Object.keys(process.env).some((key) => key.startsWith('RAILWAY_'));
15
+ }
16
+
17
+ function run(command, args) {
18
+ const result = spawnSync(command, args, {
19
+ stdio: 'inherit',
20
+ env: process.env,
21
+ cwd: repoRoot,
22
+ shell: true,
23
+ });
24
+ if (result.status !== 0) {
25
+ process.exit(result.status ?? 1);
26
+ }
27
+ }
28
+
29
+ if (!isRailwayEnvironment()) {
30
+ run('npx', ['electron-vite', 'build']);
31
+ process.exit(0);
32
+ }
33
+
34
+ console.log('[build] Railway environment detected. Building landing page artifact from /site.');
35
+ rmSync(distDir, { recursive: true, force: true });
36
+ mkdirSync(distDir, { recursive: true });
37
+
38
+ const sourceIndex = join(siteDir, 'index.html');
39
+ if (!existsSync(sourceIndex)) {
40
+ console.error('[build] Missing site/index.html; cannot produce landing artifact.');
41
+ process.exit(1);
42
+ }
43
+
44
+ cpSync(sourceIndex, join(distDir, 'index.html'));
45
+
46
+ const optionalAssetsDir = join(siteDir, 'assets');
47
+ if (existsSync(optionalAssetsDir)) {
48
+ cpSync(optionalAssetsDir, join(distDir, 'assets'), { recursive: true });
49
+ }
50
+
51
+ console.log('[build] Landing page artifact ready at /dist/index.html');
@@ -0,0 +1,314 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * markupr Icon Generation Script
4
+ *
5
+ * Generates all app icons and brand assets from SVG sources using sharp.
6
+ *
7
+ * Usage: node scripts/generate-icons.mjs
8
+ */
9
+
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import { fileURLToPath } from 'url';
13
+ import { execSync } from 'child_process';
14
+ import sharp from 'sharp';
15
+
16
+ // Get __dirname equivalent in ES modules
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.dirname(__filename);
19
+
20
+ // Paths
21
+ const PROJECT_ROOT = path.join(__dirname, '..');
22
+ const SVG_SOURCE_DIR = path.join(PROJECT_ROOT, 'assets', 'svg-source');
23
+ const BUILD_DIR = path.join(PROJECT_ROOT, 'build');
24
+ const ASSETS_DIR = path.join(PROJECT_ROOT, 'assets');
25
+ const RENDERER_ASSETS_DIR = path.join(PROJECT_ROOT, 'src', 'renderer', 'assets');
26
+
27
+ // Ensure directories exist
28
+ [BUILD_DIR, ASSETS_DIR, RENDERER_ASSETS_DIR, SVG_SOURCE_DIR].forEach((dir) => {
29
+ if (!fs.existsSync(dir)) {
30
+ fs.mkdirSync(dir, { recursive: true });
31
+ }
32
+ });
33
+
34
+ // Tray icon sizes
35
+ const TRAY_SIZES = { normal: 22, retina: 44 };
36
+
37
+ /**
38
+ * Convert SVG to PNG at specified size using sharp
39
+ */
40
+ async function svgToPng(svgPath, outputPath, width, height = width) {
41
+ const svgBuffer = fs.readFileSync(svgPath);
42
+
43
+ await sharp(svgBuffer)
44
+ .resize(width, height, {
45
+ fit: 'contain',
46
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
47
+ })
48
+ .png()
49
+ .toFile(outputPath);
50
+
51
+ console.log(` Generated: ${path.basename(outputPath)} (${width}x${height})`);
52
+ }
53
+
54
+ /**
55
+ * Generate main app icon in all sizes
56
+ */
57
+ async function generateAppIcon() {
58
+ console.log('\n=== Generating App Icon ===');
59
+
60
+ const svgPath = path.join(SVG_SOURCE_DIR, 'icon.svg');
61
+
62
+ if (!fs.existsSync(svgPath)) {
63
+ console.error('Error: icon.svg not found in assets/svg-source/');
64
+ return false;
65
+ }
66
+
67
+ // Generate master 1024x1024 PNG
68
+ const masterPath = path.join(BUILD_DIR, 'icon.png');
69
+ await svgToPng(svgPath, masterPath, 1024);
70
+
71
+ // Generate individual sizes for iconset
72
+ const iconsetDir = path.join(BUILD_DIR, 'icon.iconset');
73
+ if (fs.existsSync(iconsetDir)) {
74
+ fs.rmSync(iconsetDir, { recursive: true });
75
+ }
76
+ fs.mkdirSync(iconsetDir, { recursive: true });
77
+
78
+ // macOS iconset naming convention
79
+ const macOsSizes = [
80
+ { size: 16, suffix: '16x16' },
81
+ { size: 32, suffix: '16x16@2x' },
82
+ { size: 32, suffix: '32x32' },
83
+ { size: 64, suffix: '32x32@2x' },
84
+ { size: 128, suffix: '128x128' },
85
+ { size: 256, suffix: '128x128@2x' },
86
+ { size: 256, suffix: '256x256' },
87
+ { size: 512, suffix: '256x256@2x' },
88
+ { size: 512, suffix: '512x512' },
89
+ { size: 1024, suffix: '512x512@2x' },
90
+ ];
91
+
92
+ for (const { size, suffix } of macOsSizes) {
93
+ const outputPath = path.join(iconsetDir, `icon_${suffix}.png`);
94
+ await svgToPng(svgPath, outputPath, size);
95
+ }
96
+
97
+ // Generate .icns using iconutil (macOS only)
98
+ const icnsPath = path.join(BUILD_DIR, 'icon.icns');
99
+ if (process.platform === 'darwin') {
100
+ try {
101
+ execSync(`iconutil -c icns "${iconsetDir}" -o "${icnsPath}"`);
102
+ console.log(` Generated: icon.icns`);
103
+ } catch (error) {
104
+ console.error(' Warning: Could not generate .icns (iconutil failed)');
105
+ }
106
+ } else {
107
+ console.log(' Skipping .icns generation (not on macOS)');
108
+ }
109
+
110
+ // Generate Windows .ico
111
+ await generateWindowsIcon(svgPath);
112
+
113
+ return true;
114
+ }
115
+
116
+ /**
117
+ * Generate Windows .ico file by creating a multi-size PNG fallback
118
+ */
119
+ async function generateWindowsIcon(svgPath) {
120
+ console.log('\n=== Generating Windows Icon Assets ===');
121
+
122
+ const sizes = [16, 24, 32, 48, 64, 128, 256];
123
+
124
+ for (const size of sizes) {
125
+ const outputPath = path.join(BUILD_DIR, `icon-${size}.png`);
126
+ await svgToPng(svgPath, outputPath, size);
127
+ }
128
+
129
+ // Try to use png2icons if available
130
+ try {
131
+ const png2icons = await import('png2icons');
132
+ const input = fs.readFileSync(path.join(BUILD_DIR, 'icon.png'));
133
+ const output = png2icons.default.createICO(input, png2icons.default.BICUBIC2, 0, true, true);
134
+ fs.writeFileSync(path.join(BUILD_DIR, 'icon.ico'), output);
135
+ console.log(` Generated: icon.ico`);
136
+ } catch {
137
+ console.log(' Note: png2icons not installed. Windows icon sizes generated as PNGs.');
138
+ console.log(' Run: npm install --save-dev png2icons');
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Generate tray icons for all states
144
+ */
145
+ async function generateTrayIcons() {
146
+ console.log('\n=== Generating Tray Icons ===');
147
+
148
+ const states = ['tray-icon', 'tray-icon-recording', 'tray-icon-processing'];
149
+
150
+ for (const state of states) {
151
+ const svgPath = path.join(SVG_SOURCE_DIR, `${state}.svg`);
152
+
153
+ if (!fs.existsSync(svgPath)) {
154
+ console.log(` Skipping ${state}.svg (not found)`);
155
+ continue;
156
+ }
157
+
158
+ // Generate normal size (22x22)
159
+ const normalPath = path.join(ASSETS_DIR, `${state}.png`);
160
+ await svgToPng(svgPath, normalPath, TRAY_SIZES.normal);
161
+
162
+ // Generate Template version (for macOS auto-tinting)
163
+ const templatePath = path.join(ASSETS_DIR, `${state}Template.png`);
164
+ await svgToPng(svgPath, templatePath, TRAY_SIZES.normal);
165
+
166
+ // Generate @2x retina versions
167
+ const retina2xPath = path.join(ASSETS_DIR, `${state}@2x.png`);
168
+ await svgToPng(svgPath, retina2xPath, TRAY_SIZES.retina);
169
+
170
+ const template2xPath = path.join(ASSETS_DIR, `${state}Template@2x.png`);
171
+ await svgToPng(svgPath, template2xPath, TRAY_SIZES.retina);
172
+ }
173
+
174
+ // Generate processing animation frames
175
+ await generateProcessingFrames();
176
+ }
177
+
178
+ /**
179
+ * Generate processing animation frames
180
+ */
181
+ async function generateProcessingFrames() {
182
+ console.log('\n=== Generating Processing Animation Frames ===');
183
+
184
+ const baseSvgPath = path.join(SVG_SOURCE_DIR, 'tray-icon-processing.svg');
185
+
186
+ if (!fs.existsSync(baseSvgPath)) {
187
+ console.log(' Skipping processing frames (SVG not found)');
188
+ return;
189
+ }
190
+
191
+ const baseSvg = fs.readFileSync(baseSvgPath, 'utf8');
192
+
193
+ // Generate 4 frames with rotated spinner
194
+ for (let frame = 0; frame < 4; frame++) {
195
+ const rotation = frame * 90;
196
+
197
+ // Modify SVG to rotate the spinner
198
+ const frameSvg = baseSvg.replace(
199
+ 'stroke-dasharray="10 6"',
200
+ `stroke-dasharray="10 6" transform="rotate(${rotation}, 16, 5)"`
201
+ );
202
+
203
+ const tempSvgPath = path.join(SVG_SOURCE_DIR, `tray-processing-frame-${frame}.svg`);
204
+ fs.writeFileSync(tempSvgPath, frameSvg);
205
+
206
+ // Generate PNGs
207
+ const normalPath = path.join(ASSETS_DIR, `tray-processing-${frame}.png`);
208
+ const templatePath = path.join(ASSETS_DIR, `tray-processing-${frame}Template.png`);
209
+ const retina2xPath = path.join(ASSETS_DIR, `tray-processing-${frame}@2x.png`);
210
+ const template2xPath = path.join(ASSETS_DIR, `tray-processing-${frame}Template@2x.png`);
211
+
212
+ await svgToPng(tempSvgPath, normalPath, TRAY_SIZES.normal);
213
+ await svgToPng(tempSvgPath, templatePath, TRAY_SIZES.normal);
214
+ await svgToPng(tempSvgPath, retina2xPath, TRAY_SIZES.retina);
215
+ await svgToPng(tempSvgPath, template2xPath, TRAY_SIZES.retina);
216
+
217
+ // Cleanup temp SVG
218
+ fs.unlinkSync(tempSvgPath);
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Generate DMG background images
224
+ */
225
+ async function generateDmgBackground() {
226
+ console.log('\n=== Generating DMG Background ===');
227
+
228
+ const svgPath = path.join(SVG_SOURCE_DIR, 'dmg-background.svg');
229
+
230
+ if (!fs.existsSync(svgPath)) {
231
+ console.log(' Skipping DMG background (SVG not found)');
232
+ return;
233
+ }
234
+
235
+ // Standard resolution (660x400)
236
+ const normalPath = path.join(BUILD_DIR, 'dmg-background.png');
237
+ await svgToPng(svgPath, normalPath, 660, 400);
238
+
239
+ // Retina resolution (1320x800)
240
+ const retinaPath = path.join(BUILD_DIR, 'dmg-background@2x.png');
241
+ await svgToPng(svgPath, retinaPath, 1320, 800);
242
+ }
243
+
244
+ /**
245
+ * Check logo SVGs exist
246
+ */
247
+ async function checkLogos() {
248
+ console.log('\n=== Checking Logo SVGs ===');
249
+
250
+ const logos = ['logo.svg', 'logo-dark.svg'];
251
+
252
+ for (const logo of logos) {
253
+ const srcPath = path.join(RENDERER_ASSETS_DIR, logo);
254
+ if (fs.existsSync(srcPath)) {
255
+ console.log(` Found: ${logo}`);
256
+ } else {
257
+ console.log(` Missing: ${logo}`);
258
+ }
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Generate favicons for web use
264
+ */
265
+ async function generateFavicons() {
266
+ console.log('\n=== Generating Favicons ===');
267
+
268
+ const svgPath = path.join(SVG_SOURCE_DIR, 'icon.svg');
269
+
270
+ if (!fs.existsSync(svgPath)) {
271
+ return;
272
+ }
273
+
274
+ const sizes = [16, 32, 48, 64, 180, 192, 512];
275
+
276
+ for (const size of sizes) {
277
+ const outputPath = path.join(BUILD_DIR, `favicon-${size}.png`);
278
+ await svgToPng(svgPath, outputPath, size);
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Main execution
284
+ */
285
+ async function main() {
286
+ console.log('=========================================');
287
+ console.log(' markupr Icon Generator (sharp)');
288
+ console.log('=========================================');
289
+
290
+ try {
291
+ await generateAppIcon();
292
+ await generateTrayIcons();
293
+ await generateDmgBackground();
294
+ await checkLogos();
295
+ await generateFavicons();
296
+
297
+ console.log('\n=========================================');
298
+ console.log(' Icon generation complete!');
299
+ console.log('=========================================\n');
300
+
301
+ console.log('Generated files:');
302
+ console.log(' build/icon.png - Master app icon (1024x1024)');
303
+ console.log(' build/icon.icns - macOS icon bundle');
304
+ console.log(' build/icon-*.png - Windows icon sizes');
305
+ console.log(' build/dmg-background.png - DMG installer background');
306
+ console.log(' assets/tray-*.png - Menu bar tray icons');
307
+ console.log(' src/renderer/assets/ - In-app logo SVGs');
308
+ } catch (error) {
309
+ console.error('\nError during icon generation:', error);
310
+ process.exit(1);
311
+ }
312
+ }
313
+
314
+ main();