mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-15 21:11:08 +02:00
feat(apps): copilot answers from installed apps and surfaces them
Generic app-copilot bridge (no app-specific wiring anywhere): - app-read-data builtin: read (or list) an installed app's data/ files — the agent-maintained JSON the app renders. Same path confinement as app-set-data; 50k char cap with truncation flag; parsed JSON returned when possible. Attached via the app-navigation skill. - read-view view=apps: installed apps with name/description/dataFiles/ agentSlugs, navigating the user's screen to the Apps view (same show-while-telling contract as email/bg-tasks). Renderer routes the new view value. - copilot instructions embed the installed-apps list (name + description per app) with routing guidance: prefer an app's fresh data over external calls, answer from it, open-app to surface it. The apps:list handler fingerprints the app set and invalidates the instructions cache when it changes (installs, deletes, copilot- created folders all flow through that poll). - app-navigation skill: apps section + a worked example framing the pattern generically (match apps by their own descriptions, never a hardcoded topic map). Verified against real data: app-read-data returns pr-dashboard's live 10-PR data.json, escape paths rejected, key-order golden test updated and passing.
This commit is contained in:
parent
214cae7190
commit
7d38dc84a2
7 changed files with 172 additions and 9 deletions
|
|
@ -79,6 +79,9 @@ import * as appsPublisher from '@x/core/dist/apps/publisher.js';
|
|||
|
||||
// D18 install previews awaiting confirmation, keyed by app name.
|
||||
const appInstallPreviews = new Map<string, Awaited<ReturnType<typeof appsInstaller.previewInstall>>>();
|
||||
// Last-seen app-set fingerprint; a change invalidates the copilot
|
||||
// instructions cache (they embed the installed-apps list).
|
||||
let lastAppsFingerprint: string | null = null;
|
||||
import { consumePendingDeepLink } from './deeplink.js';
|
||||
import { qualifyAndDisconnectComposioGoogle } from '@x/core/dist/migrations/composio-google-migration.js';
|
||||
import { IAgentScheduleRepo } from '@x/core/dist/agent-schedule/repo.js';
|
||||
|
|
@ -1618,6 +1621,15 @@ export function setupIpcHandlers() {
|
|||
for (const app of apps) {
|
||||
if (app.agentSlugs.length) await appsAgents.syncAppAgents(app);
|
||||
}
|
||||
// The copilot instructions embed the installed-apps list. This handler
|
||||
// is the one place that sees every change to the app set (installs,
|
||||
// deletes, copilot-created folders — the renderer polls it), so refresh
|
||||
// the instructions cache when the set actually changes.
|
||||
const fingerprint = JSON.stringify(apps.map((a) => [a.folder, a.manifest?.name, a.manifest?.description, a.hasDist]));
|
||||
if (fingerprint !== lastAppsFingerprint) {
|
||||
lastAppsFingerprint = fingerprint;
|
||||
invalidateCopilotInstructionsCache();
|
||||
}
|
||||
return {
|
||||
serverRunning: status.running,
|
||||
...(status.error ? { serverError: status.error } : {}),
|
||||
|
|
|
|||
|
|
@ -4773,6 +4773,7 @@ function App() {
|
|||
case 'knowledge': void navigateToView({ type: 'knowledge-view' }); break
|
||||
case 'workspace': void navigateToView({ type: 'workspace' }); break
|
||||
case 'code': void navigateToView({ type: 'code' }); break
|
||||
case 'apps': openAppsView(); break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue