Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"source-map-support": "^0.5.21",
"streamdown": "^1.4.0",
"undici": "^7.16.0",
"web-push": "^3.6.7",
"write-file-atomic": "^6.0.0",
"ws": "^8.18.3",
"zod": "^4.1.11",
Expand Down Expand Up @@ -61,6 +62,7 @@
"@types/minimist": "^1.2.5",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/web-push": "^3.6.4",
"@types/write-file-atomic": "^4.0.3",
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^8.44.1",
Expand Down Expand Up @@ -901,6 +903,8 @@

"@types/wait-on": ["@types/[email protected]", "", { "dependencies": { "@types/node": "*" } }, "sha512-EBsPjFMrFlMbbUFf9D1Fp+PAB2TwmUn7a3YtHyD9RLuTIk1jDd8SxXVAoez2Ciy+8Jsceo2MYEYZzJ/DvorOKw=="],

"@types/web-push": ["@types/[email protected]", "", { "dependencies": { "@types/node": "*" } }, "sha512-GnJmSr40H3RAnj0s34FNTcJi1hmWFV5KXugE0mYWnYhgTAHLJ/dJKAwDmvPJYMke0RplY2XE9LnM4hqSqKIjhQ=="],

"@types/write-file-atomic": ["@types/[email protected]", "", { "dependencies": { "@types/node": "*" } }, "sha512-qdo+vZRchyJIHNeuI1nrpsLw+hnkgqP/8mlaN6Wle/NKhydHmUN9l4p3ZE8yP90AJNJW4uB8HQhedb4f1vNayQ=="],

