@sutrata/editor 0.1.1 → 0.2.0

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 (268) hide show
  1. package/README.md +87 -0
  2. package/dist/ai/VoiceConfirmDialog.d.ts +1 -0
  3. package/dist/ai/VoiceConfirmDialog.js +6 -6
  4. package/dist/ai/VoiceToolbar.d.ts +1 -0
  5. package/dist/ai/VoiceToolbar.js +22 -16
  6. package/dist/ai/clean-response.d.ts +7 -0
  7. package/dist/ai/clean-response.js +58 -0
  8. package/dist/ai/format-transcript.d.ts +3 -0
  9. package/dist/ai/format-transcript.js +7 -0
  10. package/dist/ai/prompts.d.ts +8 -1
  11. package/dist/ai/prompts.js +34 -7
  12. package/dist/autocomplete/suggestions.js +1 -1
  13. package/dist/context/DocumentContext.d.ts +28 -4
  14. package/dist/context/DocumentContext.js +67 -37
  15. package/dist/editor/EditorView.js +32 -4
  16. package/dist/editor/SelectionMenu.js +5 -3
  17. package/dist/editor/external-decorations-plugin.d.ts +23 -0
  18. package/dist/editor/external-decorations-plugin.js +151 -0
  19. package/dist/editor/omitted-scene-plugin.d.ts +9 -0
  20. package/dist/editor/omitted-scene-plugin.js +44 -0
  21. package/dist/editor/plugins.js +4 -0
  22. package/dist/editor/private-metadata-plugin.d.ts +10 -0
  23. package/dist/editor/private-metadata-plugin.js +60 -0
  24. package/dist/editor/prosemirror-to-sutra.js +179 -74
  25. package/dist/editor/scene-heading-view.js +2 -0
  26. package/dist/editor/schema.js +69 -12
  27. package/dist/editor/sutra-to-prosemirror.d.ts +2 -0
  28. package/dist/editor/sutra-to-prosemirror.js +32 -34
  29. package/dist/extensions/ai-provider.d.ts +44 -0
  30. package/dist/extensions/ai-provider.js +27 -0
  31. package/dist/extensions/collab.d.ts +21 -0
  32. package/dist/extensions/collab.js +6 -0
  33. package/dist/extensions/command-registry.d.ts +49 -0
  34. package/dist/extensions/command-registry.js +28 -0
  35. package/dist/extensions/decorations.d.ts +48 -0
  36. package/dist/extensions/decorations.js +6 -0
  37. package/dist/extensions/export-registry.d.ts +59 -0
  38. package/dist/extensions/export-registry.js +10 -0
  39. package/dist/extensions/panel-registry.d.ts +30 -0
  40. package/dist/extensions/panel-registry.js +16 -0
  41. package/dist/extensions/registries.d.ts +15 -0
  42. package/dist/extensions/registries.js +12 -0
  43. package/dist/extensions/registry-store.d.ts +26 -0
  44. package/dist/extensions/registry-store.js +35 -0
  45. package/dist/extensions/session.d.ts +29 -0
  46. package/dist/extensions/session.js +20 -0
  47. package/dist/extensions/speech-provider.d.ts +35 -0
  48. package/dist/extensions/speech-provider.js +17 -0
  49. package/dist/file/builtin-exporters.d.ts +9 -0
  50. package/dist/file/builtin-exporters.js +72 -0
  51. package/dist/file/docx-exporter.js +7 -4
  52. package/dist/file/docx-importer.d.ts +9 -0
  53. package/dist/file/docx-importer.js +47 -19
  54. package/dist/file/scene-number.d.ts +5 -0
  55. package/dist/file/scene-number.js +8 -0
  56. package/dist/file/workflow-reports.js +13 -7
  57. package/dist/findreplace/FindReplace.js +5 -2
  58. package/dist/import/AIImportDialog.d.ts +11 -0
  59. package/dist/import/AIImportDialog.js +112 -0
  60. package/dist/import/ai-import.d.ts +51 -0
  61. package/dist/import/ai-import.js +200 -0
  62. package/dist/import/apply-import.d.ts +7 -0
  63. package/dist/import/apply-import.js +35 -0
  64. package/dist/import/extract.d.ts +17 -0
  65. package/dist/import/extract.js +18 -0
  66. package/dist/index.d.ts +17 -2
  67. package/dist/index.js +7 -0
  68. package/dist/locales/bn.json +8 -0
  69. package/dist/locales/en.json +8 -0
  70. package/dist/locales/gu.json +8 -0
  71. package/dist/locales/hi.json +8 -0
  72. package/dist/locales/kn.json +8 -0
  73. package/dist/locales/ml.json +8 -0
  74. package/dist/locales/mr.json +8 -0
  75. package/dist/locales/or.json +8 -0
  76. package/dist/locales/pa.json +8 -0
  77. package/dist/locales/si.json +8 -0
  78. package/dist/locales/ta.json +8 -0
  79. package/dist/locales/te.json +8 -0
  80. package/dist/navigator/SceneNavigator.js +125 -131
  81. package/dist/navigator/StatisticsDialog.js +5 -1
  82. package/dist/navigator/scene-edits.d.ts +18 -0
  83. package/dist/navigator/scene-edits.js +143 -0
  84. package/dist/navigator/scene-list.js +4 -4
  85. package/dist/navigator/scene-numbering.d.ts +37 -0
  86. package/dist/navigator/scene-numbering.js +88 -0
  87. package/dist/settings/SettingsDialog.js +8 -120
  88. package/dist/shell/AppBar.js +21 -2
  89. package/dist/shell/AppShell.js +18 -4
  90. package/dist/shell/ElementToolbar.d.ts +5 -0
  91. package/dist/shell/ElementToolbar.js +35 -25
  92. package/dist/shell/LanguageStatus.js +6 -0
  93. package/dist/shell/StatusBar.js +11 -6
  94. package/dist/shell/builtin-commands.d.ts +10 -0
  95. package/dist/shell/builtin-commands.js +43 -0
  96. package/dist/shell/icons.d.ts +6 -0
  97. package/dist/shell/icons.js +6 -0
  98. package/dist/shell/use-commands.d.ts +7 -0
  99. package/dist/shell/use-commands.js +24 -0
  100. package/dist/shell/use-panel-context.d.ts +3 -0
  101. package/dist/shell/use-panel-context.js +39 -0
  102. package/dist/source/SourceView.js +18 -1
  103. package/dist/styles/screenplay.css +113 -1
  104. package/dist/titlepage/ExportDialog.d.ts +5 -0
  105. package/dist/titlepage/ExportDialog.js +59 -96
  106. package/package.json +32 -5
  107. package/dist/ai/OnboardingDialog.d.ts +0 -6
  108. package/dist/ai/OnboardingDialog.js +0 -115
  109. package/dist/ai/ai-client.d.ts +0 -71
  110. package/dist/ai/ai-client.js +0 -494
  111. package/dist/ai/generated-providers.json +0 -3696
  112. package/dist/ai/voice-service.d.ts +0 -15
  113. package/dist/ai/voice-service.js +0 -81
  114. package/dist/editor/character-view.d.ts +0 -35
  115. package/dist/editor/character-view.js +0 -112
  116. package/dist/editor/transliterate-input.d.ts +0 -10
  117. package/dist/editor/transliterate-input.js +0 -88
  118. package/dist/extensions/types.d.ts +0 -73
  119. package/dist/extensions/types.js +0 -12
  120. package/scripts/copy-assets.mjs +0 -16
  121. package/scripts/generate-providers.mjs +0 -127
  122. package/src/ai/OnboardingDialog.tsx +0 -390
  123. package/src/ai/VoiceConfirmDialog.tsx +0 -137
  124. package/src/ai/VoiceToolbar.tsx +0 -321
  125. package/src/ai/ai-client.ts +0 -596
  126. package/src/ai/commands.ts +0 -164
  127. package/src/ai/generated-providers.json +0 -3696
  128. package/src/ai/prompts.ts +0 -62
  129. package/src/ai/voice-service.ts +0 -96
  130. package/src/autocomplete/AutocompletePlugin.ts +0 -21
  131. package/src/autocomplete/suggestions.ts +0 -147
  132. package/src/context/DocumentContext.tsx +0 -648
  133. package/src/desktop-api.d.ts +0 -40
  134. package/src/editor/EditorView.tsx +0 -82
  135. package/src/editor/SelectionMenu.tsx +0 -152
  136. package/src/editor/attr-pencil-plugin.ts +0 -172
  137. package/src/editor/character-decoration-plugin.ts +0 -104
  138. package/src/editor/editor-bus.ts +0 -51
  139. package/src/editor/find-highlight-plugin.ts +0 -68
  140. package/src/editor/frontmatter-field-view.ts +0 -52
  141. package/src/editor/frontmatter-field.ts +0 -115
  142. package/src/editor/grapheme-cursor.ts +0 -99
  143. package/src/editor/ime-plugin.ts +0 -85
  144. package/src/editor/insert-helper.ts +0 -43
  145. package/src/editor/keymap.ts +0 -124
  146. package/src/editor/language-class-plugin.ts +0 -91
  147. package/src/editor/plugins.ts +0 -26
  148. package/src/editor/prosemirror-to-sutra.ts +0 -192
  149. package/src/editor/scene-heading-view.ts +0 -147
  150. package/src/editor/schema.ts +0 -156
  151. package/src/editor/sutra-to-prosemirror.ts +0 -156
  152. package/src/extensions/storage-adapter.ts +0 -65
  153. package/src/extensions/types.ts +0 -60
  154. package/src/file/docx-exporter.ts +0 -585
  155. package/src/file/docx-importer.ts +0 -313
  156. package/src/file/print-paginator.ts +0 -301
  157. package/src/file/templates.ts +0 -73
  158. package/src/file/workflow-reports.ts +0 -820
  159. package/src/findreplace/FindReplace.tsx +0 -242
  160. package/src/findreplace/find-engine.ts +0 -97
  161. package/src/findreplace/scroll-to-match.ts +0 -89
  162. package/src/fonts/tofu-detect.ts +0 -53
  163. package/src/i18n/LanguageContext.tsx +0 -207
  164. package/src/i18n/language-detect.ts +0 -73
  165. package/src/i18n/useTranslation.tsx +0 -74
  166. package/src/index.ts +0 -27
  167. package/src/locales/bn.json +0 -143
  168. package/src/locales/en.json +0 -143
  169. package/src/locales/gu.json +0 -143
  170. package/src/locales/hi.json +0 -143
  171. package/src/locales/kn.json +0 -143
  172. package/src/locales/ml.json +0 -143
  173. package/src/locales/mr.json +0 -143
  174. package/src/locales/or.json +0 -143
  175. package/src/locales/pa.json +0 -143
  176. package/src/locales/si.json +0 -143
  177. package/src/locales/ta.json +0 -143
  178. package/src/locales/te.json +0 -143
  179. package/src/navigator/SceneNavigator.tsx +0 -844
  180. package/src/navigator/StatisticsDialog.tsx +0 -249
  181. package/src/navigator/scene-list.ts +0 -84
  182. package/src/settings/SettingsDialog.tsx +0 -303
  183. package/src/shell/AppBar.tsx +0 -354
  184. package/src/shell/AppShell.tsx +0 -71
  185. package/src/shell/ConfirmDialog.tsx +0 -71
  186. package/src/shell/ElementToolbar.tsx +0 -175
  187. package/src/shell/LanguageStatus.tsx +0 -101
  188. package/src/shell/StatusBar.tsx +0 -135
  189. package/src/shell/SutrataLogo.tsx +0 -89
  190. package/src/shell/Toast.tsx +0 -46
  191. package/src/shell/ToolbarButton.tsx +0 -30
  192. package/src/shell/VersionHistory.tsx +0 -212
  193. package/src/shell/Watermark.tsx +0 -9
  194. package/src/shell/fonts/fonts.css +0 -1133
  195. package/src/shell/icons.tsx +0 -335
  196. package/src/shell/toolbar-actions.ts +0 -59
  197. package/src/source/SourceView.tsx +0 -111
  198. package/src/source/find-highlight-source.ts +0 -57
  199. package/src/source/sutra-lang.ts +0 -121
  200. package/src/spellcheck/dictionaries.ts +0 -21
  201. package/src/spellcheck/hunspell.ts +0 -110
  202. package/src/spellcheck/spellcheck-plugin.ts +0 -83
  203. package/src/styles/StyleDialog.tsx +0 -148
  204. package/src/styles/builtin-styles.ts +0 -139
  205. package/src/styles/css-adapter.ts +0 -76
  206. package/src/styles/docx-adapter.ts +0 -109
  207. package/src/styles/embed-fonts.ts +0 -81
  208. package/src/styles/pagination.ts +0 -27
  209. package/src/styles/print-adapter.ts +0 -288
  210. package/src/styles/registry.ts +0 -20
  211. package/src/styles/screenplay.css +0 -3006
  212. package/src/styles/script-ranges.ts +0 -17
  213. package/src/styles/types.ts +0 -104
  214. package/src/styles/validate.ts +0 -114
  215. package/src/templates/templates.ts +0 -194
  216. package/src/titlepage/ExportDialog.tsx +0 -494
  217. package/src/titlepage/TitlePageDialog.tsx +0 -312
  218. package/src/titlepage/frontmatter-form.ts +0 -280
  219. package/src/titlepage/languages.ts +0 -37
  220. package/src/types.ts +0 -7
  221. package/tests/AppBar.test.tsx +0 -35
  222. package/tests/AppShell.test.tsx +0 -22
  223. package/tests/ElementToolbar.test.tsx +0 -36
  224. package/tests/LanguageStatus.test.tsx +0 -129
  225. package/tests/SelectionMenu.test.tsx +0 -71
  226. package/tests/ToolbarButton.test.tsx +0 -24
  227. package/tests/ai-onboarding.test.ts +0 -102
  228. package/tests/ai-status.test.tsx +0 -72
  229. package/tests/ai-structured.test.ts +0 -94
  230. package/tests/autocomplete/AutocompletePlugin.test.ts +0 -20
  231. package/tests/autocomplete/suggestions.test.ts +0 -106
  232. package/tests/document-context.test.tsx +0 -565
  233. package/tests/docx-importer.test.ts +0 -160
  234. package/tests/editor/character-decoration-plugin.test.ts +0 -101
  235. package/tests/editor/character-extension.test.ts +0 -44
  236. package/tests/editor/grapheme-cursor.test.ts +0 -118
  237. package/tests/editor/ime-plugin.test.ts +0 -72
  238. package/tests/editor/inline-note-bridge.test.ts +0 -32
  239. package/tests/editor/language-class-plugin.test.ts +0 -265
  240. package/tests/editor/title-page.test.ts +0 -124
  241. package/tests/embed-fonts.test.ts +0 -17
  242. package/tests/exporters.test.ts +0 -365
  243. package/tests/findreplace/FindReplace.test.tsx +0 -391
  244. package/tests/findreplace/find-engine.test.ts +0 -86
  245. package/tests/findreplace/scroll-to-match.test.ts +0 -50
  246. package/tests/fonts/tofu-detect.test.ts +0 -122
  247. package/tests/i18n/LanguageContext.test.tsx +0 -146
  248. package/tests/i18n/language-detect.test.ts +0 -54
  249. package/tests/i18n/locale-parity.test.ts +0 -25
  250. package/tests/i18n/useTranslation.test.tsx +0 -45
  251. package/tests/keymap.test.ts +0 -18
  252. package/tests/navigator/SceneNavigator.test.tsx +0 -177
  253. package/tests/navigator/StatisticsDialog.test.tsx +0 -63
  254. package/tests/navigator/scene-list.test.ts +0 -71
  255. package/tests/print-paginator.test.ts +0 -82
  256. package/tests/shell/VersionHistory.test.tsx +0 -129
  257. package/tests/spellcheck/hunspell.test.ts +0 -82
  258. package/tests/spellcheck/spellcheck-plugin.test.ts +0 -56
  259. package/tests/styles.test.ts +0 -315
  260. package/tests/templates/templates.test.ts +0 -83
  261. package/tests/titlepage/TitlePageDialog.test.tsx +0 -90
  262. package/tests/titlepage/apply-title-page.test.ts +0 -61
  263. package/tests/titlepage/frontmatter-form.test.ts +0 -115
  264. package/tests/toolbar-actions.test.ts +0 -93
  265. package/tests/voice-commands.test.ts +0 -58
  266. package/tsconfig.json +0 -17
  267. package/vitest.config.ts +0 -11
  268. package/vitest.setup.ts +0 -65
