@4da/mcp-server 5.0.2 → 5.0.3
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/README.md +3 -3
- package/dist/auth-context.d.ts +0 -1
- package/dist/auth-context.js +0 -1
- package/dist/auth.d.ts +0 -1
- package/dist/auth.js +0 -1
- package/dist/db.d.ts +17 -2
- package/dist/db.js +93 -66
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +17 -15
- package/dist/embeddings.d.ts +0 -1
- package/dist/embeddings.js +0 -1
- package/dist/http-transport.d.ts +0 -1
- package/dist/http-transport.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +17 -5
- package/dist/live/cache.d.ts +0 -1
- package/dist/live/cache.js +0 -1
- package/dist/live/crates-registry.d.ts +0 -1
- package/dist/live/crates-registry.js +5 -8
- package/dist/live/cvss.d.ts +0 -1
- package/dist/live/cvss.js +0 -1
- package/dist/live/go-registry.d.ts +0 -1
- package/dist/live/go-registry.js +4 -9
- package/dist/live/hn-fetcher.d.ts +0 -1
- package/dist/live/hn-fetcher.js +23 -11
- package/dist/live/http-utils.d.ts +0 -1
- package/dist/live/http-utils.js +0 -1
- package/dist/live/index.d.ts +0 -1
- package/dist/live/index.js +0 -1
- package/dist/live/npm-registry.d.ts +0 -1
- package/dist/live/npm-registry.js +4 -8
- package/dist/live/osv-scanner.d.ts +0 -1
- package/dist/live/osv-scanner.js +0 -1
- package/dist/live/platform.d.ts +0 -1
- package/dist/live/platform.js +0 -1
- package/dist/live/pypi-registry.d.ts +0 -1
- package/dist/live/pypi-registry.js +7 -10
- package/dist/live/rate-limiter.d.ts +0 -1
- package/dist/live/rate-limiter.js +0 -1
- package/dist/live/semver-utils.d.ts +11 -1
- package/dist/live/semver-utils.js +14 -1
- package/dist/live/types.d.ts +0 -1
- package/dist/live/types.js +0 -1
- package/dist/live/version-resolver.d.ts +0 -1
- package/dist/live/version-resolver.js +0 -1
- package/dist/live-singleton.d.ts +0 -1
- package/dist/live-singleton.js +0 -1
- package/dist/project-scanner.d.ts +0 -1
- package/dist/project-scanner.js +0 -1
- package/dist/schema-registry.d.ts +17 -8
- package/dist/schema-registry.js +54 -9
- package/dist/schemas/developer-dna.json +1 -1
- package/dist/schemas/get-context.json +2 -2
- package/dist/schemas/get-relevant-content.json +1 -1
- package/dist/schemas/record-feedback.json +1 -1
- package/dist/setup.d.ts +0 -1
- package/dist/setup.js +0 -1
- package/dist/tool-dispatch.d.ts +0 -1
- package/dist/tool-dispatch.js +21 -2
- package/dist/tools/agent-memory.d.ts +0 -1
- package/dist/tools/agent-memory.js +0 -1
- package/dist/tools/decision-enforcement.d.ts +0 -1
- package/dist/tools/decision-enforcement.js +0 -1
- package/dist/tools/decision-memory.d.ts +0 -1
- package/dist/tools/decision-memory.js +0 -1
- package/dist/tools/decision-recall.d.ts +0 -1
- package/dist/tools/decision-recall.js +0 -1
- package/dist/tools/dependency-health.d.ts +0 -1
- package/dist/tools/dependency-health.js +31 -5
- package/dist/tools/developer-dna.d.ts +3 -3
- package/dist/tools/developer-dna.js +63 -47
- package/dist/tools/ecosystem-pulse.d.ts +7 -2
- package/dist/tools/ecosystem-pulse.js +39 -3
- package/dist/tools/get-actionable-signals.d.ts +0 -1
- package/dist/tools/get-actionable-signals.js +0 -1
- package/dist/tools/get-context.d.ts +0 -1
- package/dist/tools/get-context.js +2 -3
- package/dist/tools/get-relevant-content.d.ts +0 -1
- package/dist/tools/get-relevant-content.js +1 -3
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.js +0 -1
- package/dist/tools/knowledge-gaps.d.ts +0 -1
- package/dist/tools/knowledge-gaps.js +79 -17
- package/dist/tools/recall.d.ts +0 -1
- package/dist/tools/recall.js +0 -1
- package/dist/tools/record-feedback.d.ts +1 -2
- package/dist/tools/record-feedback.js +7 -8
- package/dist/tools/upgrade-planner.d.ts +0 -1
- package/dist/tools/upgrade-planner.js +15 -3
- package/dist/tools/vulnerability-scan.d.ts +0 -1
- package/dist/tools/vulnerability-scan.js +0 -1
- package/dist/tools/what-should-i-know.d.ts +0 -1
- package/dist/tools/what-should-i-know.js +6 -3
- package/dist/types.d.ts +2 -3
- package/dist/types.js +0 -1
- package/package.json +37 -11
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Privacy: sends only package names — public manifest data.
|
|
9
9
|
*/
|
|
10
10
|
import { fetchJson, fetchWithTimeout } from "./http-utils.js";
|
|
11
|
-
import { computeSemverDistance,
|
|
11
|
+
import { computeSemverDistance, maxStableSemver } from "./semver-utils.js";
|
|
12
12
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
13
13
|
const NPM_DOWNLOADS_URL = "https://api.npmjs.org/downloads/point/last-week";
|
|
14
14
|
const NPM_TIMEOUT_MS = 8_000;
|
|
@@ -127,13 +127,10 @@ export class NpmRegistry {
|
|
|
127
127
|
return result;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
// Semver-max, not last-published: maintenance releases of older lines are
|
|
131
|
+
// published after newer lines (see maxStableSemver).
|
|
130
132
|
function findLatestStable(versions) {
|
|
131
|
-
|
|
132
|
-
if (!isPreRelease(versions[i])) {
|
|
133
|
-
return versions[i];
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return null;
|
|
133
|
+
return maxStableSemver(versions);
|
|
137
134
|
}
|
|
138
135
|
function errorResult(name, currentVersion, isDev, fetchError) {
|
|
139
136
|
return {
|
|
@@ -152,4 +149,3 @@ function errorResult(name, currentVersion, isDev, fetchError) {
|
|
|
152
149
|
fetchError,
|
|
153
150
|
};
|
|
154
151
|
}
|
|
155
|
-
//# sourceMappingURL=npm-registry.js.map
|
package/dist/live/osv-scanner.js
CHANGED
package/dist/live/platform.d.ts
CHANGED
|
@@ -29,4 +29,3 @@ export declare function hostTarget(): HostTarget;
|
|
|
29
29
|
export declare function targetActiveOnHost(target: string | null | undefined, host?: HostTarget): boolean;
|
|
30
30
|
/** Evaluate a cfg predicate body (already unwrapped from `cfg( ... )`). */
|
|
31
31
|
export declare function evalCfg(expr: string, host?: HostTarget): boolean;
|
|
32
|
-
//# sourceMappingURL=platform.d.ts.map
|
package/dist/live/platform.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Privacy: sends only package names -- public manifest data.
|
|
9
9
|
*/
|
|
10
10
|
import { fetchJson } from "./http-utils.js";
|
|
11
|
-
import { computeSemverDistance, isPreRelease } from "./semver-utils.js";
|
|
11
|
+
import { computeSemverDistance, isPreRelease, maxStableSemver } from "./semver-utils.js";
|
|
12
12
|
const PYPI_BASE_URL = "https://pypi.org/pypi";
|
|
13
13
|
const PYPI_TIMEOUT_MS = 8_000;
|
|
14
14
|
const PYPI_CACHE_TTL = 86_400; // 24 hours
|
|
@@ -83,17 +83,15 @@ export class PyPIRegistry {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
function findLatestStable(versions, releases) {
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
// Semver-max among eligible versions, not last-listed (see maxStableSemver).
|
|
87
|
+
const eligible = versions.filter((v) => {
|
|
88
88
|
if (isPreRelease(v))
|
|
89
|
-
|
|
89
|
+
return false;
|
|
90
90
|
// Skip if all files for this version are yanked
|
|
91
91
|
const files = releases[v];
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
return null;
|
|
92
|
+
return !(files && files.length > 0 && files.every((f) => f.yanked));
|
|
93
|
+
});
|
|
94
|
+
return maxStableSemver(eligible);
|
|
97
95
|
}
|
|
98
96
|
function getLastPublished(files) {
|
|
99
97
|
if (!files || files.length === 0)
|
|
@@ -139,4 +137,3 @@ function errorResult(name, currentVersion, isDev, fetchError) {
|
|
|
139
137
|
fetchError,
|
|
140
138
|
};
|
|
141
139
|
}
|
|
142
|
-
//# sourceMappingURL=pypi-registry.js.map
|
|
@@ -10,4 +10,14 @@ export declare function isPreRelease(version: string): boolean;
|
|
|
10
10
|
export declare function compareSemver(a: string, b: string): number;
|
|
11
11
|
/** Highest version (by MAJOR.MINOR.PATCH) from a list, or null if empty. */
|
|
12
12
|
export declare function maxSemver(versions: string[]): string | null;
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Highest NON-prerelease version by semver from a list.
|
|
15
|
+
*
|
|
16
|
+
* Registries list versions in publish order, and maintenance releases for an
|
|
17
|
+
* older line land AFTER newer lines (React published 19.0.8 after 19.2.x; rsa
|
|
18
|
+
* published 0.9.10 after 0.10.0-rc.*). Taking the "last stable entry" therefore
|
|
19
|
+
* reported an older line as the latest stable — which surfaced as a bogus
|
|
20
|
+
* stable version in dependency_health and a literal DOWNGRADE recommendation
|
|
21
|
+
* in upgrade_planner. Order-independent max fixes the class.
|
|
22
|
+
*/
|
|
23
|
+
export declare function maxStableSemver(versions: string[]): string | null;
|
|
@@ -49,4 +49,17 @@ export function maxSemver(versions) {
|
|
|
49
49
|
return null;
|
|
50
50
|
return versions.reduce((max, v) => (compareSemver(v, max) > 0 ? v : max), versions[0]);
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Highest NON-prerelease version by semver from a list.
|
|
54
|
+
*
|
|
55
|
+
* Registries list versions in publish order, and maintenance releases for an
|
|
56
|
+
* older line land AFTER newer lines (React published 19.0.8 after 19.2.x; rsa
|
|
57
|
+
* published 0.9.10 after 0.10.0-rc.*). Taking the "last stable entry" therefore
|
|
58
|
+
* reported an older line as the latest stable — which surfaced as a bogus
|
|
59
|
+
* stable version in dependency_health and a literal DOWNGRADE recommendation
|
|
60
|
+
* in upgrade_planner. Order-independent max fixes the class.
|
|
61
|
+
*/
|
|
62
|
+
export function maxStableSemver(versions) {
|
|
63
|
+
const stable = versions.filter((v) => parseSemver(v) !== null && !isPreRelease(v));
|
|
64
|
+
return maxSemver(stable);
|
|
65
|
+
}
|
package/dist/live/types.d.ts
CHANGED
package/dist/live/types.js
CHANGED
|
@@ -23,4 +23,3 @@ export declare function resolveVersions(cwd: string, deps: string[], devDeps: st
|
|
|
23
23
|
* Direct dependency health and upgrade planning continue to use resolveVersions.
|
|
24
24
|
*/
|
|
25
25
|
export declare function resolveAuditVersions(cwd: string, deps: string[], devDeps: string[], language: string, targets?: Record<string, string>): ResolvedDependency[];
|
|
26
|
-
//# sourceMappingURL=version-resolver.d.ts.map
|
package/dist/live-singleton.d.ts
CHANGED
package/dist/live-singleton.js
CHANGED
package/dist/project-scanner.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Schema Registry for Dynamic Context Discovery
|
|
3
3
|
*
|
|
4
|
-
* Reduces tool listing from ~4500 tokens to ~
|
|
5
|
-
* - Returning
|
|
4
|
+
* Reduces tool listing from ~4500 tokens to ~1300 tokens by:
|
|
5
|
+
* - Returning one-liner summaries in list_tools
|
|
6
|
+
* - Serving the REAL inputSchema only for tools with REQUIRED parameters
|
|
7
|
+
* (AD-032): a client cannot construct a valid call to those without the
|
|
8
|
+
* schema, and most clients never read MCP Resources — so a slim
|
|
9
|
+
* `{type:"object"}` made required-param tools effectively uncallable.
|
|
10
|
+
* All-optional tools stay slim (`{}` is a valid call) with the full
|
|
11
|
+
* schema still available as a Resource.
|
|
6
12
|
* - Storing full schemas as MCP Resources (lazy-loaded)
|
|
7
13
|
*
|
|
8
14
|
* Also provides category/tag metadata for tool discovery and filtering.
|
|
@@ -39,16 +45,20 @@ export interface ToolRegistryEntry {
|
|
|
39
45
|
* 14 tools total: 9 standalone + 5 full-mode.
|
|
40
46
|
*/
|
|
41
47
|
export declare const TOOL_REGISTRY: Record<string, ToolRegistryEntry>;
|
|
48
|
+
/** An inputSchema as tools/list serves it — the MCP Tool contract requires
|
|
49
|
+
* the literal `type: "object"` at the root. */
|
|
50
|
+
export type ToolInputSchema = {
|
|
51
|
+
type: "object";
|
|
52
|
+
} & Record<string, unknown>;
|
|
42
53
|
/**
|
|
43
|
-
* Get
|
|
44
|
-
*
|
|
54
|
+
* Get the tool list for the tools/list response: slim summaries throughout,
|
|
55
|
+
* real inputSchema for required-param tools, `{type:"object"}` otherwise
|
|
56
|
+
* (full schema via resources).
|
|
45
57
|
*/
|
|
46
58
|
export declare function getSlimToolList(standaloneOnly?: boolean): Array<{
|
|
47
59
|
name: string;
|
|
48
60
|
description: string;
|
|
49
|
-
inputSchema:
|
|
50
|
-
type: "object";
|
|
51
|
-
};
|
|
61
|
+
inputSchema: ToolInputSchema;
|
|
52
62
|
annotations: ToolAnnotations;
|
|
53
63
|
}>;
|
|
54
64
|
/**
|
|
@@ -77,4 +87,3 @@ export declare function getCategoryManifest(): {
|
|
|
77
87
|
};
|
|
78
88
|
/** Find tools matching any of the given tags */
|
|
79
89
|
export declare function getToolsByTags(tags: string[]): string[];
|
|
80
|
-
//# sourceMappingURL=schema-registry.d.ts.map
|
package/dist/schema-registry.js
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Schema Registry for Dynamic Context Discovery
|
|
4
4
|
*
|
|
5
|
-
* Reduces tool listing from ~4500 tokens to ~
|
|
6
|
-
* - Returning
|
|
5
|
+
* Reduces tool listing from ~4500 tokens to ~1300 tokens by:
|
|
6
|
+
* - Returning one-liner summaries in list_tools
|
|
7
|
+
* - Serving the REAL inputSchema only for tools with REQUIRED parameters
|
|
8
|
+
* (AD-032): a client cannot construct a valid call to those without the
|
|
9
|
+
* schema, and most clients never read MCP Resources — so a slim
|
|
10
|
+
* `{type:"object"}` made required-param tools effectively uncallable.
|
|
11
|
+
* All-optional tools stay slim (`{}` is a valid call) with the full
|
|
12
|
+
* schema still available as a Resource.
|
|
7
13
|
* - Storing full schemas as MCP Resources (lazy-loaded)
|
|
8
14
|
*
|
|
9
15
|
* Also provides category/tag metadata for tool discovery and filtering.
|
|
@@ -11,6 +17,9 @@
|
|
|
11
17
|
* Full schemas available at: 4da://schema/{tool_name}
|
|
12
18
|
* Category manifest at: 4da://categories
|
|
13
19
|
*/
|
|
20
|
+
import { readFileSync } from "node:fs";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { dirname, join } from "node:path";
|
|
14
23
|
/**
|
|
15
24
|
* Slim tool registry — one-liner descriptions + category/tag metadata.
|
|
16
25
|
* Full schemas are stored in schemas/*.json and exposed as MCP Resources.
|
|
@@ -61,7 +70,7 @@ export const TOOL_REGISTRY = {
|
|
|
61
70
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
62
71
|
},
|
|
63
72
|
get_context: {
|
|
64
|
-
summary: "What 4DA knows about the user: role, tech stack, interests, and
|
|
73
|
+
summary: "What 4DA knows about the user: role, tech stack, interests, exclusions, and ACE-detected context. Call FIRST when you need to know what the user works on before answering or recommending.",
|
|
65
74
|
schemaFile: "get-context.json",
|
|
66
75
|
category: "intelligence",
|
|
67
76
|
tags: ["context", "interests", "tech-stack", "profile"],
|
|
@@ -93,10 +102,10 @@ export const TOOL_REGISTRY = {
|
|
|
93
102
|
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
94
103
|
},
|
|
95
104
|
record_feedback: {
|
|
96
|
-
summary: "Record click/save/dismiss on a content item
|
|
105
|
+
summary: "Record click/save/dismiss on a content item as explicit interaction history. Call AFTER the user reacts to a surfaced item (opens, saves, or dismisses it).",
|
|
97
106
|
schemaFile: "record-feedback.json",
|
|
98
107
|
category: "intelligence",
|
|
99
|
-
tags: ["feedback", "
|
|
108
|
+
tags: ["feedback", "history", "save", "dismiss"],
|
|
100
109
|
standalone: false,
|
|
101
110
|
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: false, idempotentHint: false },
|
|
102
111
|
},
|
|
@@ -136,9 +145,46 @@ export const TOOL_REGISTRY = {
|
|
|
136
145
|
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
137
146
|
},
|
|
138
147
|
};
|
|
148
|
+
/** Schemas live beside this module in both layouts: src/schemas (vitest) and
|
|
149
|
+
* dist/schemas (compiled — populated by the copy-schemas build step). */
|
|
150
|
+
const SCHEMAS_DIR = join(dirname(fileURLToPath(import.meta.url)), "schemas");
|
|
151
|
+
/** Lazy cache: tool name → its real inputSchema when the schema declares
|
|
152
|
+
* required parameters, else null (tool stays slim). */
|
|
153
|
+
const requiredParamSchemas = new Map();
|
|
139
154
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
155
|
+
* The tools/list discoverability line (AD-032): a tool whose schema declares
|
|
156
|
+
* REQUIRED parameters serves its real inputSchema — `{type:"object"}` hid the
|
|
157
|
+
* required params from every client that never reads MCP Resources, making
|
|
158
|
+
* those tools fail on first call (GPT adversarial audit, finding 7). Tools
|
|
159
|
+
* whose parameters are all optional keep the slim schema: `{}` is a valid
|
|
160
|
+
* call, and the full schema stays one Resource read away. Fail-open: an
|
|
161
|
+
* unreadable or malformed schema file falls back to slim rather than
|
|
162
|
+
* breaking tools/list.
|
|
163
|
+
*/
|
|
164
|
+
function inputSchemaIfRequired(name, schemaFile) {
|
|
165
|
+
if (!requiredParamSchemas.has(name)) {
|
|
166
|
+
let loaded = null;
|
|
167
|
+
try {
|
|
168
|
+
const parsed = JSON.parse(readFileSync(join(SCHEMAS_DIR, schemaFile), "utf-8"));
|
|
169
|
+
const schema = parsed.inputSchema;
|
|
170
|
+
if (schema &&
|
|
171
|
+
schema.type === "object" &&
|
|
172
|
+
Array.isArray(schema.required) &&
|
|
173
|
+
schema.required.length > 0) {
|
|
174
|
+
loaded = schema;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
loaded = null;
|
|
179
|
+
}
|
|
180
|
+
requiredParamSchemas.set(name, loaded);
|
|
181
|
+
}
|
|
182
|
+
return requiredParamSchemas.get(name) ?? null;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get the tool list for the tools/list response: slim summaries throughout,
|
|
186
|
+
* real inputSchema for required-param tools, `{type:"object"}` otherwise
|
|
187
|
+
* (full schema via resources).
|
|
142
188
|
*/
|
|
143
189
|
export function getSlimToolList(standaloneOnly) {
|
|
144
190
|
return Object.entries(TOOL_REGISTRY)
|
|
@@ -146,7 +192,7 @@ export function getSlimToolList(standaloneOnly) {
|
|
|
146
192
|
.map(([name, info]) => ({
|
|
147
193
|
name,
|
|
148
194
|
description: info.summary,
|
|
149
|
-
inputSchema: { type: "object" },
|
|
195
|
+
inputSchema: inputSchemaIfRequired(name, info.schemaFile) ?? { type: "object" },
|
|
150
196
|
annotations: info.annotations,
|
|
151
197
|
}));
|
|
152
198
|
}
|
|
@@ -200,4 +246,3 @@ export function getToolsByTags(tags) {
|
|
|
200
246
|
.filter(([, entry]) => entry.tags.some((t) => tagSet.has(t.toLowerCase())))
|
|
201
247
|
.map(([name]) => name);
|
|
202
248
|
}
|
|
203
|
-
//# sourceMappingURL=schema-registry.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "developer_dna",
|
|
3
|
-
"description": "Export your Developer DNA — a comprehensive profile of your tech identity built from project scans,
|
|
3
|
+
"description": "Export your Developer DNA — a comprehensive profile of your tech identity built from project scans, explicit interests, and local interaction history. Includes primary stack, adjacent tech, top dependencies, engaged topics, blind spots, source engagement rates, and aggregate stats. Call when the user asks for a summary of their developer profile, identity, or tech fingerprint.",
|
|
4
4
|
"inputSchema": {
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "get_context",
|
|
3
|
-
"description": "Get the user's context - what 4DA knows about them.\n\nReturns information about:\n- Static Identity: User-declared role, tech stack, domains, interests, and exclusions\n- ACE Context (optional): Auto-detected technologies and active topics from recent activity\n- Learned Preferences (optional):
|
|
3
|
+
"description": "Get the user's context - what 4DA knows about them.\n\nReturns information about:\n- Static Identity: User-declared role, tech stack, domains, interests, and exclusions\n- ACE Context (optional): Auto-detected technologies and active topics from recent activity\n- Learned Preferences (optional): retained compatibility field; implicit preference learning no longer contributes to scoring\n\nCall FIRST when you need to understand what the user works on or cares about before answering or recommending.",
|
|
4
4
|
"inputSchema": {
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"include_learned": {
|
|
12
12
|
"type": "boolean",
|
|
13
|
-
"description": "Include learned
|
|
13
|
+
"description": "Include the retained learned-preferences compatibility field. Default: true"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "get_relevant_content",
|
|
3
|
-
"description": "Get filtered relevant content from 4DA's personalized feed.\n\nReturns content items that match the user's interests, tech stack, and
|
|
3
|
+
"description": "Get filtered relevant content from 4DA's personalized feed.\n\nReturns content items that match the user's explicit interests, tech stack, and ACE-detected context.\nItems are scored based on:\n- Explicit interests declared by the user\n- Tech stack and domains\n- ACE-detected context (recent files, projects, git activity)\n\nIMPORTANT for autonomous use: each item carries an `evidence_class` describing how it is grounded. The relevance_score float is NOT comparable across classes — gate actions on evidence_class, not the number:\n- \"osv_verified\": a security advisory matching one of the user's INSTALLED dependencies — safe to act on\n- \"dependency_grounded\": matched one of the user's declared dependencies — trustworthy\n- \"semantic_only\": topical/embedding relevance with NO dependency edge — surface to the human, verify before acting\n- \"keyword_heuristic\": standalone-mode keyword score (no Rust pipeline) — weakest signal\n\nCall when the user asks what to read, what is relevant to them, or for content on a topic.",
|
|
4
4
|
"inputSchema": {
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "record_feedback",
|
|
3
|
-
"description": "Record user
|
|
3
|
+
"description": "Record explicit user interaction history for a content item.\n\nFeedback actions:\n- \"click\": User clicked/opened the item\n- \"save\": User saved/bookmarked the item\n- \"dismiss\": User dismissed the item\n- \"mark_irrelevant\": User marked item as not relevant\n\nThis records what happened; it does not train content preferences (interaction counts only graduate scoring's bootstrap gate). Call after the user reacts to a surfaced item (opens, saves, or dismisses it).",
|
|
4
4
|
"inputSchema": {
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
package/dist/setup.d.ts
CHANGED
package/dist/setup.js
CHANGED
package/dist/tool-dispatch.d.ts
CHANGED
|
@@ -24,4 +24,3 @@ export declare function dispatchTool(name: string, db: FourDADatabase, args: Rec
|
|
|
24
24
|
export declare function hasDispatchTool(name: string): boolean;
|
|
25
25
|
/** Get count of registered tool executors */
|
|
26
26
|
export declare function getDispatchToolCount(): number;
|
|
27
|
-
//# sourceMappingURL=tool-dispatch.d.ts.map
|
package/dist/tool-dispatch.js
CHANGED
|
@@ -58,7 +58,27 @@ export async function dispatchTool(name, db, args) {
|
|
|
58
58
|
throw new Error(`Unknown tool: ${name}`);
|
|
59
59
|
}
|
|
60
60
|
assertToolPermission(name);
|
|
61
|
-
|
|
61
|
+
// BUSY/LOCKED retry at the single choke point every tool passes through.
|
|
62
|
+
// The desktop engine writes to the same database every 30 minutes; a read
|
|
63
|
+
// that collides with its transaction deserves one backoff retry rather than
|
|
64
|
+
// an immediate error JSON. (db.queryWithRetry existed for this but had no
|
|
65
|
+
// production caller — it is sync and the executors are async, so the retry
|
|
66
|
+
// lives here.)
|
|
67
|
+
const toolArgs = (args || {});
|
|
68
|
+
let result;
|
|
69
|
+
try {
|
|
70
|
+
result = await executor(db, toolArgs);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
const code = error.code;
|
|
74
|
+
if (code === "SQLITE_BUSY" || code === "SQLITE_LOCKED") {
|
|
75
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
76
|
+
result = await executor(db, toolArgs);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
62
82
|
const payload = FRESHNESS_TOOLS.has(name) ? attachFreshness(db, result) : result;
|
|
63
83
|
return {
|
|
64
84
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
@@ -94,4 +114,3 @@ export function hasDispatchTool(name) {
|
|
|
94
114
|
export function getDispatchToolCount() {
|
|
95
115
|
return Object.keys(DISPATCH_MAP).length;
|
|
96
116
|
}
|
|
97
|
-
//# sourceMappingURL=tool-dispatch.js.map
|
|
@@ -72,4 +72,3 @@ export declare const checkDecisionAlignmentTool: {
|
|
|
72
72
|
};
|
|
73
73
|
export declare function executeCheckDecisionAlignment(db: FourDADatabase, params: CheckDecisionAlignmentParams): AlignmentResult | Promise<AlignmentResult>;
|
|
74
74
|
export {};
|
|
75
|
-
//# sourceMappingURL=decision-enforcement.d.ts.map
|
|
@@ -210,4 +210,3 @@ export function executeCheckDecisionAlignment(db, params) {
|
|
|
210
210
|
// Provider configured -> hybrid retrieval (returns a Promise; dispatch awaits).
|
|
211
211
|
return hybridDecisionRecall(db, query, candidates, 50, config).then(({ ranked, semanticById, recall_mode }) => assembleAlignment(params, ranked, semanticById, recall_mode));
|
|
212
212
|
}
|
|
213
|
-
//# sourceMappingURL=decision-enforcement.js.map
|
|
@@ -56,4 +56,3 @@ export declare function decisionEmbedText(row: DecisionLike): string;
|
|
|
56
56
|
* be embedded.
|
|
57
57
|
*/
|
|
58
58
|
export declare function hybridDecisionRecall<T extends DecisionLike>(db: FourDADatabase, query: string, rows: T[], limit: number, config: EmbeddingConfig): Promise<DecisionRecallResult<T>>;
|
|
59
|
-
//# sourceMappingURL=decision-recall.d.ts.map
|
|
@@ -42,4 +42,3 @@ export declare const dependencyHealthTool: {
|
|
|
42
42
|
};
|
|
43
43
|
};
|
|
44
44
|
export declare function executeDependencyHealth(_db: FourDADatabase, params: DependencyHealthParams, liveIntel: LiveIntelligence | null): Promise<DependencyHealthResult>;
|
|
45
|
-
//# sourceMappingURL=dependency-health.d.ts.map
|
|
@@ -112,11 +112,38 @@ export async function executeDependencyHealth(_db, params, liveIntel) {
|
|
|
112
112
|
});
|
|
113
113
|
const limit = params.limit ?? 50;
|
|
114
114
|
const limited = sorted.slice(0, limit);
|
|
115
|
-
// Health score: 100 = perfect
|
|
115
|
+
// Health score: 100 = perfect. Proportional and severity-weighted — the old
|
|
116
|
+
// absolute-count formula (15 points per vulnerable package, 2 per outdated,
|
|
117
|
+
// regardless of severity, degree, or project size) pinned any real-sized
|
|
118
|
+
// project at 0/100: a patch-behind dep cost the same as a critical CVE and
|
|
119
|
+
// the number informed nothing.
|
|
116
120
|
const total = registryData.length || 1;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
// Vulnerabilities: severity-weighted; transitive findings at one-third
|
|
122
|
+
// weight (their fix arrives via a parent bump — the direct surface is what
|
|
123
|
+
// the user controls directly).
|
|
124
|
+
const sevWeight = { critical: 20, high: 10, medium: 4, low: 1 };
|
|
125
|
+
let vulnPenaltyRaw = 0;
|
|
126
|
+
if (vulnResult) {
|
|
127
|
+
for (const v of vulnResult.vulnerabilities) {
|
|
128
|
+
const w = sevWeight[v.severity] ?? 2; // "unknown" (mostly unmaintained-notices) counts low
|
|
129
|
+
vulnPenaltyRaw += v.isDirect ? w : w / 3;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const vulnPenalty = Math.min(Math.round(vulnPenaltyRaw), 55);
|
|
133
|
+
// Staleness: degree-weighted and proportional to the tracked set — a major
|
|
134
|
+
// behind is a real liability, a patch behind is routine drift.
|
|
135
|
+
let stalenessWeight = 0;
|
|
136
|
+
for (const dep of registryData) {
|
|
137
|
+
const label = dep.versionsBehind?.label;
|
|
138
|
+
if (label === "major")
|
|
139
|
+
stalenessWeight += 1;
|
|
140
|
+
else if (label === "minor")
|
|
141
|
+
stalenessWeight += 0.35;
|
|
142
|
+
else if (label === "patch")
|
|
143
|
+
stalenessWeight += 0.1;
|
|
144
|
+
}
|
|
145
|
+
const outdatedPenalty = Math.min(30, Math.round((stalenessWeight / total) * 60));
|
|
146
|
+
const deprecatedPenalty = Math.min(deprecated * 8, 15);
|
|
120
147
|
const healthScore = Math.max(0, 100 - vulnPenalty - deprecatedPenalty - outdatedPenalty);
|
|
121
148
|
const vulnSummary = vulnResult ? {
|
|
122
149
|
critical: vulnResult.bySeverity.critical,
|
|
@@ -151,4 +178,3 @@ export async function executeDependencyHealth(_db, params, liveIntel) {
|
|
|
151
178
|
cached: false,
|
|
152
179
|
};
|
|
153
180
|
}
|
|
154
|
-
//# sourceMappingURL=dependency-health.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* developer_dna tool
|
|
3
3
|
*
|
|
4
4
|
* Export a comprehensive Developer DNA profile built from project scans,
|
|
5
|
-
*
|
|
5
|
+
* explicit interests, and local interaction history.
|
|
6
6
|
*/
|
|
7
7
|
import type { FourDADatabase } from "../db.js";
|
|
8
8
|
export interface DeveloperDnaParams {
|
|
@@ -46,7 +46,8 @@ interface EngagedTopic {
|
|
|
46
46
|
interface BlindSpotEntry {
|
|
47
47
|
dependency: string;
|
|
48
48
|
severity: string;
|
|
49
|
-
|
|
49
|
+
/** Days since last engagement with content about this dep; null = never engaged. */
|
|
50
|
+
days_stale: number | null;
|
|
50
51
|
}
|
|
51
52
|
interface SourceEngagement {
|
|
52
53
|
source_type: string;
|
|
@@ -76,4 +77,3 @@ interface DeveloperDna {
|
|
|
76
77
|
}
|
|
77
78
|
export declare function executeDeveloperDna(db: FourDADatabase, params: DeveloperDnaParams): DeveloperDna;
|
|
78
79
|
export {};
|
|
79
|
-
//# sourceMappingURL=developer-dna.d.ts.map
|