synabun 2.0.0-beta → 2.0.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 (70) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/THIRD-PARTY-LICENSES.md +5 -0
  3. package/launcher.mjs +40 -0
  4. package/lib/claude-hooks.js +61 -8
  5. package/lib/client-config-repair.js +4 -3
  6. package/lib/data-home-migration.js +4 -0
  7. package/lib/desktop-pwa.js +206 -0
  8. package/lib/external-tools.js +221 -0
  9. package/lib/first-launch-protection.js +5 -0
  10. package/lib/packaged-runtime.js +110 -0
  11. package/lib/start-launcher.js +1309 -0
  12. package/neural-interface/i18n/en.json +41 -2
  13. package/neural-interface/i18n/pt-BR.json +41 -2
  14. package/neural-interface/lib/assistant-envelope.js +9 -6
  15. package/neural-interface/lib/augmented-path.js +23 -3
  16. package/neural-interface/lib/browser-language.js +83 -0
  17. package/neural-interface/lib/claude-agent-bridge.js +54 -147
  18. package/neural-interface/lib/claude-executable.js +241 -0
  19. package/neural-interface/lib/claude-model-catalog.js +52 -91
  20. package/neural-interface/lib/native-binary-runtime.js +69 -337
  21. package/neural-interface/lib/native-loop-providers.js +30 -44
  22. package/neural-interface/lib/offline-page.js +54 -0
  23. package/neural-interface/lib/session-title-generator.js +5 -0
  24. package/neural-interface/lib/synabun-update-plan.js +19 -0
  25. package/neural-interface/package-lock.json +0 -251
  26. package/neural-interface/public/install-app.html +31 -0
  27. package/neural-interface/public/manifest.json +2 -0
  28. package/neural-interface/public/offline.html +401 -66
  29. package/neural-interface/public/onboarding.html +252 -146
  30. package/neural-interface/public/shared/assistant/asst-mascot.js +12 -10
  31. package/neural-interface/public/shared/assistant/asst-rack-styles.js +0 -3
  32. package/neural-interface/public/shared/assistant/asst-render.js +58 -49
  33. package/neural-interface/public/shared/assistant/asst-styles.js +4 -2
  34. package/neural-interface/public/shared/command-runner-model.js +30 -0
  35. package/neural-interface/public/shared/html-shell.js +9 -5
  36. package/neural-interface/public/shared/pwa-install-page.js +34 -0
  37. package/neural-interface/public/shared/pwa-install.css +12 -0
  38. package/neural-interface/public/shared/pwa-install.js +28 -0
  39. package/neural-interface/public/shared/settings/settings-rules.js +160 -0
  40. package/neural-interface/public/shared/start-bridge.js +583 -0
  41. package/neural-interface/public/shared/styleguide/sg-colors.js +5 -2
  42. package/neural-interface/public/shared/styleguide/sg-import-export.js +4 -3
  43. package/neural-interface/public/shared/styleguide/sg-kit.js +4 -1
  44. package/neural-interface/public/shared/styleguide/sg-panel.js +9 -1
  45. package/neural-interface/public/shared/styleguide/sg-typography.js +1 -0
  46. package/neural-interface/public/shared/styles.css +801 -392
  47. package/neural-interface/public/shared/term-ready.js +307 -0
  48. package/neural-interface/public/shared/ui-claude-panel.js +3 -3
  49. package/neural-interface/public/shared/ui-command-runner.js +251 -468
  50. package/neural-interface/public/shared/ui-judgments.js +1 -1
  51. package/neural-interface/public/shared/ui-loading.js +221 -10
  52. package/neural-interface/public/shared/ui-menubar.js +11 -27
  53. package/neural-interface/public/shared/ui-settings.js +36 -59
  54. package/neural-interface/public/shared/ui-terminal.js +130 -144
  55. package/neural-interface/public/sw.js +3 -1
  56. package/neural-interface/public/variant/2d/main.js +2 -1
  57. package/neural-interface/public/variant/3d/main.js +2 -1
  58. package/neural-interface/scripts/rebuild-pty.js +15 -12
  59. package/neural-interface/server.js +220 -185
  60. package/package.json +13 -1
  61. package/postinstall.js +11 -81
  62. package/setup.js +72 -4
  63. package/docs/browser-v2.md +0 -109
  64. package/docs/hook-integrity.md +0 -89
  65. package/docs/judgments.md +0 -182
  66. package/docs/style-guide.md +0 -246
  67. package/scripts/audit-claude-hook-usage.mjs +0 -12
  68. package/scripts/audit-memory-duplicates.mjs +0 -44
  69. package/scripts/measure-claude-hook-overhead.mjs +0 -77
  70. package/scripts/recover-user-config.mjs +0 -254