package/package.json CHANGED
@@ -1,10 +1,33 @@
1
1
  {
2
2
  "name": "@sutrata/editor",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
+ "description": "React + ProseMirror screenplay editor for Sutra, with first-class support for Indic and other complex scripts.",
4
5
  "license": "GPL-3.0-or-later",
6
+ "keywords": [
7
+ "sutra",
8
+ "screenplay",
9
+ "editor",
10
+ "prosemirror",
11
+ "react",
12
+ "indic",
13
+ "unicode",
14
+ "fountain"
15
+ ],
16
+ "homepage": "https://github.com/sutrata/sutrata/tree/main/packages/editor#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/sutrata/sutrata.git",
20
+ "directory": "packages/editor"
21
+ },
22
+ "bugs": {
23
+ "url": "https://github.com/sutrata/sutrata/issues"
24
+ },
5
25
  "type": "module",
6
26
  "main": "./dist/index.js",
7
27
  "types": "./dist/index.d.ts",
28
+ "files": [
29
+ "dist"
30
+ ],
8
31
  "dependencies": {
9
32
  "@codemirror/commands": "^6.10.3",
10
33
  "@codemirror/language": "^6.12.3",
@@ -23,9 +46,11 @@
23
46
  "prosemirror-state": "^1.4.3",
24
47
  "prosemirror-transform": "^1.9.0",
25
48
  "prosemirror-view": "^1.33.0",
49
+ "@sutrata/parser": "0.2.0"
50
+ },
51
+ "peerDependencies": {
26
52
  "react": "^18.3.0",
27
- "react-dom": "^18.3.0",
28
- "@sutrata/parser": "0.1.0"
53
+ "react-dom": "^18.3.0"
29
54
  },
