modular-studio 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/assets/graphPopulator-C6jg83nL.js +1 -0
- package/dist/assets/index-CXhIX28x.js +634 -0
- package/dist/assets/index-CeNF0r-K.css +1 -0
- package/dist/assets/jszip.min-BlpRodxc.js +2 -0
- package/dist/index.html +16 -0
- package/dist/vite.svg +1 -0
- package/dist-server/bin/modular-mcp.d.ts +8 -0
- package/dist-server/bin/modular-mcp.d.ts.map +1 -0
- package/dist-server/bin/modular-mcp.js +158 -0
- package/dist-server/bin/modular-mcp.js.map +1 -0
- package/dist-server/bin/modular-studio.d.ts +3 -0
- package/dist-server/bin/modular-studio.d.ts.map +1 -0
- package/dist-server/bin/modular-studio.js +63 -0
- package/dist-server/bin/modular-studio.js.map +1 -0
- package/dist-server/server/config.d.ts +4 -0
- package/dist-server/server/config.d.ts.map +1 -0
- package/dist-server/server/config.js +33 -0
- package/dist-server/server/config.js.map +1 -0
- package/dist-server/server/data/mcp-clients.json +5 -0
- package/dist-server/server/index.d.ts +3 -0
- package/dist-server/server/index.d.ts.map +1 -0
- package/dist-server/server/index.js +174 -0
- package/dist-server/server/index.js.map +1 -0
- package/dist-server/server/mcp/manager.d.ts +47 -0
- package/dist-server/server/mcp/manager.d.ts.map +1 -0
- package/dist-server/server/mcp/manager.js +203 -0
- package/dist-server/server/mcp/manager.js.map +1 -0
- package/dist-server/server/mcp/modular-server.d.ts +55 -0
- package/dist-server/server/mcp/modular-server.d.ts.map +1 -0
- package/dist-server/server/mcp/modular-server.js +492 -0
- package/dist-server/server/mcp/modular-server.js.map +1 -0
- package/dist-server/server/mcp/transport.d.ts +29 -0
- package/dist-server/server/mcp/transport.d.ts.map +1 -0
- package/dist-server/server/mcp/transport.js +61 -0
- package/dist-server/server/mcp/transport.js.map +1 -0
- package/dist-server/server/routes/agent-sdk.d.ts +3 -0
- package/dist-server/server/routes/agent-sdk.d.ts.map +1 -0
- package/dist-server/server/routes/agent-sdk.js +99 -0
- package/dist-server/server/routes/agent-sdk.js.map +1 -0
- package/dist-server/server/routes/agents.d.ts +10 -0
- package/dist-server/server/routes/agents.d.ts.map +1 -0
- package/dist-server/server/routes/agents.js +61 -0
- package/dist-server/server/routes/agents.js.map +1 -0
- package/dist-server/server/routes/auth-codex.d.ts +3 -0
- package/dist-server/server/routes/auth-codex.d.ts.map +1 -0
- package/dist-server/server/routes/auth-codex.js +51 -0
- package/dist-server/server/routes/auth-codex.js.map +1 -0
- package/dist-server/server/routes/capabilities.d.ts +3 -0
- package/dist-server/server/routes/capabilities.d.ts.map +1 -0
- package/dist-server/server/routes/capabilities.js +32 -0
- package/dist-server/server/routes/capabilities.js.map +1 -0
- package/dist-server/server/routes/claude-config.d.ts +3 -0
- package/dist-server/server/routes/claude-config.d.ts.map +1 -0
- package/dist-server/server/routes/claude-config.js +146 -0
- package/dist-server/server/routes/claude-config.js.map +1 -0
- package/dist-server/server/routes/connectors.d.ts +12 -0
- package/dist-server/server/routes/connectors.d.ts.map +1 -0
- package/dist-server/server/routes/connectors.js +325 -0
- package/dist-server/server/routes/connectors.js.map +1 -0
- package/dist-server/server/routes/embeddings.d.ts +6 -0
- package/dist-server/server/routes/embeddings.d.ts.map +1 -0
- package/dist-server/server/routes/embeddings.js +130 -0
- package/dist-server/server/routes/embeddings.js.map +1 -0
- package/dist-server/server/routes/health.d.ts +9 -0
- package/dist-server/server/routes/health.d.ts.map +1 -0
- package/dist-server/server/routes/health.js +284 -0
- package/dist-server/server/routes/health.js.map +1 -0
- package/dist-server/server/routes/knowledge.d.ts +3 -0
- package/dist-server/server/routes/knowledge.d.ts.map +1 -0
- package/dist-server/server/routes/knowledge.js +534 -0
- package/dist-server/server/routes/knowledge.js.map +1 -0
- package/dist-server/server/routes/llm.d.ts +3 -0
- package/dist-server/server/routes/llm.d.ts.map +1 -0
- package/dist-server/server/routes/llm.js +200 -0
- package/dist-server/server/routes/llm.js.map +1 -0
- package/dist-server/server/routes/mcp-oauth.d.ts +12 -0
- package/dist-server/server/routes/mcp-oauth.d.ts.map +1 -0
- package/dist-server/server/routes/mcp-oauth.js +137 -0
- package/dist-server/server/routes/mcp-oauth.js.map +1 -0
- package/dist-server/server/routes/mcp.d.ts +3 -0
- package/dist-server/server/routes/mcp.d.ts.map +1 -0
- package/dist-server/server/routes/mcp.js +177 -0
- package/dist-server/server/routes/mcp.js.map +1 -0
- package/dist-server/server/routes/pipeline.d.ts +45 -0
- package/dist-server/server/routes/pipeline.d.ts.map +1 -0
- package/dist-server/server/routes/pipeline.js +483 -0
- package/dist-server/server/routes/pipeline.js.map +1 -0
- package/dist-server/server/routes/providers.d.ts +3 -0
- package/dist-server/server/routes/providers.d.ts.map +1 -0
- package/dist-server/server/routes/providers.js +204 -0
- package/dist-server/server/routes/providers.js.map +1 -0
- package/dist-server/server/routes/qualification.d.ts +3 -0
- package/dist-server/server/routes/qualification.d.ts.map +1 -0
- package/dist-server/server/routes/qualification.js +105 -0
- package/dist-server/server/routes/qualification.js.map +1 -0
- package/dist-server/server/routes/repo-index.d.ts +4 -0
- package/dist-server/server/routes/repo-index.d.ts.map +1 -0
- package/dist-server/server/routes/repo-index.js +318 -0
- package/dist-server/server/routes/repo-index.js.map +1 -0
- package/dist-server/server/routes/runtime.d.ts +3 -0
- package/dist-server/server/routes/runtime.d.ts.map +1 -0
- package/dist-server/server/routes/runtime.js +122 -0
- package/dist-server/server/routes/runtime.js.map +1 -0
- package/dist-server/server/routes/skills-search.d.ts +3 -0
- package/dist-server/server/routes/skills-search.d.ts.map +1 -0
- package/dist-server/server/routes/skills-search.js +198 -0
- package/dist-server/server/routes/skills-search.js.map +1 -0
- package/dist-server/server/routes/worktrees.d.ts +3 -0
- package/dist-server/server/routes/worktrees.d.ts.map +1 -0
- package/dist-server/server/routes/worktrees.js +70 -0
- package/dist-server/server/routes/worktrees.js.map +1 -0
- package/dist-server/server/services/__tests__/embeddingService.test.d.ts +5 -0
- package/dist-server/server/services/__tests__/embeddingService.test.d.ts.map +1 -0
- package/dist-server/server/services/__tests__/embeddingService.test.js +233 -0
- package/dist-server/server/services/__tests__/embeddingService.test.js.map +1 -0
- package/dist-server/server/services/agentRunner.d.ts +46 -0
- package/dist-server/server/services/agentRunner.d.ts.map +1 -0
- package/dist-server/server/services/agentRunner.js +295 -0
- package/dist-server/server/services/agentRunner.js.map +1 -0
- package/dist-server/server/services/agentStore.d.ts +40 -0
- package/dist-server/server/services/agentStore.d.ts.map +1 -0
- package/dist-server/server/services/agentStore.js +62 -0
- package/dist-server/server/services/agentStore.js.map +1 -0
- package/dist-server/server/services/contentStore.d.ts +32 -0
- package/dist-server/server/services/contentStore.d.ts.map +1 -0
- package/dist-server/server/services/contentStore.js +68 -0
- package/dist-server/server/services/contentStore.js.map +1 -0
- package/dist-server/server/services/embeddingService.d.ts +53 -0
- package/dist-server/server/services/embeddingService.d.ts.map +1 -0
- package/dist-server/server/services/embeddingService.js +199 -0
- package/dist-server/server/services/embeddingService.js.map +1 -0
- package/dist-server/server/services/factExtractor.d.ts +14 -0
- package/dist-server/server/services/factExtractor.d.ts.map +1 -0
- package/dist-server/server/services/factExtractor.js +126 -0
- package/dist-server/server/services/factExtractor.js.map +1 -0
- package/dist-server/server/services/githubIndexer.d.ts +59 -0
- package/dist-server/server/services/githubIndexer.d.ts.map +1 -0
- package/dist-server/server/services/githubIndexer.js +183 -0
- package/dist-server/server/services/githubIndexer.js.map +1 -0
- package/dist-server/server/services/mcpOAuth.d.ts +32 -0
- package/dist-server/server/services/mcpOAuth.d.ts.map +1 -0
- package/dist-server/server/services/mcpOAuth.js +264 -0
- package/dist-server/server/services/mcpOAuth.js.map +1 -0
- package/dist-server/server/services/memoryScorer.d.ts +19 -0
- package/dist-server/server/services/memoryScorer.d.ts.map +1 -0
- package/dist-server/server/services/memoryScorer.js +147 -0
- package/dist-server/server/services/memoryScorer.js.map +1 -0
- package/dist-server/server/services/repoIndexer.d.ts +91 -0
- package/dist-server/server/services/repoIndexer.d.ts.map +1 -0
- package/dist-server/server/services/repoIndexer.js +512 -0
- package/dist-server/server/services/repoIndexer.js.map +1 -0
- package/dist-server/server/services/teamRunner.d.ts +39 -0
- package/dist-server/server/services/teamRunner.d.ts.map +1 -0
- package/dist-server/server/services/teamRunner.js +76 -0
- package/dist-server/server/services/teamRunner.js.map +1 -0
- package/dist-server/server/services/worktreeManager.d.ts +27 -0
- package/dist-server/server/services/worktreeManager.d.ts.map +1 -0
- package/dist-server/server/services/worktreeManager.js +107 -0
- package/dist-server/server/services/worktreeManager.js.map +1 -0
- package/dist-server/server/types.d.ts +30 -0
- package/dist-server/server/types.d.ts.map +1 -0
- package/dist-server/server/types.js +2 -0
- package/dist-server/server/types.js.map +1 -0
- package/dist-server/server/utils/pathSecurity.d.ts +34 -0
- package/dist-server/server/utils/pathSecurity.d.ts.map +1 -0
- package/dist-server/server/utils/pathSecurity.js +78 -0
- package/dist-server/server/utils/pathSecurity.js.map +1 -0
- package/dist-server/src/services/budgetAllocator.d.ts +37 -0
- package/dist-server/src/services/budgetAllocator.d.ts.map +1 -0
- package/dist-server/src/services/budgetAllocator.js +120 -0
- package/dist-server/src/services/budgetAllocator.js.map +1 -0
- package/dist-server/src/services/contradictionDetector.d.ts +18 -0
- package/dist-server/src/services/contradictionDetector.d.ts.map +1 -0
- package/dist-server/src/services/contradictionDetector.js +111 -0
- package/dist-server/src/services/contradictionDetector.js.map +1 -0
- package/dist-server/src/services/treeIndexer.d.ts +91 -0
- package/dist-server/src/services/treeIndexer.d.ts.map +1 -0
- package/dist-server/src/services/treeIndexer.js +289 -0
- package/dist-server/src/services/treeIndexer.js.map +1 -0
- package/dist-server/src/store/knowledgeBase.d.ts +130 -0
- package/dist-server/src/store/knowledgeBase.d.ts.map +1 -0
- package/dist-server/src/store/knowledgeBase.js +299 -0
- package/dist-server/src/store/knowledgeBase.js.map +1 -0
- package/dist-server/tsconfig.server.tsbuildinfo +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Repository Indexer
|
|
3
|
+
*
|
|
4
|
+
* Shallow-clones a GitHub repo (or any git URL) into a temp directory,
|
|
5
|
+
* runs the repo scanner, generates tree index, then cleans up.
|
|
6
|
+
*
|
|
7
|
+
* This is the bridge between "point at a GitHub URL" and
|
|
8
|
+
* "get a tree-indexed knowledge base for an agent."
|
|
9
|
+
*/
|
|
10
|
+
import { type RepoScan } from './repoIndexer.js';
|
|
11
|
+
export interface LocalRepoIndexRequest {
|
|
12
|
+
path: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
subdir?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface GitHubIndexRequest {
|
|
17
|
+
/** GitHub URL (https://github.com/owner/repo) or any git clone URL */
|
|
18
|
+
url: string;
|
|
19
|
+
/** Specific branch/tag/commit to check out (default: HEAD) */
|
|
20
|
+
ref?: string;
|
|
21
|
+
/** Subdirectory within the repo to focus on (e.g. "packages/frontend") */
|
|
22
|
+
subdir?: string;
|
|
23
|
+
/** Keep the clone on disk (default: false, auto-cleanup) */
|
|
24
|
+
persist?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface GitHubIndexResult {
|
|
27
|
+
/** Repo name (from package.json or URL) */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Base GitHub blob URL for building file links */
|
|
30
|
+
baseUrl?: string;
|
|
31
|
+
/** Where it was cloned (only if persist=true) */
|
|
32
|
+
clonePath?: string;
|
|
33
|
+
/** Full repo scan data */
|
|
34
|
+
scan: RepoScan;
|
|
35
|
+
/** Generated markdown knowledge base (filename → content) */
|
|
36
|
+
knowledgeDocs: Map<string, string>;
|
|
37
|
+
/** Overview doc (ready for tree indexing) */
|
|
38
|
+
overviewMarkdown: string;
|
|
39
|
+
/** All knowledge docs concatenated (ready for tree indexing) */
|
|
40
|
+
fullMarkdown: string;
|
|
41
|
+
/** Timing */
|
|
42
|
+
timing: {
|
|
43
|
+
cloneMs: number;
|
|
44
|
+
scanMs: number;
|
|
45
|
+
generateMs: number;
|
|
46
|
+
totalMs: number;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export declare function indexLocalRepo(request: LocalRepoIndexRequest): Promise<GitHubIndexResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Clone a GitHub repo, scan it, generate tree-indexable knowledge, optionally clean up.
|
|
52
|
+
*/
|
|
53
|
+
export declare function indexGitHubRepo(request: GitHubIndexRequest): Promise<GitHubIndexResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Index multiple repos in parallel (for multi-agent scenarios).
|
|
56
|
+
* Returns a map of repo URL → index result.
|
|
57
|
+
*/
|
|
58
|
+
export declare function indexMultipleRepos(repos: GitHubIndexRequest[]): Promise<Map<string, GitHubIndexResult>>;
|
|
59
|
+
//# sourceMappingURL=githubIndexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"githubIndexer.d.ts","sourceRoot":"","sources":["../../../server/services/githubIndexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAA8D,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI7G,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,6DAA6D;IAC7D,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,6CAA6C;IAC7C,gBAAgB,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AA+BD,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiC/F;AAID;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4F7F;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,kBAAkB,EAAE,GAC1B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAkBzC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Repository Indexer
|
|
3
|
+
*
|
|
4
|
+
* Shallow-clones a GitHub repo (or any git URL) into a temp directory,
|
|
5
|
+
* runs the repo scanner, generates tree index, then cleans up.
|
|
6
|
+
*
|
|
7
|
+
* This is the bridge between "point at a GitHub URL" and
|
|
8
|
+
* "get a tree-indexed knowledge base for an agent."
|
|
9
|
+
*/
|
|
10
|
+
import { execSync } from 'node:child_process';
|
|
11
|
+
import { mkdtempSync, rmSync, existsSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { scanRepository, generateKnowledgeBase, generateOverviewDoc } from './repoIndexer.js';
|
|
15
|
+
// ── Helpers ──
|
|
16
|
+
function parseGitUrl(url) {
|
|
17
|
+
// Handle: https://github.com/owner/repo, https://github.com/owner/repo.git
|
|
18
|
+
// Also: git@github.com:owner/repo.git
|
|
19
|
+
const httpsMatch = url.match(/github\.com\/([^/]+)\/([^/.]+)/);
|
|
20
|
+
if (httpsMatch)
|
|
21
|
+
return { owner: httpsMatch[1], repo: httpsMatch[2] };
|
|
22
|
+
const sshMatch = url.match(/github\.com:([^/]+)\/([^/.]+)/);
|
|
23
|
+
if (sshMatch)
|
|
24
|
+
return { owner: sshMatch[1], repo: sshMatch[2] };
|
|
25
|
+
// Fallback: use last path segment
|
|
26
|
+
const segments = url.replace(/\.git$/, '').split('/');
|
|
27
|
+
return { owner: segments[segments.length - 2] || 'unknown', repo: segments[segments.length - 1] || 'unknown' };
|
|
28
|
+
}
|
|
29
|
+
function normalizeGitUrl(url) {
|
|
30
|
+
// Ensure it ends with .git for clone
|
|
31
|
+
if (!url.endsWith('.git'))
|
|
32
|
+
return `${url}.git`;
|
|
33
|
+
return url;
|
|
34
|
+
}
|
|
35
|
+
function buildGitHubBaseUrl(url, ref) {
|
|
36
|
+
if (!url.includes('github.com'))
|
|
37
|
+
return undefined;
|
|
38
|
+
const { owner, repo } = parseGitUrl(url);
|
|
39
|
+
const branch = ref || 'HEAD';
|
|
40
|
+
return `https://github.com/${owner}/${repo}/blob/${branch}/`;
|
|
41
|
+
}
|
|
42
|
+
export async function indexLocalRepo(request) {
|
|
43
|
+
const t0 = Date.now();
|
|
44
|
+
const { path, subdir } = request;
|
|
45
|
+
const scanRoot = subdir ? join(path, subdir) : path;
|
|
46
|
+
if (!existsSync(scanRoot)) {
|
|
47
|
+
throw new Error(`Subdirectory "${subdir}" not found in repository path`);
|
|
48
|
+
}
|
|
49
|
+
const scanStart = Date.now();
|
|
50
|
+
const scan = scanRepository(scanRoot);
|
|
51
|
+
if (request.name)
|
|
52
|
+
scan.name = request.name;
|
|
53
|
+
const scanMs = Date.now() - scanStart;
|
|
54
|
+
const genStart = Date.now();
|
|
55
|
+
const knowledgeDocs = generateKnowledgeBase(scan);
|
|
56
|
+
const overviewMarkdown = generateOverviewDoc(scan);
|
|
57
|
+
const sortedKeys = [...knowledgeDocs.keys()].sort();
|
|
58
|
+
const fullMarkdown = sortedKeys.map((k) => knowledgeDocs.get(k)).join('\n\n---\n\n');
|
|
59
|
+
const generateMs = Date.now() - genStart;
|
|
60
|
+
return {
|
|
61
|
+
name: scan.name,
|
|
62
|
+
scan,
|
|
63
|
+
knowledgeDocs,
|
|
64
|
+
overviewMarkdown,
|
|
65
|
+
fullMarkdown,
|
|
66
|
+
timing: {
|
|
67
|
+
cloneMs: 0,
|
|
68
|
+
scanMs,
|
|
69
|
+
generateMs,
|
|
70
|
+
totalMs: Date.now() - t0,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// ── Main ──
|
|
75
|
+
/**
|
|
76
|
+
* Clone a GitHub repo, scan it, generate tree-indexable knowledge, optionally clean up.
|
|
77
|
+
*/
|
|
78
|
+
export async function indexGitHubRepo(request) {
|
|
79
|
+
const t0 = Date.now();
|
|
80
|
+
const { url, ref, subdir, persist } = request;
|
|
81
|
+
const { repo } = parseGitUrl(url);
|
|
82
|
+
const cloneUrl = normalizeGitUrl(url);
|
|
83
|
+
const baseUrl = buildGitHubBaseUrl(url, ref);
|
|
84
|
+
// 1. Clone into temp directory (shallow for speed)
|
|
85
|
+
const tempDir = mkdtempSync(join(tmpdir(), `modular-gh-${repo}-`));
|
|
86
|
+
try {
|
|
87
|
+
const cloneStart = Date.now();
|
|
88
|
+
const depthArg = '--depth 1';
|
|
89
|
+
const branchArg = ref ? `--branch ${ref}` : '';
|
|
90
|
+
try {
|
|
91
|
+
execSync(`git clone ${depthArg} ${branchArg} --single-branch "${cloneUrl}" "${tempDir}"`, { stdio: 'pipe', timeout: 60_000 });
|
|
92
|
+
}
|
|
93
|
+
catch (cloneErr) {
|
|
94
|
+
// On Windows, filenames with colons (e.g. timestamps) cause checkout
|
|
95
|
+
// failures even though the clone (object fetch) succeeds. Detect this
|
|
96
|
+
// and recover: the .git dir exists, just some files couldn't checkout.
|
|
97
|
+
const gitDir = join(tempDir, '.git');
|
|
98
|
+
if (existsSync(gitDir)) {
|
|
99
|
+
// Best-effort checkout of whatever files Windows can handle
|
|
100
|
+
try {
|
|
101
|
+
execSync('git checkout HEAD -- .', { cwd: tempDir, stdio: 'pipe', timeout: 30_000 });
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Some files still fail — that's fine, we index what we can
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// Genuine clone failure (network, auth, etc.)
|
|
109
|
+
throw cloneErr;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const cloneMs = Date.now() - cloneStart;
|
|
113
|
+
// 2. Determine scan root (may be a subdirectory)
|
|
114
|
+
const scanRoot = subdir ? join(tempDir, subdir) : tempDir;
|
|
115
|
+
if (!existsSync(scanRoot)) {
|
|
116
|
+
throw new Error(`Subdirectory "${subdir}" not found in cloned repo`);
|
|
117
|
+
}
|
|
118
|
+
// 3. Scan the repository
|
|
119
|
+
const scanStart = Date.now();
|
|
120
|
+
const scan = scanRepository(scanRoot);
|
|
121
|
+
// Override the name with the GitHub repo name
|
|
122
|
+
scan.name = repo;
|
|
123
|
+
const scanMs = Date.now() - scanStart;
|
|
124
|
+
// 4. Generate knowledge base markdown
|
|
125
|
+
const genStart = Date.now();
|
|
126
|
+
const knowledgeDocs = generateKnowledgeBase(scan);
|
|
127
|
+
const overviewMarkdown = generateOverviewDoc(scan);
|
|
128
|
+
// Concatenate all docs into a single markdown for tree indexing
|
|
129
|
+
const allDocs = [];
|
|
130
|
+
const sortedKeys = [...knowledgeDocs.keys()].sort();
|
|
131
|
+
for (const key of sortedKeys) {
|
|
132
|
+
allDocs.push(knowledgeDocs.get(key));
|
|
133
|
+
}
|
|
134
|
+
const fullMarkdown = allDocs.join('\n\n---\n\n');
|
|
135
|
+
const generateMs = Date.now() - genStart;
|
|
136
|
+
const result = {
|
|
137
|
+
name: repo,
|
|
138
|
+
baseUrl,
|
|
139
|
+
scan,
|
|
140
|
+
knowledgeDocs,
|
|
141
|
+
overviewMarkdown,
|
|
142
|
+
fullMarkdown,
|
|
143
|
+
timing: {
|
|
144
|
+
cloneMs,
|
|
145
|
+
scanMs,
|
|
146
|
+
generateMs,
|
|
147
|
+
totalMs: Date.now() - t0,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
if (persist) {
|
|
151
|
+
result.clonePath = tempDir;
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
// Clean up unless persist requested
|
|
157
|
+
if (!persist) {
|
|
158
|
+
try {
|
|
159
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
catch { /* best effort */ }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Index multiple repos in parallel (for multi-agent scenarios).
|
|
167
|
+
* Returns a map of repo URL → index result.
|
|
168
|
+
*/
|
|
169
|
+
export async function indexMultipleRepos(repos) {
|
|
170
|
+
const results = new Map();
|
|
171
|
+
const settled = await Promise.allSettled(repos.map(async (req) => {
|
|
172
|
+
const result = await indexGitHubRepo(req);
|
|
173
|
+
return { url: req.url, result };
|
|
174
|
+
}));
|
|
175
|
+
for (const outcome of settled) {
|
|
176
|
+
if (outcome.status === 'fulfilled') {
|
|
177
|
+
results.set(outcome.value.url, outcome.value.result);
|
|
178
|
+
}
|
|
179
|
+
// Skip failed ones — caller can check which URLs are missing
|
|
180
|
+
}
|
|
181
|
+
return results;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=githubIndexer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"githubIndexer.js","sourceRoot":"","sources":["../../../server/services/githubIndexer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP OAuth 2.0 + PKCE service for Streamable HTTP servers.
|
|
3
|
+
*
|
|
4
|
+
* Flow: discover → register (dynamic) → authorize (popup) → callback → token storage
|
|
5
|
+
* Spec: MCP Streamable HTTP transport with OAuth as of 2025-03-26
|
|
6
|
+
*/
|
|
7
|
+
interface OAuthMetadata {
|
|
8
|
+
issuer: string;
|
|
9
|
+
authorization_endpoint: string;
|
|
10
|
+
token_endpoint: string;
|
|
11
|
+
registration_endpoint?: string;
|
|
12
|
+
token_endpoint_auth_methods_supported?: string[];
|
|
13
|
+
code_challenge_methods_supported?: string[];
|
|
14
|
+
scopes_supported?: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function discoverOAuth(serverUrl: string): Promise<OAuthMetadata>;
|
|
17
|
+
export declare function startOAuthFlow(serverUrl: string, redirectUri: string, preregisteredClientId?: string): Promise<{
|
|
18
|
+
authUrl: string;
|
|
19
|
+
state: string;
|
|
20
|
+
}>;
|
|
21
|
+
export declare function handleCallback(code: string, state: string, redirectUri: string): Promise<{
|
|
22
|
+
serverUrl: string;
|
|
23
|
+
}>;
|
|
24
|
+
export declare function getToken(serverUrl: string): Promise<string | null>;
|
|
25
|
+
export declare function getConnectionStatus(serverUrl: string): Promise<{
|
|
26
|
+
connected: boolean;
|
|
27
|
+
expiresAt?: number;
|
|
28
|
+
}>;
|
|
29
|
+
export declare function disconnect(serverUrl: string): Promise<void>;
|
|
30
|
+
export declare function listConnectedServers(): Promise<string[]>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=mcpOAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpOAuth.d.ts","sourceRoot":"","sources":["../../../server/services/mcpOAuth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qCAAqC,CAAC,EAAE,MAAM,EAAE,CAAC;IACjD,gCAAgC,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AA2DD,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAc7E;AAkDD,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,qBAAqB,CAAC,EAAE,MAAM,GAC7B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiD7C;AAID,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAiDhC;AAuDD,wBAAsB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBxE;AAED,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAMD;AAED,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjE;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAO9D"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP OAuth 2.0 + PKCE service for Streamable HTTP servers.
|
|
3
|
+
*
|
|
4
|
+
* Flow: discover → register (dynamic) → authorize (popup) → callback → token storage
|
|
5
|
+
* Spec: MCP Streamable HTTP transport with OAuth as of 2025-03-26
|
|
6
|
+
*/
|
|
7
|
+
import { randomBytes, createHash } from 'node:crypto';
|
|
8
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const DATA_DIR = join(__dirname, '..', 'data');
|
|
13
|
+
const TOKEN_FILE = join(DATA_DIR, 'mcp-tokens.json');
|
|
14
|
+
const CLIENT_FILE = join(DATA_DIR, 'mcp-clients.json');
|
|
15
|
+
// ── State ──
|
|
16
|
+
// SECURITY FIX: Limit pending OAuth flows to prevent memory exhaustion
|
|
17
|
+
const MAX_PENDING_FLOWS = 100;
|
|
18
|
+
const pendingFlows = new Map();
|
|
19
|
+
// ── Persistence helpers ──
|
|
20
|
+
async function ensureDataDir() {
|
|
21
|
+
await mkdir(DATA_DIR, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
async function loadJson(path) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(await readFile(path, 'utf-8'));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function saveJson(path, data) {
|
|
32
|
+
await ensureDataDir();
|
|
33
|
+
// SECURITY FIX: Set secure file permissions (owner read/write only)
|
|
34
|
+
// TODO: For production use, implement encryption at rest
|
|
35
|
+
await writeFile(path, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
36
|
+
}
|
|
37
|
+
// ── PKCE ──
|
|
38
|
+
function generateCodeVerifier() {
|
|
39
|
+
return randomBytes(32).toString('base64url');
|
|
40
|
+
}
|
|
41
|
+
function generateCodeChallenge(verifier) {
|
|
42
|
+
return createHash('sha256').update(verifier).digest('base64url');
|
|
43
|
+
}
|
|
44
|
+
// ── Discovery ──
|
|
45
|
+
export async function discoverOAuth(serverUrl) {
|
|
46
|
+
const base = new URL(serverUrl);
|
|
47
|
+
// Try MCP-standard well-known path first, then RFC 8414
|
|
48
|
+
const paths = [
|
|
49
|
+
`${base.origin}/.well-known/oauth-authorization-server`,
|
|
50
|
+
`${base.origin}/.well-known/openid-configuration`,
|
|
51
|
+
];
|
|
52
|
+
for (const url of paths) {
|
|
53
|
+
try {
|
|
54
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
55
|
+
if (resp.ok)
|
|
56
|
+
return await resp.json();
|
|
57
|
+
}
|
|
58
|
+
catch { /* try next */ }
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`OAuth discovery failed for ${serverUrl} — no .well-known endpoint found`);
|
|
61
|
+
}
|
|
62
|
+
// ── Dynamic Client Registration ──
|
|
63
|
+
async function getOrRegisterClient(metadata, serverUrl, redirectUri) {
|
|
64
|
+
const cache = await loadJson(CLIENT_FILE);
|
|
65
|
+
if (cache[serverUrl])
|
|
66
|
+
return cache[serverUrl];
|
|
67
|
+
if (!metadata.registration_endpoint) {
|
|
68
|
+
throw new Error(`${serverUrl} does not support Dynamic Client Registration. ` +
|
|
69
|
+
`Configure a client_id manually in the registry entry.`);
|
|
70
|
+
}
|
|
71
|
+
const resp = await fetch(metadata.registration_endpoint, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers: { 'Content-Type': 'application/json' },
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
client_name: 'Modular Patchbay',
|
|
76
|
+
redirect_uris: [redirectUri],
|
|
77
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
78
|
+
response_types: ['code'],
|
|
79
|
+
token_endpoint_auth_method: 'none', // public client, PKCE
|
|
80
|
+
}),
|
|
81
|
+
signal: AbortSignal.timeout(10_000),
|
|
82
|
+
});
|
|
83
|
+
if (!resp.ok) {
|
|
84
|
+
const body = await resp.text();
|
|
85
|
+
throw new Error(`Client registration failed at ${metadata.registration_endpoint}: ${resp.status} — ${body}`);
|
|
86
|
+
}
|
|
87
|
+
const data = await resp.json();
|
|
88
|
+
const creds = {
|
|
89
|
+
client_id: data.client_id,
|
|
90
|
+
client_secret: data.client_secret,
|
|
91
|
+
};
|
|
92
|
+
cache[serverUrl] = creds;
|
|
93
|
+
await saveJson(CLIENT_FILE, cache);
|
|
94
|
+
return creds;
|
|
95
|
+
}
|
|
96
|
+
// ── Start Auth Flow ──
|
|
97
|
+
export async function startOAuthFlow(serverUrl, redirectUri, preregisteredClientId) {
|
|
98
|
+
const metadata = await discoverOAuth(serverUrl);
|
|
99
|
+
let clientCredentials;
|
|
100
|
+
if (preregisteredClientId) {
|
|
101
|
+
clientCredentials = { client_id: preregisteredClientId };
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
clientCredentials = await getOrRegisterClient(metadata, serverUrl, redirectUri);
|
|
105
|
+
}
|
|
106
|
+
// SECURITY FIX: Clean expired flows before adding new ones
|
|
107
|
+
for (const [k, v] of pendingFlows) {
|
|
108
|
+
if (Date.now() - v.createdAt > 600_000)
|
|
109
|
+
pendingFlows.delete(k);
|
|
110
|
+
}
|
|
111
|
+
// SECURITY FIX: Reject new flows if we're at the limit
|
|
112
|
+
if (pendingFlows.size >= MAX_PENDING_FLOWS) {
|
|
113
|
+
throw new Error('Too many pending OAuth flows. Please try again later.');
|
|
114
|
+
}
|
|
115
|
+
const codeVerifier = generateCodeVerifier();
|
|
116
|
+
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
117
|
+
const state = randomBytes(16).toString('hex');
|
|
118
|
+
const params = new URLSearchParams({
|
|
119
|
+
response_type: 'code',
|
|
120
|
+
client_id: clientCredentials.client_id,
|
|
121
|
+
redirect_uri: redirectUri,
|
|
122
|
+
code_challenge: codeChallenge,
|
|
123
|
+
code_challenge_method: 'S256',
|
|
124
|
+
state,
|
|
125
|
+
});
|
|
126
|
+
if (metadata.scopes_supported?.length) {
|
|
127
|
+
params.set('scope', metadata.scopes_supported.join(' '));
|
|
128
|
+
}
|
|
129
|
+
pendingFlows.set(state, {
|
|
130
|
+
serverUrl,
|
|
131
|
+
codeVerifier,
|
|
132
|
+
clientCredentials,
|
|
133
|
+
metadata,
|
|
134
|
+
createdAt: Date.now(),
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
authUrl: `${metadata.authorization_endpoint}?${params}`,
|
|
138
|
+
state,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// ── Handle Callback ──
|
|
142
|
+
export async function handleCallback(code, state, redirectUri) {
|
|
143
|
+
const flow = pendingFlows.get(state);
|
|
144
|
+
if (!flow)
|
|
145
|
+
throw new Error('Unknown or expired OAuth state');
|
|
146
|
+
pendingFlows.delete(state);
|
|
147
|
+
const body = {
|
|
148
|
+
grant_type: 'authorization_code',
|
|
149
|
+
code,
|
|
150
|
+
redirect_uri: redirectUri,
|
|
151
|
+
client_id: flow.clientCredentials.client_id,
|
|
152
|
+
code_verifier: flow.codeVerifier,
|
|
153
|
+
};
|
|
154
|
+
if (flow.clientCredentials.client_secret) {
|
|
155
|
+
body.client_secret = flow.clientCredentials.client_secret;
|
|
156
|
+
}
|
|
157
|
+
const resp = await fetch(flow.metadata.token_endpoint, {
|
|
158
|
+
method: 'POST',
|
|
159
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
160
|
+
body: new URLSearchParams(body),
|
|
161
|
+
signal: AbortSignal.timeout(10_000),
|
|
162
|
+
});
|
|
163
|
+
if (!resp.ok) {
|
|
164
|
+
const errBody = await resp.text();
|
|
165
|
+
throw new Error(`Token exchange failed: ${resp.status} — ${errBody}`);
|
|
166
|
+
}
|
|
167
|
+
const tokenData = await resp.json();
|
|
168
|
+
const tokenSet = {
|
|
169
|
+
access_token: tokenData.access_token,
|
|
170
|
+
refresh_token: tokenData.refresh_token,
|
|
171
|
+
token_type: tokenData.token_type || 'Bearer',
|
|
172
|
+
scope: tokenData.scope,
|
|
173
|
+
expires_at: tokenData.expires_in
|
|
174
|
+
? Date.now() + tokenData.expires_in * 1000
|
|
175
|
+
: undefined,
|
|
176
|
+
};
|
|
177
|
+
await storeToken(flow.serverUrl, tokenSet);
|
|
178
|
+
return { serverUrl: flow.serverUrl };
|
|
179
|
+
}
|
|
180
|
+
// ── Token Storage ──
|
|
181
|
+
async function refreshToken(serverUrl, token) {
|
|
182
|
+
// We need the client credentials and token endpoint to refresh
|
|
183
|
+
const clients = await loadJson(CLIENT_FILE);
|
|
184
|
+
const client = clients[serverUrl];
|
|
185
|
+
if (!client)
|
|
186
|
+
throw new Error('No client credentials for refresh');
|
|
187
|
+
// Re-discover to get token_endpoint
|
|
188
|
+
const metadata = await discoverOAuth(serverUrl);
|
|
189
|
+
const body = {
|
|
190
|
+
grant_type: 'refresh_token',
|
|
191
|
+
refresh_token: token.refresh_token,
|
|
192
|
+
client_id: client.client_id,
|
|
193
|
+
};
|
|
194
|
+
if (client.client_secret)
|
|
195
|
+
body.client_secret = client.client_secret;
|
|
196
|
+
const resp = await fetch(metadata.token_endpoint, {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
199
|
+
body: new URLSearchParams(body),
|
|
200
|
+
signal: AbortSignal.timeout(10_000),
|
|
201
|
+
});
|
|
202
|
+
if (!resp.ok)
|
|
203
|
+
throw new Error('Token refresh failed: ' + resp.status);
|
|
204
|
+
const data = await resp.json();
|
|
205
|
+
const newToken = {
|
|
206
|
+
access_token: data.access_token,
|
|
207
|
+
refresh_token: data.refresh_token || token.refresh_token, // keep old refresh if none returned
|
|
208
|
+
token_type: data.token_type || 'Bearer',
|
|
209
|
+
scope: data.scope || token.scope,
|
|
210
|
+
expires_at: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined,
|
|
211
|
+
};
|
|
212
|
+
await storeToken(serverUrl, newToken);
|
|
213
|
+
return newToken.access_token;
|
|
214
|
+
}
|
|
215
|
+
async function storeToken(serverUrl, token) {
|
|
216
|
+
const tokens = await loadJson(TOKEN_FILE);
|
|
217
|
+
tokens[serverUrl] = token;
|
|
218
|
+
await saveJson(TOKEN_FILE, tokens);
|
|
219
|
+
}
|
|
220
|
+
export async function getToken(serverUrl) {
|
|
221
|
+
const tokens = await loadJson(TOKEN_FILE);
|
|
222
|
+
const token = tokens[serverUrl];
|
|
223
|
+
if (!token)
|
|
224
|
+
return null;
|
|
225
|
+
// Check expiry with 60s buffer
|
|
226
|
+
if (token.expires_at && Date.now() > token.expires_at - 60_000) {
|
|
227
|
+
if (token.refresh_token) {
|
|
228
|
+
try {
|
|
229
|
+
return await refreshToken(serverUrl, token);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return null; // refresh failed, need re-auth
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
return token.access_token;
|
|
238
|
+
}
|
|
239
|
+
export async function getConnectionStatus(serverUrl) {
|
|
240
|
+
const tokens = await loadJson(TOKEN_FILE);
|
|
241
|
+
const token = tokens[serverUrl];
|
|
242
|
+
if (!token)
|
|
243
|
+
return { connected: false };
|
|
244
|
+
const expired = token.expires_at ? Date.now() > token.expires_at : false;
|
|
245
|
+
return { connected: !expired, expiresAt: token.expires_at };
|
|
246
|
+
}
|
|
247
|
+
export async function disconnect(serverUrl) {
|
|
248
|
+
const tokens = await loadJson(TOKEN_FILE);
|
|
249
|
+
delete tokens[serverUrl];
|
|
250
|
+
await saveJson(TOKEN_FILE, tokens);
|
|
251
|
+
const clients = await loadJson(CLIENT_FILE);
|
|
252
|
+
delete clients[serverUrl];
|
|
253
|
+
await saveJson(CLIENT_FILE, clients);
|
|
254
|
+
}
|
|
255
|
+
export async function listConnectedServers() {
|
|
256
|
+
const tokens = await loadJson(TOKEN_FILE);
|
|
257
|
+
return Object.keys(tokens).filter(url => {
|
|
258
|
+
const t = tokens[url];
|
|
259
|
+
if (t.expires_at && Date.now() > t.expires_at)
|
|
260
|
+
return false;
|
|
261
|
+
return true;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=mcpOAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpOAuth.js","sourceRoot":"","sources":["../../../server/services/mcpOAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ExtractedFact } from './factExtractor.js';
|
|
2
|
+
export interface ScoredFact extends ExtractedFact {
|
|
3
|
+
score: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function scoreFact(fact: ExtractedFact, query: string, now?: number): number;
|
|
6
|
+
export declare function rankFacts(facts: ExtractedFact[], query: string, limit?: number, now?: number): ExtractedFact[];
|
|
7
|
+
export declare function computeStrength(fact: ExtractedFact, now?: number): number;
|
|
8
|
+
export declare function textSimilarity(a: string, b: string): number;
|
|
9
|
+
export interface ConsolidationResult {
|
|
10
|
+
kept: ExtractedFact[];
|
|
11
|
+
pruned: ExtractedFact[];
|
|
12
|
+
merged: Array<{
|
|
13
|
+
merged: ExtractedFact;
|
|
14
|
+
from: ExtractedFact[];
|
|
15
|
+
}>;
|
|
16
|
+
promoted: ExtractedFact[];
|
|
17
|
+
}
|
|
18
|
+
export declare function consolidateMemory(facts: ExtractedFact[], now?: number): ConsolidationResult;
|
|
19
|
+
//# sourceMappingURL=memoryScorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryScorer.d.ts","sourceRoot":"","sources":["../../../server/services/memoryScorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAqBlF;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAsB9G;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAezE;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAgB3D;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,MAAM,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,aAAa,CAAC;QAAC,IAAI,EAAE,aAAa,EAAE,CAAA;KAAE,CAAC,CAAC;IAChE,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,mBAAmB,CA2F3F"}
|