Merge branch 'worktree-agent-afbb9437'
This commit is contained in:
commit
2ed952f19c
90 files changed
+270701
-32
No files matched your search
@@ -1182,6 +1182,13 @@ export class AppDatabase {
|
||||
return row ? { ...row, isPrimary: toBoolean(row.isPrimary) } : null;
|
||||
}
|
||||
|
||||
listWorkspaceLocalPaths(companyId: string): string[] {
|
||||
const rows = this.db
|
||||
.prepare("select local_path as localPath from workspaces where company_id = ? and local_path is not null")
|
||||
.all(companyId) as Array<{ localPath: string }>;
|
||||
return rows.map((r) => r.localPath).filter(Boolean);
|
||||
}
|
||||
|
||||
getAnyCompanyWorkspace(companyId: string): WorkspaceRecord | null {
|
||||
const row = this.db
|
||||
.prepare(
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
dialog,
|
||||
Menu,
|
||||
nativeImage,
|
||||
nativeTheme,
|
||||
net,
|
||||
protocol,
|
||||
session,
|
||||
@@ -206,7 +207,7 @@ export function createDesktopShellService({
|
||||
y: savedWindowState.bounds.y,
|
||||
minWidth: 1180,
|
||||
minHeight: 760,
|
||||
backgroundColor: "#13110f",
|
||||
backgroundColor: "#ffffff",
|
||||
titleBarStyle: process.platform === "darwin" ? "hiddenInset" : "default",
|
||||
webPreferences: {
|
||||
preload: preloadPath,
|
||||
@@ -220,6 +221,9 @@ export function createDesktopShellService({
|
||||
},
|
||||
});
|
||||
|
||||
// Sync native theme with app to ensure Windows title bar matches content
|
||||
nativeTheme.themeSource = "light";
|
||||
|
||||
if (isDev && devServerUrl) {
|
||||
await mainWindow.loadURL(devServerUrl);
|
||||
} else {
|
||||
|
||||
@@ -50,13 +50,19 @@ export function registerSkillHandlers({
|
||||
return result;
|
||||
});
|
||||
|
||||
// ---- List all skills for a company ----
|
||||
// ---- List all skills for a company (also scans workspace .agents/skills/) ----
|
||||
registerHandle(IPC_CHANNELS.listSkills, async (_event, payload) => {
|
||||
const parsed = listSkillsSchema.parse(payload);
|
||||
const companyError = ensureCompanyExists(parsed.companyId);
|
||||
if (companyError) return companyError;
|
||||
const serviceError = requireSkillService();
|
||||
if (serviceError) return serviceError;
|
||||
// Scan workspace .agents/skills/ directories for new skills before listing
|
||||
try {
|
||||
await skillService!.scanWorkspaceSkills(parsed.companyId);
|
||||
} catch {
|
||||
// Non-fatal: scan failure should not block listing existing skills
|
||||
}
|
||||
return ok(skillService!.listForCompany(parsed.companyId));
|
||||
});
|
||||
|
||||
|
||||
@@ -701,6 +701,66 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen
|
||||
return inventory;
|
||||
}
|
||||
|
||||
// ---- Workspace .agents/skills/ scanning (Bug 6) ----
|
||||
|
||||
/**
|
||||
* Scan all workspace local paths for a company, looking for
|
||||
* `.agents/skills/` directories containing SKILL.md files.
|
||||
* Auto-imports any found skills that are not already in the database.
|
||||
* Cross-platform: uses path.join for correct separators.
|
||||
*/
|
||||
async function scanWorkspaceSkills(
|
||||
companyId: string,
|
||||
): Promise<SkillImportResult[]> {
|
||||
const allResults: SkillImportResult[] = [];
|
||||
|
||||
// 1. Scan user home directories: ~/.agents/skills/ and ~/.claude/skills/
|
||||
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
||||
if (homeDir) {
|
||||
const homeScanDirs = [
|
||||
join(homeDir, ".agents", "skills"),
|
||||
join(homeDir, ".claude", "skills"),
|
||||
];
|
||||
for (const scanDir of homeScanDirs) {
|
||||
if (!existsSync(scanDir)) continue;
|
||||
try {
|
||||
const stat = statSync(scanDir);
|
||||
if (!stat.isDirectory()) continue;
|
||||
const results = await importFromLocal(companyId, scanDir);
|
||||
allResults.push(...results);
|
||||
logger.info(`Scanned home skills: ${scanDir} — imported ${results.length} skill(s)`);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
logger.warn(`Failed to scan home skills at ${scanDir}: ${message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Scan workspace .agents/skills/ directories
|
||||
const workspacePaths = db.listWorkspaceLocalPaths(companyId);
|
||||
for (const wsPath of workspacePaths) {
|
||||
const agentsSkillsDir = join(wsPath, ".agents", "skills");
|
||||
if (!existsSync(agentsSkillsDir)) continue;
|
||||
|
||||
try {
|
||||
const stat = statSync(agentsSkillsDir);
|
||||
if (!stat.isDirectory()) continue;
|
||||
|
||||
const results = await importFromLocal(companyId, agentsSkillsDir);
|
||||
allResults.push(...results);
|
||||
logger.info(
|
||||
`Scanned workspace skills: ${agentsSkillsDir} — imported ${results.length} skill(s)`,
|
||||
);
|
||||
} catch (err) {
|
||||
// Log but don't fail the entire scan if one workspace has issues
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
logger.warn(`Failed to scan workspace skills at ${agentsSkillsDir}: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return allResults;
|
||||
}
|
||||
|
||||
// ---- Public API ----
|
||||
|
||||
return {
|
||||
@@ -715,5 +775,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen
|
||||
removeFromAgent,
|
||||
checkUpdateStatus,
|
||||
listRuntimeSkillEntries,
|
||||
scanWorkspaceSkills,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user