30
55
  "devDependencies": {
31
56
  "@testing-library/jest-dom": "^6.9.1",
@@ -34,13 +59,15 @@
34
59
  "@types/react": "^18.3.0",
35
60
  "@types/react-dom": "^18.3.0",
36
61
  "@vitejs/plugin-react": "^4.3.0",
62
+ "fast-check": "^4.10.2",
37
63
  "jsdom": "^29.1.1",
64
+ "react": "^18.3.0",
65
+ "react-dom": "^18.3.0",
38
66
  "typescript": "^5.4.0",
39
67
  "vitest": "^1.6.0"
40
68
  },
41
69
  "scripts": {
42
- "build": "node scripts/generate-providers.mjs && tsc && node scripts/copy-assets.mjs",
43
- "generate:providers": "node scripts/generate-providers.mjs",
70
+ "build": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\" && tsc && node scripts/copy-assets.mjs",
44
71
  "test": "vitest run",
45
72
  "test:watch": "vitest"
46
73
  }
@@ -1,6 +0,0 @@
1
- import React from 'react';
2
- interface Props {
3
- onClose: () => void;
4
- }
5
- export declare function OnboardingDialog({ onClose }: Props): React.JSX.Element;
6
- export {};
@@ -1,115 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef } from 'react';
3
- import { getApiKey, setApiKey, deleteApiKey, getAIConfig, saveAIConfig, fetchProviders, testConnection, listModels } from './ai-client';
4
- import { SparklesIcon } from '../shell/icons';
5
- export function OnboardingDialog({ onClose }) {
6
- const [activeTab, setActiveTab] = useState('intro');
7
- const [providers, setProviders] = useState([]);
8
- const [providerId, setProviderId] = useState('anthropic');
9
- const [keyInput, setKeyInput] = useState('');
10
- const [showKey, setShowKey] = useState(false);
11
- const [testStatus, setTestStatus] = useState('idle');
12
- const [testError, setTestError] = useState('');
13
- const [config, setConfig] = useState(getAIConfig);
14
- // Custom provider state
15
- const [customId, setCustomId] = useState('');
16
- const [customName, setCustomName] = useState('');
17
- const [customBaseUrl, setCustomBaseUrl] = useState('');
18
- const [customModels, setCustomModels] = useState('');
19
- const dialogRef = useRef(null);
20
- useEffect(() => {
21
- void fetchProviders(config).then(setProviders);
22
- // eslint-disable-next-line react-hooks/exhaustive-deps
23
- }, [config.customProviders]);
24
- useEffect(() => {
25
- dialogRef.current?.focus();
26
- void loadKeyForProvider(providerId);
27
- }, [providerId]);
28
- const loadKeyForProvider = async (pid) => {
29
- setTestStatus('idle');
30
- setTestError('');
31
- const key = await getApiKey(pid);
32
- setKeyInput(key || '');
33
- };
34
- const handleTestKey = async () => {
35
- if (!keyInput.trim()) {
36
- setTestStatus('error');
37
- setTestError('Please enter an API key to test.');
38
- return;
39
- }
40
- setTestStatus('testing');
41
- setTestError('');
42
- try {
43
- const ok = await testConnection(providerId, keyInput.trim(), config);
44
- if (ok) {
45
- setTestStatus('success');
46
- }
47
- else {
48
- setTestStatus('error');
49
- setTestError('Connection failed: empty or invalid response from endpoint.');
50
- }
51
- }
52
- catch (e) {
53
- setTestStatus('error');
54
- setTestError(e.message || String(e));
55
- }
56
- };
57
- const handleSaveKey = async () => {
58
- const trimmed = keyInput.trim();
59
- if (trimmed) {
60
- await setApiKey(providerId, trimmed);
61
- const provider = providers.find(p => p.id === providerId);
62
- let preferredModel = provider?.models[0]?.id || '';
63
- if (provider) {
64
- const liveModels = await listModels(provider, trimmed);
65
- preferredModel = liveModels[0]?.id || preferredModel;
66
- }
67
- const updated = { ...config, preferredProvider: providerId, preferredModel };
68
- setConfig(updated);
69
- saveAIConfig(updated);
70
- setTestStatus('success');
71
- }
72
- else {
73
- await deleteApiKey(providerId);
74
- setTestStatus('idle');
75
- }
76
- };
77
- const handleAddCustomProvider = () => {
78
- if (!customId || !customName || !customBaseUrl || !customModels) {
79
- alert('Please fill out all custom provider fields.');
80
- return;
81
- }
82
- const modelsList = customModels.split(',').map(m => {
83
- const parts = m.trim().split(':');
84
- const id = parts[0]?.trim() || '';
85
- const name = parts[1]?.trim() || id;
86
- return { id, name };
87
- }).filter(m => m.id);
88
- const newCustom = {
89
- id: customId.trim().toLowerCase(),
90
- name: customName.trim(),
91
- baseUrl: customBaseUrl.trim(),
92
- models: modelsList,
93
- };
94
- const updated = { ...config };
95
- const index = updated.customProviders.findIndex(p => p.id === newCustom.id);
96
- if (index >= 0) {
97
- updated.customProviders[index] = newCustom;
98
- }
99
- else {
100
- updated.customProviders.push(newCustom);
101
- }
102
- setConfig(updated);
103
- saveAIConfig(updated);
104
- setCustomId('');
105
- setCustomName('');
106
- setCustomBaseUrl('');
107
- setCustomModels('');
108
- alert(`Custom provider "${newCustom.name}" added. You can now configure its key in the API Keys tab.`);
109
- };
110
- const handleFinish = () => {
111
- localStorage.setItem('sutrata_onboarding_completed', 'true');
112
- onClose();
113
- };
114
- return (_jsx("div", { className: "cs-dialog-overlay", onClick: onClose, style: { zIndex: 300 }, children: _jsxs("div", { ref: dialogRef, className: "cs-dialog cs-onboarding-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Intelligence Setup", onClick: e => e.stopPropagation(), tabIndex: -1, children: [_jsxs("div", { className: "cs-dialog-header", children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx(SparklesIcon, { size: 16 }), _jsx("span", { className: "cs-dialog-title", children: "Intelligence & Dictation Setup" })] }), _jsx("button", { type: "button", className: "cs-fr-close", onClick: onClose, "aria-label": "Close", children: "\u00D7" })] }), _jsxs("div", { className: "cs-tabs-header", children: [_jsx("button", { type: "button", className: `cs-tab-btn ${activeTab === 'intro' ? 'active' : ''}`, onClick: () => setActiveTab('intro'), children: "Overview" }), _jsx("button", { type: "button", className: `cs-tab-btn ${activeTab === 'keys' ? 'active' : ''}`, onClick: () => setActiveTab('keys'), children: "API Keys" }), _jsx("button", { type: "button", className: `cs-tab-btn ${activeTab === 'custom' ? 'active' : ''}`, onClick: () => setActiveTab('custom'), children: "Custom Endpoints" })] }), _jsxs("div", { className: "cs-onboarding-body", children: [activeTab === 'intro' && (_jsxs("div", { className: "cs-onboarding-section", children: [_jsx("h3", { className: "cs-onboarding-h3", children: "Client-Side AI Formatting & Voice" }), _jsx("p", { className: "cs-onboarding-desc", children: "Sutrata connects directly from your device to high-performance inference APIs. Your screenplays and audio transcripts are processed strictly with your own API credentials." }), _jsxs("div", { className: "cs-onboarding-card", children: [_jsxs("div", { className: "cs-onboarding-step", children: [_jsx("div", { className: "cs-onboarding-step-num", children: "1" }), _jsxs("div", { children: [_jsx("strong", { children: "Get a Free-Tier Key:" }), " Obtain a free API key from Google AI Studio (Gemini/Gemma) or Groq (Llama 3.3)."] })] }), _jsxs("div", { className: "cs-onboarding-step", children: [_jsx("div", { className: "cs-onboarding-step-num", children: "2" }), _jsxs("div", { children: [_jsx("strong", { children: "Enter Your Key:" }), " Save the key in the API Keys tab. It is encrypted in your local OS keyring or stored securely in your browser session."] })] }), _jsxs("div", { className: "cs-onboarding-step", children: [_jsx("div", { className: "cs-onboarding-step-num", children: "3" }), _jsxs("div", { children: [_jsx("strong", { children: "Start Dictating:" }), " Speak naturally into Sutrata; the formatting engine parses characters, dialogue, and scenes automatically."] })] })] }), _jsx("div", { className: "cs-dialog-actions", style: { display: 'flex', justifyContent: 'flex-end', marginTop: '16px' }, children: _jsx("button", { type: "button", className: "cs-voice-btn-primary", onClick: () => setActiveTab('keys'), children: "Configure API Keys \u2192" }) })] })), activeTab === 'keys' && (_jsxs("div", { className: "cs-onboarding-section", children: [_jsxs("div", { className: "cs-settings-row", style: { marginBottom: '12px' }, children: [_jsx("label", { className: "cs-settings-label", htmlFor: "cs-ob-provider", children: "Active Provider:" }), _jsx("select", { id: "cs-ob-provider", className: "cs-settings-select", value: providerId, onChange: e => setProviderId(e.target.value), children: providers.map(p => (_jsx("option", { value: p.id, children: p.name }, p.id))) })] }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '6px', marginBottom: '16px' }, children: [_jsxs("label", { className: "cs-settings-label", htmlFor: "cs-ob-key", children: ["API Key for ", providerId, ":"] }), _jsxs("div", { style: { display: 'flex', gap: '8px' }, children: [_jsx("input", { id: "cs-ob-key", type: showKey ? 'text' : 'password', className: "cs-voice-textarea", style: { flex: 1, minHeight: '34px', padding: '6px 10px', height: '34px' }, value: keyInput, onChange: e => setKeyInput(e.target.value), placeholder: `Enter ${providerId} API key...` }), _jsx("button", { type: "button", className: "cs-voice-btn-ghost", onClick: () => setShowKey(!showKey), style: { padding: '0 10px', height: '34px' }, children: showKey ? 'Hide' : 'Show' })] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px', alignItems: 'center', marginBottom: '16px' }, children: [_jsx("button", { type: "button", className: "cs-voice-btn-primary", onClick: handleSaveKey, children: "Save Key" }), _jsx("button", { type: "button", className: "cs-voice-btn-secondary", onClick: handleTestKey, disabled: testStatus === 'testing', children: testStatus === 'testing' ? 'Testing...' : 'Test Connection' }), testStatus === 'success' && (_jsx("span", { style: { color: '#10b981', fontSize: '13px', fontWeight: 500 }, children: "\u2713 Verified connection" })), testStatus === 'error' && (_jsx("span", { style: { color: '#ef4444', fontSize: '12px' }, children: testError }))] }), _jsxs("div", { className: "cs-dialog-actions", style: { display: 'flex', justifyContent: 'space-between', marginTop: '20px' }, children: [_jsx("button", { type: "button", className: "cs-voice-btn-ghost", onClick: () => setActiveTab('intro'), children: "\u2190 Back" }), _jsx("button", { type: "button", className: "cs-voice-btn-primary", onClick: handleFinish, children: "Done & Close" })] })] })), activeTab === 'custom' && (_jsxs("div", { className: "cs-onboarding-section", children: [_jsx("p", { className: "cs-onboarding-desc", children: "Connect to local OpenAI-compatible endpoints such as Ollama, vLLM, or LM Studio." }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px', marginBottom: '16px' }, children: [_jsxs("div", { children: [_jsx("label", { className: "cs-settings-label", htmlFor: "cs-ob-custom-id", children: "Provider ID (e.g. ollama):" }), _jsx("input", { id: "cs-ob-custom-id", type: "text", className: "cs-voice-textarea", style: { width: '100%', height: '34px', minHeight: '34px', padding: '6px 10px' }, value: customId, onChange: e => setCustomId(e.target.value), placeholder: "ollama" })] }), _jsxs("div", { children: [_jsx("label", { className: "cs-settings-label", htmlFor: "cs-ob-custom-name", children: "Display Name:" }), _jsx("input", { id: "cs-ob-custom-name", type: "text", className: "cs-voice-textarea", style: { width: '100%', height: '34px', minHeight: '34px', padding: '6px 10px' }, value: customName, onChange: e => setCustomName(e.target.value), placeholder: "Local Ollama" })] }), _jsxs("div", { children: [_jsx("label", { className: "cs-settings-label", htmlFor: "cs-ob-custom-url", children: "Base URL:" }), _jsx("input", { id: "cs-ob-custom-url", type: "text", className: "cs-voice-textarea", style: { width: '100%', height: '34px', minHeight: '34px', padding: '6px 10px' }, value: customBaseUrl, onChange: e => setCustomBaseUrl(e.target.value), placeholder: "http://localhost:11434/v1" })] }), _jsxs("div", { children: [_jsx("label", { className: "cs-settings-label", htmlFor: "cs-ob-custom-models", children: "Models (id:name comma-separated):" }), _jsx("input", { id: "cs-ob-custom-models", type: "text", className: "cs-voice-textarea", style: { width: '100%', height: '34px', minHeight: '34px', padding: '6px 10px' }, value: customModels, onChange: e => setCustomModels(e.target.value), placeholder: "llama3:Llama 3, mistral:Mistral 7B" })] })] }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', marginTop: '16px' }, children: [_jsx("button", { type: "button", className: "cs-voice-btn-secondary", onClick: handleAddCustomProvider, children: "Register Endpoint" }), _jsx("button", { type: "button", className: "cs-voice-btn-primary", onClick: () => setActiveTab('keys'), children: "Go to API Keys \u2192" })] })] }))] })] }) }));
115
- }
@@ -1,71 +0,0 @@
1
- export interface AIConfig {
2
- preferredProvider: string;
3
- preferredModel: string;
4
- customProviders: CustomProvider[];
5
- }
6
- export interface CustomProvider {
7
- id: string;
8
- name: string;
9
- baseUrl: string;
10
- models: {
11
- id: string;
12
- name: string;
13
- }[];
14
- }
15
- export interface ModelConfig {
16
- id: string;
17
- name: string;
18
- }
19
- export interface ProviderConfig {
20
- id: string;
21
- name: string;
22
- baseUrl: string;
23
- models: ModelConfig[];
24
- }
25
- /** Opaque JSON Schema object — forwarded into provider request bodies and/or
26
- * embedded in the prompt text; see callAIStructured. */
27
- export type JsonSchema = Record<string, unknown>;
28
- export declare function getApiKey(provider: string): Promise<string | null>;
29
- export declare function setApiKey(provider: string, key: string): Promise<void>;
30
- export declare function deleteApiKey(provider: string): Promise<void>;
31
- export declare function getAIConfig(): AIConfig;
32
- export declare function saveAIConfig(config: AIConfig): void;
33
- export declare function fetchProviders(config?: AIConfig): Promise<ProviderConfig[]>;
34
- /**
35
- * Parses a structured AI response into T, tolerating a model that wraps the
36
- * JSON in a markdown fence or adds stray text around it despite being asked
37
- * not to (some providers don't strictly honor response_format hints).
38
- */
39
- export declare function extractJson<T>(raw: string): T;
40
- export declare function cleanVoiceResponse(text: string): string;
41
- export declare function subscribeToAICalls(callback: (calls: {
42
- providerName: string;
43
- model: string;
44
- }[]) => void): () => void;
45
- export declare function formatActiveCalls(calls: {
46
- providerName: string;
47
- model: string;
48
- }[]): string;
49
- export declare function callAI(prompt: string, systemPrompt: string, config: AIConfig, options?: {
50
- clean?: 'voice';
51
- }): Promise<string>;
52
- /**
53
- * Like callAI, but requests and validates a JSON response matching `schema`
54
- * instead of returning free text — the explicit contract that replaced
55
- * sniffing the system prompt for keywords like "duration"/"synopsis".
56
- */
57
- export declare function callAIStructured<T = unknown>(prompt: string, systemPrompt: string, config: AIConfig, schema: JsonSchema): Promise<T>;
58
- /** Any provider (from the fetched + custom list) with a stored API key. */
59
- export declare function hasConfiguredApiKey(config: AIConfig): Promise<boolean>;
60
- /**
61
- * Fetches the provider's live model list so Settings/Onboarding show
62
- * current models instead of a potentially stale static one. Never throws —
63
- * falls back to `provider.models` on any error (missing endpoint, bad key,
64
- * network failure), since this is a progressive enhancement.
65
- */
66
- export declare function listModels(provider: ProviderConfig, apiKey: string): Promise<ModelConfig[]>;
67
- export declare function testConnection(providerId: string, apiKey: string, config: AIConfig): Promise<boolean>;
68
- export declare function mockActiveCallsList(calls: {
69
- providerName: string;
70
- model: string;
71
- }[]): void;