@@ -0,0 +1,54 @@
1
+ // The offline page is the one page that must work with the server down: the
2
+ // service worker serves the copy it cached while the server was still up. So
3
+ // everything it needs is put into that copy here: where SynaBun is installed,
4
+ // how it was installed, whether the Start Server launcher is registered, and
5
+ // the bridge code itself (public/shared/start-bridge.js, shared with the
6
+ // in-app loading overlay).
7
+
8
+ const BRIDGE_SLOT = '/*__SYNABUN_START_BRIDGE__*/';
9
+ const FACTS_SLOT = '/*__SYNABUN_OFFLINE_FACTS__*/';
10
+
11
+ /** An ES module with only top-level `export function` / `export const` → a classic script. */
12
+ export function moduleToClassicScript(source) {
13
+ const text = String(source || '');
14
+ if (/^\s*import\s/m.test(text) || /^\s*export\s+(?!function\b|const\b|async\s+function\b)/m.test(text)) {
15
+ throw new Error('start-bridge.js must only use `export function` / `export const` and no imports');
16
+ }
17
+ return text.replace(/^export\s+/gm, '');
18
+ }
19
+
20
+ /** JSON that is safe inside a <script> element. */
21
+ export function scriptJson(value) {
22
+ return JSON.stringify(value)
23
+ .replace(/</g, '\\u003c')
24
+ .replace(/>/g, '\\u003e')
25
+ .replace(/&/g, '\\u0026')
26
+ .replace(/\u2028/g, '\\u2028')
27
+ .replace(/\u2029/g, '\\u2029');
28
+ }
29
+
30
+ /**
31
+ * facts: { projectDir, install: 'npm' | 'git' | 'app', launcher: 'registered' | 'stale' | 'missing' | 'skipped',
32
+ * entry: a packaged application's entry executable }
33
+ * A template without the slots (an older cached copy, a hand-edited file) is
34
+ * returned as it is: the page then shows the commands and no button.
35
+ */
36
+ export function renderOfflinePage(template, { bridgeSource = '', facts = {} } = {}) {
37
+ let html = String(template || '');
38
+ if (html.includes(BRIDGE_SLOT)) {
39
+ let script = '';
40
+ try { script = moduleToClassicScript(bridgeSource).replace(/<\/script/gi, '<\\/script'); } catch {}
41
+ html = html.replace(BRIDGE_SLOT, () => script);
42
+ }
43
+ if (html.includes(FACTS_SLOT)) {
44
+ html = html.replace(FACTS_SLOT, () => `window.__SYNABUN_OFFLINE__ = ${scriptJson({
45
+ projectDir: facts.projectDir || '',
46
+ install: ['npm', 'app'].includes(facts.install) ? facts.install : 'git',
47
+ launcher: String(facts.launcher || ''),
48
+ ...(facts.entry ? { entry: String(facts.entry) } : {}),
49
+ })};`);
50
+ }
51
+ return html;
52
+ }
53
+
54
+ export const OFFLINE_SLOTS = Object.freeze({ bridge: BRIDGE_SLOT, facts: FACTS_SLOT });
@@ -70,6 +70,10 @@ export function extractCodexText(stdout) {
70
70
  }
71
71
 