"@types/ws": ["@types/[email protected]", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
Expand Down Expand Up @@ -1007,7 +1011,7 @@

"acorn-jsx": ["[email protected]", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],

"agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],

"aggregate-error": ["[email protected]", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],

Expand Down Expand Up @@ -1061,6 +1065,8 @@

"arraybuffer.prototype.slice": ["[email protected]", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="],

"asn1.js": ["[email protected]", "", { "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "safer-buffer": "^2.1.0" } }, "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA=="],

"assert-plus": ["[email protected]", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="],

"assertion-error": ["[email protected]", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
Expand Down Expand Up @@ -1115,6 +1121,8 @@

"bluebird-lst": ["[email protected]", "", { "dependencies": { "bluebird": "^3.5.5" } }, "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw=="],

"bn.js": ["[email protected]", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],

"body-parser": ["[email protected]", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],

"boolean": ["[email protected]", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="],
Expand All @@ -1137,6 +1145,8 @@

"buffer-equal": ["[email protected]", "", {}, "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg=="],

"buffer-equal-constant-time": ["[email protected]", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],

"buffer-from": ["[email protected]", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],

"builder-util": ["[email protected]", "", { "dependencies": { "7zip-bin": "~5.2.0", "@types/debug": "^4.1.6", "app-builder-bin": "4.0.0", "bluebird-lst": "^1.0.9", "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.1", "is-ci": "^3.0.0", "js-yaml": "^4.1.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0" } }, "sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA=="],
Expand Down Expand Up @@ -1443,6 +1453,8 @@

"eastasianwidth": ["[email protected]", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],

"ecdsa-sig-formatter": ["[email protected]", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],

"ee-first": ["[email protected]", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],

"ejs": ["[email protected]", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
Expand Down Expand Up @@ -1749,7 +1761,9 @@

"http2-wrapper": ["[email protected]", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="],

"https-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
"http_ece": ["[email protected]", "", {}, "sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA=="],

"https-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],

"human-signals": ["[email protected]", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],

Expand Down Expand Up @@ -1991,6 +2005,10 @@

"jszip": ["[email protected]", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="],

"jwa": ["[email protected]", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],

"jws": ["[email protected]", "", { "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg=="],

"katex": ["[email protected]", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-woHRUZ/iF23GBP1dkDQMh1QBad9dmr8/PAwNA54VrSOVYgI12MAcE14TqnDdQOdzyEonGzMepYnqBMYdsoAr8Q=="],

"keyv": ["[email protected]", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
Expand Down Expand Up @@ -2227,6 +2245,8 @@

"min-indent": ["[email protected]", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],

"minimalistic-assert": ["[email protected]", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="],

"minimatch": ["[email protected]", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],

"minimist": ["[email protected]", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
Expand Down Expand Up @@ -2869,6 +2889,8 @@

"web-namespaces": ["[email protected]", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],

"web-push": ["[email protected]", "", { "dependencies": { "asn1.js": "^5.3.0", "http_ece": "1.2.0", "https-proxy-agent": "^7.0.0", "jws": "^4.0.0", "minimist": "^1.2.5" }, "bin": { "web-push": "src/cli.js" } }, "sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A=="],

"web-vitals": ["[email protected]", "", {}, "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw=="],

"webpack-virtual-modules": ["[email protected]", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
Expand Down Expand Up @@ -3091,6 +3113,8 @@

"builder-util/chalk": ["[email protected]", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],

"builder-util/https-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],

"caching-transform/write-file-atomic": ["[email protected]", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="],

"chokidar/fsevents": ["[email protected]", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
Expand Down Expand Up @@ -3195,6 +3219,8 @@

"http-errors/statuses": ["[email protected]", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],

"http-proxy-agent/agent-base": ["[email protected]", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],

"import-fresh/resolve-from": ["[email protected]", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],

"istanbul-lib-processinfo/uuid": ["[email protected]", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
Expand Down Expand Up @@ -3577,6 +3603,8 @@

"builder-util/chalk/supports-color": ["[email protected]", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],

"builder-util/https-proxy-agent/agent-base": ["[email protected]", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],

"caching-transform/write-file-atomic/signal-exit": ["[email protected]", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],

"concurrently/chalk/ansi-styles": ["[email protected]", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"source-map-support": "^0.5.21",
"streamdown": "^1.4.0",
"undici": "^7.16.0",
"web-push": "^3.6.7",
"write-file-atomic": "^6.0.0",
"ws": "^8.18.3",
"zod": "^4.1.11",
Expand Down Expand Up @@ -102,6 +103,7 @@
"@types/minimist": "^1.2.5",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/web-push": "^3.6.4",
"@types/write-file-atomic": "^4.0.3",
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^8.44.1",
Expand Down
45 changes: 45 additions & 0 deletions public/service-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,48 @@ self.addEventListener('fetch', (event) => {
);
});

// Push event - show notification
self.addEventListener('push', (event) => {
if (!event.data) {
return;
}

try {
const data = event.data.json();

event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icon-192.png',
badge: '/icon-192.png',
tag: data.workspaceId,
data: { workspaceId: data.workspaceId },
})
);
} catch (error) {
console.error('Error handling push event:', error);
}
});

// Notification click - focus app and navigate to workspace
self.addEventListener('notificationclick', (event) => {
event.notification.close();

event.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true })
.then((clientList) => {
// If a window is already open, focus it
for (const client of clientList) {
if (client.url.includes(self.location.origin) && 'focus' in client) {
return client.focus();
}
}
// Otherwise open a new window
if (clients.openWindow) {
return clients.openWindow(`/?workspace=${event.notification.data.workspaceId}`);
}
})
);
});


5 changes: 5 additions & 0 deletions src/App.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ function setupMockAPI(options: {
install: () => undefined,
onStatus: () => () => undefined,
},
notification: {
subscribePush: () => Promise.resolve(undefined),
unsubscribePush: () => Promise.resolve(undefined),
getVapidKey: () => Promise.resolve(null),
},
...options.apiOverrides,
};

Expand Down
7 changes: 7 additions & 0 deletions src/browser/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,13 @@ const webApi: IPCApi = {
return wsManager.on(IPC_CHANNELS.UPDATE_STATUS, callback as (data: unknown) => void);
},
},
notification: {
subscribePush: (workspaceId, subscription) =>
invokeIPC(IPC_CHANNELS.NOTIFICATION_SUBSCRIBE_PUSH, workspaceId, subscription),
unsubscribePush: (workspaceId, endpoint) =>
invokeIPC(IPC_CHANNELS.NOTIFICATION_UNSUBSCRIBE_PUSH, workspaceId, endpoint),
getVapidKey: () => invokeIPC(IPC_CHANNELS.NOTIFICATION_GET_VAPID_KEY),
},
};

if (typeof window.api === "undefined") {
Expand Down
5 changes: 5 additions & 0 deletions src/constants/ipc-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export const IPC_CHANNELS = {
UPDATE_STATUS: "update:status",
UPDATE_STATUS_SUBSCRIBE: "update:status:subscribe",

// Notification channels
NOTIFICATION_SUBSCRIBE_PUSH: "notification:subscribePush",
NOTIFICATION_UNSUBSCRIBE_PUSH: "notification:unsubscribePush",
NOTIFICATION_GET_VAPID_KEY: "notification:getVapidKey",

// Dynamic channel prefixes
WORKSPACE_CHAT_PREFIX: "workspace:chat:",
WORKSPACE_METADATA: "workspace:metadata",
Expand Down
6 changes: 6 additions & 0 deletions src/constants/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ export function getRuntimeKey(projectPath: string): string {
*/
export const USE_1M_CONTEXT_KEY = "use1MContext";

/**
* Get the localStorage key for completion notification preference (global)
* Format: "notifications:completionEnabled"
*/
export const NOTIFICATION_ENABLED_KEY = "notifications:completionEnabled";

/**
* Get the localStorage key for the preferred compaction model (global)
* Format: "preferredCompactionModel"
Expand Down
3 changes: 3 additions & 0 deletions src/debug/agentSessionCli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { HistoryService } from "@/services/historyService";
import { PartialService } from "@/services/partialService";
import { AIService } from "@/services/aiService";
import { InitStateManager } from "@/services/initStateManager";
import { NotificationService } from "@/services/NotificationService";
import { AgentSession, type AgentSessionChatEvent } from "@/services/agentSession";
import {
isCaughtUpMessage,
Expand Down Expand Up @@ -211,6 +212,7 @@ async function main(): Promise<void> {
const partialService = new PartialService(config, historyService);
const aiService = new AIService(config, historyService, partialService);
const initStateManager = new InitStateManager(config);
const notificationService = new NotificationService(config.rootDir, true);
ensureProvidersConfig(config);

const session = new AgentSession({
Expand All @@ -220,6 +222,7 @@ async function main(): Promise<void> {
partialService,
aiService,
initStateManager,
notificationService,
});

session.ensureMetadata({
Expand Down
2 changes: 1 addition & 1 deletion src/main-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ app.use(express.json({ limit: "50mb" }));

// Initialize config and IPC service
const config = new Config();
const ipcMainService = new IpcMain(config);
const ipcMainService = new IpcMain(config, false); // false = not desktop (web/mobile)

// Track WebSocket clients and their subscriptions
const clients: Clients = new Map();
Expand Down
7 changes: 7 additions & 0 deletions src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ const api: IPCApi = {
};
},
},
notification: {
subscribePush: (workspaceId: string, subscription: unknown) =>
ipcRenderer.invoke(IPC_CHANNELS.NOTIFICATION_SUBSCRIBE_PUSH, workspaceId, subscription),
unsubscribePush: (workspaceId: string, endpoint: string) =>
ipcRenderer.invoke(IPC_CHANNELS.NOTIFICATION_UNSUBSCRIBE_PUSH, workspaceId, endpoint),
getVapidKey: () => ipcRenderer.invoke(IPC_CHANNELS.NOTIFICATION_GET_VAPID_KEY),
},
};

// Expose the API along with platform/versions
Expand Down
Loading