feat(run,notifications,profiles): stop sending prompts nobody typed, and fix notification + profile delivery
Run console:
- Picking a pipeline no longer pre-writes anything into the prompt box
(`promptPrefill` in `LaneConsolePane.tsx` is gone — it wrote the driving
slash command on a claude lane and a stage checklist on a codex one).
Whatever sits in that box is sent as a real prompt the moment the run
starts, so the box is the user's alone now.
- Resuming a session sends NO prompt at all (`handleStart` in `RunSetup.tsx`):
the resumed session carries its own transcript, and leftover text in the box
fired an extra turn into it.
Notifications:
- `client/src/lib/notify.ts` is now the ONE sender, used by both
`useNotifications` and Settings' test button, and it reports where the
notification landed: `POST /api/push/send` answering `{native:false,pushed:0}`
means it went NOWHERE, so the client falls back to a local notification
instead of counting the 200 as delivered.
- A notification carries the lane that raised it (`/workspace?lane=<id>`), and
Workspace selects that lane on arrival.
Profiles:
- `server/lib/cc-profiles.js` reads and writes the macOS login Keychain item
`Claude Code-credentials`, where the `claude` CLI actually keeps
`claudeAiOauth` on darwin — a switch used to rewrite a file nothing reads.
The file stays the fallback, is kept in step only when it already exists, and
`AGENTHUB_CC_KEYCHAIN=0` pins it (tests set it).
Tests: npm run test:server (1820 pass), client vitest (553 pass).
This commit is contained in:
+9
-1
@@ -82,8 +82,12 @@ function showNativeNotificationIfElectron(title, body) {
|
||||
*
|
||||
* Returns `{ native, pushed, failed }` so the caller can surface what actually
|
||||
* happened in its API response — silent failures stop looking like success.
|
||||
*
|
||||
* @param {string} [url] Same-origin path (e.g. `/workspace?lane=3`) the
|
||||
* service worker's `notificationclick` handler navigates to. Undefined for
|
||||
* notifications with no specific target.
|
||||
*/
|
||||
async function sendPushToAll(db, title, body) {
|
||||
async function sendPushToAll(db, title, body, url) {
|
||||
const native = showNativeNotificationIfElectron(title, body);
|
||||
|
||||
const subscriptions = db.prepare("SELECT * FROM push_subscriptions").all();
|
||||
@@ -102,6 +106,10 @@ async function sendPushToAll(db, title, body) {
|
||||
badge: "/favicon.svg",
|
||||
silent: false,
|
||||
sound: "default",
|
||||
// `data` is the standard NotificationOptions field notificationclick reads
|
||||
// back via `event.notification.data`; omitted entirely when there's no url
|
||||
// so `event.notification.data` stays undefined rather than `{url: undefined}`.
|
||||
...(url ? { data: { url } } : {}),
|
||||
});
|
||||
const results = await Promise.allSettled(
|
||||
subscriptions.map((sub) =>
|
||||
|
||||
Reference in New Issue
Block a user