72
72
  async function generateClaudeTitle(input, deps) {
73
+ // The user's Claude Code, as every other SDK call (lib/claude-executable.js).
74
+ // Without one there is no title to ask for: the caller falls back to its own.
75
+ const executable = typeof deps.claudeExecutable === 'function' ? deps.claudeExecutable() : null;
76
+ if (!executable?.path && !deps.claudeQuery) throw new Error(executable?.reason || 'Claude CLI not found');
73
77
  const abortController = new AbortController();
74
78
  const timer = setTimeout(() => abortController.abort(new Error('Session title request timed out')), SESSION_TITLE_TIMEOUT_MS);
75
79
  timer.unref?.();
@@ -89,6 +93,7 @@ async function generateClaudeTitle(input, deps) {
89
93
  persistSession: false,
90
94
  includePartialMessages: false,
91
95
  abortController,
96
+ ...(executable?.path ? { pathToClaudeCodeExecutable: executable.path } : {}),
92
97
  env: cleanClaudeEnv(deps.env || process.env),
93
98
  canUseTool: async () => ({ behavior: 'deny', message: 'Session title generation cannot use tools.' }),
94
99
  },
@@ -246,6 +246,25 @@ export function buildSynabunInstallPlan({
246
246
  const version = formatSynabunVersion(latest);
247
247
  const target = version || latest;
248
248
 
249
+ if (kind === 'packaged-app') {
250
+ // A packaged application carries its own runtime and dependencies: npm and
251
+ // git never write inside it. A newer build is installed over it instead.
252
+ const releasesUrl = `${repoUrl}/releases`;
253
+ return {
254
+ source: 'github',
255
+ installSource: kind,
256
+ canAutoUpdate: false,
257
+ reason: 'packaged-app',
258
+ current,
259
+ target,
260
+ channel: installedChannel,
261
+ displayCommand: releasesUrl,
262
+ openUrl: releasesUrl,
263
+ manualCommand: null,
264
+ manualHint: `This copy of SynaBun is a packaged application, so v${target} is installed by replacing it with the newer build, not from inside the app. Nothing was installed. Get the build for your system from the releases page and install it over this one; your data stays where it is.`,
265
+ };
266
+ }
267
+
249
268
  if (kind !== 'npm-global') {
250
269
  const clonedHint = kind === 'github-clone'
251
270
  ? 'This SynaBun install is a GitHub checkout. Open the repository to pull or reinstall from the correct source.'
@@ -49,138 +49,12 @@
49
49
  "engines": {
50
50
  "node": ">=18.0.0"
51
51
  },
52
- "optionalDependencies": {
53
- "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.288",
54
- "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.288",
55
- "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.288",
56
- "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.288",
57
- "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.288",
58
- "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.288",
59
- "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.288",
60
- "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.288"
61
- },
62
52
  "peerDependencies": {
63
53
  "@anthropic-ai/sdk": ">=0.93.0",
64
54
  "@modelcontextprotocol/sdk": "^1.29.0",
65
55
  "zod": "^4.0.0"
66
56
  }
67
57
  },
68
- "node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": {
69
- "version": "0.3.288",
70
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.288.tgz",
71
- "integrity": "sha512-85niGScWj8sr7yqOjSfqINaKv/zB47T45o4NBq1BmpaKRYFK7grtK24LA6C7cjx1Pznp+WT68mo373fbbwFW0A==",
72
- "cpu": [
73
- "arm64"
74
- ],
75
- "license": "SEE LICENSE IN LICENSE.md",
76
- "optional": true,
77
- "os": [
78
- "darwin"
79
- ]
80
- },
81
- "node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": {
82
- "version": "0.3.288",
83
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.288.tgz",
84
- "integrity": "sha512-hY8MQtgAi+cRedFb+qSqZzAYXIfjC+ZiXtCxKCs4OqWbqrdVZ0GKcEv4nB6MfQGs/Qr4U24cDNuO2lskBbZAWA==",
85
- "cpu": [
86
- "x64"
87
- ],
88
- "license": "SEE LICENSE IN LICENSE.md",
89
- "optional": true,
90
- "os": [
91
- "darwin"
92
- ]
93
- },
94
- "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": {
95
- "version": "0.3.288",
96
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.288.tgz",
97
- "integrity": "sha512-CCj0xau64T+Ia+X2wZgjYFSUIWfNJRWIGFbT8+jKiCzQggaBo6OSZ8hAYyME3h13JYrgpyrUTzB5YiwKaw8ZFg==",
98
- "cpu": [
99
- "arm64"
100
- ],
101
- "libc": [
102
- "glibc"
103
- ],
104
- "license": "SEE LICENSE IN LICENSE.md",
105
- "optional": true,
106
- "os": [
107
- "linux"
108
- ]
109
- },
110
- "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": {
111
- "version": "0.3.288",
112
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.288.tgz",
113
- "integrity": "sha512-66MD4hzNTqrTL5MN21bSfxm/fhbnM+ERsmWHGEsJojxAWY5DXCUlDkaAYM0rxDpdvLMVt9PpRVIiWDptaiFPxA==",
114
- "cpu": [
115
- "arm64"
116
- ],
117
- "libc": [
118
- "musl"
119
- ],
120
- "license": "SEE LICENSE IN LICENSE.md",
121
- "optional": true,
122
- "os": [
123
- "linux"
124
- ]
125
- },
126
- "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": {
127
- "version": "0.3.288",
128
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.288.tgz",
129
- "integrity": "sha512-Y5M496UZKttScbzptA45NI+CMHYONnskw0aq3rJ6s+gE6L6Jy8F8UoKt0lQO11R5xTY65TIeCasjQf/bLavuNg==",
130
- "cpu": [
131
- "x64"
132
- ],
133
- "libc": [
134
- "glibc"
135
- ],
136
- "license": "SEE LICENSE IN LICENSE.md",
137
- "optional": true,
138
- "os": [
139
- "linux"
140
- ]
141
- },
142
- "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": {
143
- "version": "0.3.288",
144
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.288.tgz",
145
- "integrity": "sha512-g3HDERLfEamirfp+MJDVl1fT8YYQMILUH65jPzl+SzKLeBu26WmAXAoZFmU4dasEmKZkEnBdL0ZQy3qnDy5EXg==",
146
- "cpu": [
147
- "x64"
148
- ],
149
- "libc": [
150
- "musl"
151
- ],
152
- "license": "SEE LICENSE IN LICENSE.md",
153
- "optional": true,
154
- "os": [
155
- "linux"
156
- ]
157
- },
158
- "node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": {
159
- "version": "0.3.288",
160
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.288.tgz",
161
- "integrity": "sha512-ijVSU5Vl1L1SlEm1djPNEekxHm9FS5GOitz8kL8KLdYDspMA97bgFM4gy/+riA3qn4ERepJkjdDLE+oYMTO+UA==",
162
- "cpu": [
163
- "arm64"
164
- ],
165
- "license": "SEE LICENSE IN LICENSE.md",
166
- "optional": true,
167
- "os": [
168
- "win32"
169
- ]
170
- },
171
- "node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": {
172
- "version": "0.3.288",
173
- "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.288.tgz",
174
- "integrity": "sha512-zh4yfGduDEBKUqb3BPtq/cLYwHoScqm7X5fJhmkSs0BJiSJGlb38j6FXWDvoPfe+OXNjE5onNx5HlAnDzsQzrA==",
175
- "cpu": [
176
- "x64"
177
- ],
178
- "license": "SEE LICENSE IN LICENSE.md",
179
- "optional": true,
180
- "os": [
181
- "win32"
182
- ]
183
- },
184
58
  "node_modules/@anthropic-ai/sdk": {
185
59
  "version": "0.104.1",
186
60
  "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.104.1.tgz",
@@ -1585,140 +1459,15 @@
1585
1459
  "url": "https://opencollective.com/express"
1586
1460
  }
1587
1461
  },
1588
- "node_modules/@openai/codex": {
1589
- "version": "0.160.0",
1590
- "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.160.0.tgz",
1591
- "integrity": "sha512-kEtVGzjRAYAMOwJxN39bGcna7LT3IDQgq64NNJ/dDTfu4OzZaocJcyNb5/gGJ/IVF/Vj7oK7E2m3nmTan7lpjg==",
1592
- "license": "Apache-2.0",
1593
- "bin": {
1594
- "codex": "bin/codex.js"
1595
- },
1596
- "engines": {
1597
- "node": ">=16"
1598
- },
1599
- "optionalDependencies": {
1600
- "@openai/codex-darwin-arm64": "npm:@openai/codex@0.160.0-darwin-arm64",
1601
- "@openai/codex-darwin-x64": "npm:@openai/codex@0.160.0-darwin-x64",
1602
- "@openai/codex-linux-arm64": "npm:@openai/codex@0.160.0-linux-arm64",
1603
- "@openai/codex-linux-x64": "npm:@openai/codex@0.160.0-linux-x64",
1604
- "@openai/codex-win32-arm64": "npm:@openai/codex@0.160.0-win32-arm64",
1605
- "@openai/codex-win32-x64": "npm:@openai/codex@0.160.0-win32-x64"
1606
- }
1607
- },
1608
- "node_modules/@openai/codex-darwin-arm64": {
1609
- "name": "@openai/codex",
1610
- "version": "0.160.0-darwin-arm64",
1611
- "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.160.0-darwin-arm64.tgz",
1612
- "integrity": "sha512-aefV6cqZA2REZgR//4McyXlp7zLcTti4CI2v3j9IVgNndPBv2kCeNEcz07qeelXcwOdSFPUKb6roA48vZmDgrQ==",
1613
- "cpu": [
1614
- "arm64"
1615
- ],
1616
- "license": "Apache-2.0",
1617
- "optional": true,
1618
- "os": [
1619
- "darwin"
1620
- ],
1621
- "engines": {
1622
- "node": ">=16"
1623
- }
1624
- },
1625
- "node_modules/@openai/codex-darwin-x64": {
1626
- "name": "@openai/codex",
1627
- "version": "0.160.0-darwin-x64",
1628
- "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.160.0-darwin-x64.tgz",
1629
- "integrity": "sha512-ir7cdsPrb9VkqNqpTECoTiomv04xws/FQ968mHQzuL+2J5Da0Dkh2Qlxp7sguDDZJab4YpYmNjQvBVMXbTeQaQ==",
1630
- "cpu": [
1631
- "x64"
1632
- ],
1633
- "license": "Apache-2.0",
1634
- "optional": true,
1635
- "os": [
1636
- "darwin"
1637
- ],
1638
- "engines": {
1639
- "node": ">=16"
1640
- }
1641
- },
1642
- "node_modules/@openai/codex-linux-arm64": {
1643
- "name": "@openai/codex",
1644
- "version": "0.160.0-linux-arm64",
1645
- "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.160.0-linux-arm64.tgz",
1646
- "integrity": "sha512-VnVdsS06YlDsL8OwaJjQ3xdqdJNG4i+eBJBV3LytddknzSaF/urijLzVg3ptkwvoj8C7Gn7iWpVE+y8WEaPiCg==",
1647
- "cpu": [
1648
- "arm64"
1649
- ],
1650
- "license": "Apache-2.0",
1651
- "optional": true,
1652
- "os": [
1653
- "linux"
1654
- ],
1655
- "engines": {
1656
- "node": ">=16"
1657
- }
1658
- },
1659
- "node_modules/@openai/codex-linux-x64": {
1660
- "name": "@openai/codex",
1661
- "version": "0.160.0-linux-x64",
1662
- "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.160.0-linux-x64.tgz",
1663
- "integrity": "sha512-KI/73OqGrHmR18s7ya7E1NqV6rT0y3lxr0s8S1qR2m6zU6QRF/HlR529jALLh5vjdUnsRT4Ahoxt0axb4kY99g==",
1664
- "cpu": [
1665
- "x64"
1666
- ],
1667
- "license": "Apache-2.0",
1668
- "optional": true,
1669
- "os": [
1670
- "linux"
1671
- ],
1672
- "engines": {
1673
- "node": ">=16"
1674
- }
1675
- },
1676
1462
  "node_modules/@openai/codex-sdk": {
1677
1463
  "version": "0.160.0",
1678
1464
  "resolved": "https://registry.npmjs.org/@openai/codex-sdk/-/codex-sdk-0.160.0.tgz",
1679
1465
  "integrity": "sha512-PWmoVvX/YqofBnauvao7IEUSYWzbbbIBmwQfRu3ARb2ZbcwIUeuMaicchEpdBzpE8Bw3KOMyhlPlcSQWeg+EoA==",
1680
1466
  "license": "Apache-2.0",
1681
- "dependencies": {
1682
- "@openai/codex": "0.160.0"
1683
- },
1684
1467
  "engines": {
1685
1468
  "node": ">=18"
1686
1469
  }
1687
1470
  },
1688
- "node_modules/@openai/codex-win32-arm64": {
1689
- "name": "@openai/codex",
1690
- "version": "0.160.0-win32-arm64",
1691
- "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.160.0-win32-arm64.tgz",
1692
- "integrity": "sha512-tTvK9ZIGuj9WnYaYOAnfjJVSfPV7dKqWtDHqUPLf0Hadp6SgynTxx7S7iMXRieFeXVOI2XH76KxEHSOTOnz3zw==",
1693
- "cpu": [
1694
- "arm64"
1695
- ],
1696
- "license": "Apache-2.0",
1697
- "optional": true,
1698
- "os": [
1699
- "win32"
1700
- ],
1701
- "engines": {
1702
- "node": ">=16"
1703
- }
1704
- },
1705
- "node_modules/@openai/codex-win32-x64": {
1706
- "name": "@openai/codex",
1707
- "version": "0.160.0-win32-x64",
1708
- "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.160.0-win32-x64.tgz",
1709
- "integrity": "sha512-/gCFcuOmGlQkgGivWCtY8BNEDixh70Pue0HZOk9S8bj2vUIE1GLD9zcNB/KqqDJmn0S+lIttauLpzQnw6HOCHA==",
1710
- "cpu": [
1711
- "x64"
1712
- ],
1713
- "license": "Apache-2.0",
1714
- "optional": true,
1715
- "os": [
1716
- "win32"
1717
- ],
1718
- "engines": {
1719
- "node": ">=16"
1720
- }
1721
- },
1722
1471
  "node_modules/@opencode-ai/sdk": {
1723
1472
  "version": "1.18.34",
1724
1473
  "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.18.34.tgz",
@@ -0,0 +1,31 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Install as App — SynaBun</title>
7
+ <link rel="icon" href="/favicon-32x32.png">
8
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png">
9
+ <link rel="manifest" href="/manifest.json">
10
+ <link rel="stylesheet" href="/shared/styles.css">
11
+ <link rel="stylesheet" href="/shared/pwa-install.css">
12
+ </head>
13
+ <body id="pwa-install">
14
+ <main aria-labelledby="install-title">
15
+ <img src="/icon-192.png" width="48" height="48" alt="SynaBun">
16
+ <h1 id="install-title">Install SynaBun as an app</h1>
17
+ <p id="install-intro">The server is running in the background. Confirm installation once in your browser to give SynaBun its own app window.</p>
18
+ <ol>
19
+ <li id="install-chromium">Chrome or Edge: choose Install as App below, or the browser's Install app menu.</li>
20
+ <li id="install-safari">Safari on macOS: choose File → Add to Dock. Keep the name SynaBun.</li>
21
+ </ol>
22
+ <p id="install-later">After installation, reopen the native SynaBun launcher. It starts or reuses the server and opens your installed PWA. Closing the app window leaves the server running. Use Apps → Stop Server to stop it.</p>
23
+ <div class="actions">
24
+ <button id="install-button" type="button">Install as App</button>
25
+ <a id="install-continue" href="/">Continue to SynaBun</a>
26
+ </div>
27
+ <p id="install-status" role="status" aria-live="polite"></p>
28
+ </main>
29
+ <script type="module" src="/shared/pwa-install-page.js"></script>
30
+ </body>
31
+ </html>
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "SynaBun",
3
3
  "short_name": "SynaBun",
4
+ "id": "/",
5
+ "scope": "/",
4
6
  "start_url": "/",
5
7
  "display": "standalone",
6
8
  "display_override": ["window-controls-overlay", "standalone"],