Skip to content
Merged
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
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ jobs:
cd apps/web && npm ci &
wait

# ── Secret scanning (no deps needed) ───────────────────────────────────
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# ── Stage 2: Parallel checks ──────────────────────────────────────────
typecheck-desktop:
needs: install
Expand Down Expand Up @@ -72,6 +83,23 @@ jobs:
key: nm-${{ hashFiles('apps/desktop/package-lock.json','apps/mcp-server/package-lock.json','apps/web/package-lock.json') }}
- run: cd apps/mcp-server && npm run typecheck

typecheck-web:
needs: install
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: actions/cache/restore@v4
with:
path: |
apps/desktop/node_modules
apps/mcp-server/node_modules
apps/web/node_modules
key: nm-${{ hashFiles('apps/desktop/package-lock.json','apps/mcp-server/package-lock.json','apps/web/package-lock.json') }}
- run: cd apps/web && npm run typecheck

lint-desktop:
needs: install
runs-on: ubuntu-latest
Expand Down Expand Up @@ -167,8 +195,10 @@ jobs:
ci-pass:
if: always()
needs:
- secret-scan
- typecheck-desktop
- typecheck-mcp
- typecheck-web
- lint-desktop
- test-desktop
- test-mcp
Expand Down
12 changes: 12 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[extend]
# Use the default gitleaks ruleset
useDefault = true

[allowlist]
paths = [
'''\.env\.example$''',
'''node_modules/''',
'''dist/''',
'''release/''',
'''\.git/''',
]
148 changes: 148 additions & 0 deletions apps/desktop/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"rehype-raw": "^7.0.0",
"rehype-sanitize": "^6.0.0",
"remark-gfm": "^4.0.1",
"shiki": "^3.23.0",
"sql.js": "^1.13.0",
"tailwind-merge": "^3.4.0",
"ws": "^8.19.0",
Expand Down
34 changes: 31 additions & 3 deletions apps/desktop/src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { createEmbeddingService } from "./services/memory/embeddingService";
import { createEmbeddingWorkerService } from "./services/memory/embeddingWorkerService";
import { createHybridSearchService } from "./services/memory/hybridSearchService";
import { createUnifiedMemoryService } from "./services/memory/unifiedMemoryService";
import { createProjectMemoryFilesService } from "./services/memory/memoryFilesService";
import { createMemoryLifecycleService } from "./services/memory/memoryLifecycleService";
import { createMemoryBriefingService } from "./services/memory/memoryBriefingService";
import { createMissionMemoryLifecycleService } from "./services/memory/missionMemoryLifecycleService";
Expand Down Expand Up @@ -410,7 +411,7 @@ async function createWindow(logger?: Logger): Promise<BrowserWindow> {
await win.loadURL(`data:text/html;charset=UTF-8,${fallbackHtml}`);
}

if (process.env.VITE_DEV_SERVER_URL) {
if (process.env.VITE_DEV_SERVER_URL && !process.env.NO_DEVTOOLS) {
win.webContents.openDevTools({ mode: "detach" });
}

Expand Down Expand Up @@ -965,10 +966,22 @@ app.whenReady().then(async () => {
logger,
});
let ctoStateServiceRef: ReturnType<typeof createCtoStateService> | null = null;
let memoryFilesServiceRef: ReturnType<typeof createProjectMemoryFilesService> | null = null;
let syncMemoryDocsTimer: ReturnType<typeof setTimeout> | null = null;
const debouncedSyncMemoryDocs = () => {
if (syncMemoryDocsTimer) clearTimeout(syncMemoryDocsTimer);
syncMemoryDocsTimer = setTimeout(() => { ctoStateServiceRef?.syncDerivedMemoryDocs(); }, 2_000);
syncMemoryDocsTimer = setTimeout(() => {
try {
ctoStateServiceRef?.syncDerivedMemoryDocs();
} catch {
// Ignore best-effort generated doc sync errors.
}
try {
memoryFilesServiceRef?.sync();
} catch {
// Ignore best-effort generated memory file sync errors.
}
}, 2_000);
};
const memoryService = createUnifiedMemoryService(db, {
hybridSearchService,
Expand All @@ -982,6 +995,12 @@ app.whenReady().then(async () => {
}
},
});
const memoryFilesService = createProjectMemoryFilesService({
projectRoot,
projectId,
memoryService,
});
memoryFilesServiceRef = memoryFilesService;
const compactionFlushService = createCompactionFlushService(undefined, { logger });
aiIntegrationService.setCompactionFlushService(compactionFlushService);
const batchConsolidationService = createBatchConsolidationService({
Expand Down Expand Up @@ -1015,6 +1034,7 @@ app.whenReady().then(async () => {
embeddingWorkerServiceRef = embeddingWorkerService;
const memoryBriefingService = createMemoryBriefingService({
memoryService,
memoryFilesService,
projectRoot,
humanWorkDigestService: {
getRecentCommitSummaries: async (count?: number) => {
Expand Down Expand Up @@ -1058,7 +1078,6 @@ app.whenReady().then(async () => {
projectId,
projectRoot,
logger,
memoryService,
});
const skillRegistryService = createSkillRegistryService({
db,
Expand Down Expand Up @@ -1088,6 +1107,14 @@ app.whenReady().then(async () => {
memoryService,
});
ctoStateServiceRef = ctoStateService;
try {
memoryFilesService.sync();
} catch (err) {
logger.warn("memory_files.sync_failed", {
projectRoot,
error: err instanceof Error ? err.message : String(err),
});
}

const workerAgentService = createWorkerAgentService({
db,
Expand Down Expand Up @@ -1213,6 +1240,7 @@ app.whenReady().then(async () => {
transcriptsDir: adePaths.transcriptsDir,
projectId,
memoryService,
memoryFilesService,
fileService,
workerAgentService,
workerHeartbeatService,
Expand Down
3 changes: 0 additions & 3 deletions apps/desktop/src/main/services/ai/providerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ export function buildProviderOptions(
},
};

case "groq":
case "together":
case "xai":
return {
[descriptor.family]: { reasoningEffort: tier },
Expand All @@ -67,7 +65,6 @@ export function buildProviderOptions(

case "ollama":
case "mistral":
case "meta":
// No reasoning config needed.
return {};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,11 @@ export function createCtoOperatorTools(deps: CtoOperatorToolDeps): Record<string
laneId: z.string().optional(),
modelId: z.string().optional(),
reasoningEffort: z.string().nullable().optional(),
permissionMode: z.enum(["default", "plan", "edit", "full-auto", "config-toml"]).optional().default("full-auto"),
title: z.string().optional(),
initialPrompt: z.string().optional(),
openInUi: z.boolean().optional().default(true),
}),
execute: async ({ laneId, modelId, reasoningEffort, permissionMode, title, initialPrompt, openInUi }) => {
execute: async ({ laneId, modelId, reasoningEffort, title, initialPrompt, openInUi }) => {
try {
const selectedModelId = modelId?.trim() || deps.defaultModelId || null;
const resolved = deriveChatProvider({ modelId: selectedModelId });
Expand All @@ -457,7 +456,6 @@ export function createCtoOperatorTools(deps: CtoOperatorToolDeps): Record<string
model: resolved.model,
...(selectedModelId ? { modelId: selectedModelId } : {}),
reasoningEffort: reasoningEffort ?? deps.defaultReasoningEffort ?? null,
permissionMode,
surface: "work",
sessionProfile: "workflow",
});
Expand Down
Loading