@4da/mcp-server 6.0.0 → 6.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.0.1 — 2026-10-04
4
+
5
+ ### The server has its own repository
6
+
7
+ `@4da/mcp-server` now lives at
8
+ [github.com/4DA-Systems/4da-mcp-server](https://github.com/4DA-Systems/4da-mcp-server),
9
+ with its full history, instead of a folder of the 4DA desktop app's monorepo.
10
+ Issues, releases and the Claude Code plugin marketplace move with it:
11
+
12
+ ```bash
13
+ claude plugin marketplace add 4DA-Systems/4da-mcp-server
14
+ claude plugin install 4da@4da
15
+ ```
16
+
17
+ The package, its name in the MCP Registry (`io.github.4DA-Systems/4da-mcp-server`)
18
+ and every tool are unchanged.
19
+
20
+ - **Published with provenance.** Releases are built and published from this
21
+ repository's `release.yml` through npm trusted publishing, so each version
22
+ carries a SLSA provenance attestation tying it to the commit it was built from.
23
+ - **App-schema contract.** The server reads the desktop app's database, which
24
+ is now maintained in a different repository. `pnpm run contract` checks every
25
+ statement the server issues, and every column it probes for, against the
26
+ schema the app's migrations produce (`contract/app-schema.sql`, generated in
27
+ the app's CI). The app's CI runs the same check before a migration merges.
28
+ - **Removed dead code.** `explainRelevance`, `getSourceItem`,
29
+ `recordAgentFeedback` and `getAgentFeedbackStats` had no callers since their
30
+ tools were removed; the standalone schema no longer creates the unused
31
+ `agent_feedback` table.
32
+ - The Claude Code plugin pins the exact server version it was released with.
33
+
3
34
  ## 6.0.0 — 2026-10-02
4
35
 
5
36
  ### New: `upgrade_impact`
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@4da/mcp-server?color=gold)](https://www.npmjs.com/package/@4da/mcp-server)
4
4
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
5
- [![Node](https://img.shields.io/badge/Node-%3E%3D20-brightgreen)](https://nodejs.org/)
6
- [![smithery badge](https://smithery.ai/badge/@4da/mcp-server)](https://smithery.ai/server/@4da/mcp-server)
5
+ [![Node](https://img.shields.io/badge/Node-%3E%3D22-brightgreen)](https://nodejs.org/)
6
+ [![CI](https://github.com/4DA-Systems/4da-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/4DA-Systems/4da-mcp-server/actions/workflows/ci.yml)
7
7
 
8
8
  **Upgrade intelligence for AI coding agents.** Before your agent bumps a dependency it learns what changes between the version you run and the one you want, which of your files that touches, and which vulnerabilities the move fixes, from your own lockfiles, on your machine. Plus vulnerability scanning at osv-scanner parity, ranked upgrade plans and decision memory. Zero config, no account.
9
9
 
@@ -38,7 +38,7 @@ claude mcp add 4da -- npx @4da/mcp-server
38
38
  **As a Claude Code plugin** (the MCP server plus a hook):
39
39
 
40
40
  ```bash
41
- claude plugin marketplace add 4DA-Systems/4DA --sparse .claude-plugin mcp-4da-server
41
+ claude plugin marketplace add 4DA-Systems/4da-mcp-server
42
42
  claude plugin install 4da@4da
43
43
  ```
44
44
 
@@ -268,11 +268,11 @@ Any tool that supports [MCP](https://modelcontextprotocol.io): Claude Code, Clau
268
268
  ## Build from Source
269
269
 
270
270
  ```bash
271
- git clone https://github.com/4DA-Systems/4DA.git
272
- cd 4DA/mcp-4da-server
271
+ git clone https://github.com/4DA-Systems/4da-mcp-server.git
272
+ cd 4da-mcp-server
273
273
  pnpm install
274
274
  pnpm build
275
- pnpm test # 662 tests, offline
275
+ pnpm test # offline
276
276
  ```
277
277
 
278
278
  ## License
package/dist/db.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  import type BetterSqlite3 from "better-sqlite3";
8
8
  /** Null when better-sqlite3 can open a database here; otherwise why not, with the fix. */
9
9
  export declare function nativeBindingProblem(): string | null;
10
- import type { SourceItem, RelevantItem, UserContext, RelevanceExplanation, FeedbackAction, FeedbackResult } from "./types.js";
10
+ import type { RelevantItem, UserContext, FeedbackAction, FeedbackResult } from "./types.js";
11
11
  import type { ProjectScanResult } from "./project-scanner.js";
12
12
  /**
13
13
  * Where the deployed desktop app keeps its database, mirroring
@@ -193,10 +193,6 @@ export declare class FourDADatabase {
193
193
  * Fallback: TypeScript keyword scoring for standalone mode (no Rust pipeline).
194
194
  */
195
195
  private getRelevantContentFallback;
196
- /**
197
- * Get a single source item by ID and type
198
- */
199
- getSourceItem(itemId: number, sourceType: string): SourceItem | null;
200
196
  /**
201
197
  * Look up persisted necessity scores for an item (written by Rust analysis pipeline).
202
198
  * Returns defaults (0.0/null) if no necessity data exists yet.
@@ -206,10 +202,6 @@ export declare class FourDADatabase {
206
202
  * Get the user's context (what 4DA knows about them)
207
203
  */
208
204
  getUserContext(includeAce?: boolean, includeLearned?: boolean): UserContext;
209
- /**
210
- * Explain why an item was considered relevant
211
- */
212
- explainRelevance(itemId: number, sourceType: string): RelevanceExplanation | null;
213
205
  /**
214
206
  * Record user feedback on an item
215
207
  */
@@ -221,54 +213,6 @@ export declare class FourDADatabase {
221
213
  * so against the desktop database this is a no-op.
222
214
  */
223
215
  private ensureFeedbackTable;
224
- /**
225
- * Ensure the agent_feedback table exists.
226
- * Called on first use so existing databases (created before this feature)
227
- * get the table added without requiring a migration.
228
- */
229
- private ensureAgentFeedbackTable;
230
- /**
231
- * Record agent feedback on recommended content items
232
- */
233
- recordAgentFeedback(itemIds: string[], outcome: string, context?: string, sessionTask?: string): {
234
- success: boolean;
235
- message: string;
236
- recorded_count: number;
237
- };
238
- /**
239
- * Get agent feedback statistics for the given period
240
- */
241
- getAgentFeedbackStats(days?: number): {
242
- period_days: number;
243
- outcomes: {
244
- used: number;
245
- rejected: number;
246
- partially_used: number;
247
- total: number;
248
- };
249
- by_source: Array<{
250
- source_type: string;
251
- used: number;
252
- rejected: number;
253
- partially_used: number;
254
- total: number;
255
- usefulness_rate: number;
256
- }>;
257
- top_used_items: Array<{
258
- item_id: string;
259
- title: string | null;
260
- source_type: string | null;
261
- used_count: number;
262
- rejected_count: number;
263
- }>;
264
- recent_feedback: Array<{
265
- item_id: string;
266
- outcome: string;
267
- context: string | null;
268
- session_task: string | null;
269
- recorded_at: string;
270
- }>;
271
- };
272
216
  /**
273
217
  * Compute relevance score for an item based on user context
274
218
  */
package/dist/db.js CHANGED
@@ -668,17 +668,6 @@ export class FourDADatabase {
668
668
  );
669
669
  CREATE INDEX IF NOT EXISTS idx_advantage_period ON advantage_score(period, computed_at);
670
670
 
671
- -- Agent feedback — queried by record_agent_feedback, get_agent_feedback_stats
672
- CREATE TABLE IF NOT EXISTS agent_feedback (
673
- id INTEGER PRIMARY KEY AUTOINCREMENT,
674
- item_id TEXT NOT NULL,
675
- outcome TEXT NOT NULL,
676
- context TEXT,
677
- session_task TEXT,
678
- recorded_at TEXT DEFAULT (datetime('now'))
679
- );
680
- CREATE INDEX IF NOT EXISTS idx_agent_feedback_item ON agent_feedback(item_id);
681
- CREATE INDEX IF NOT EXISTS idx_agent_feedback_outcome ON agent_feedback(outcome);
682
671
  `);
683
672
  }
684
673
  /**
@@ -1097,17 +1086,6 @@ export class FourDADatabase {
1097
1086
  .sort((a, b) => b.relevance_score - a.relevance_score)
1098
1087
  .slice(0, limit);
1099
1088
  }
1100
- /**
1101
- * Get a single source item by ID and type
1102
- */
1103
- getSourceItem(itemId, sourceType) {
1104
- const stmt = this.db.prepare(`
1105
- SELECT id, source_type, source_id, url, title, content, content_hash, created_at, last_seen
1106
- FROM source_items
1107
- WHERE id = ? AND source_type = ?
1108
- `);
1109
- return stmt.get(itemId, sourceType) || null;
1110
- }
1111
1089
  /**
1112
1090
  * Look up persisted necessity scores for an item (written by Rust analysis pipeline).
1113
1091
  * Returns defaults (0.0/null) if no necessity data exists yet.
@@ -1205,99 +1183,6 @@ export class FourDADatabase {
1205
1183
  return context;
1206
1184
  }
1207
1185
  // ===========================================================================
1208
- // Relevance Explanation
1209
- // ===========================================================================
1210
- /**
1211
- * Explain why an item was considered relevant
1212
- */
1213
- explainRelevance(itemId, sourceType) {
1214
- const item = this.getSourceItem(itemId, sourceType);
1215
- if (!item) {
1216
- return null;
1217
- }
1218
- const context = this.getUserContext(true, true);
1219
- const itemTopics = this.extractTopics(item.title + " " + item.content);
1220
- // Compute matching elements
1221
- const matchingInterests = context.interests
1222
- .filter((i) => itemTopics.some((t) => this.topicMatches(t, i.topic)))
1223
- .map((i) => i.topic);
1224
- const matchingTech = context.tech_stack.filter((tech) => itemTopics.some((t) => this.topicMatches(t, tech)));
1225
- const matchingTopics = context.ace?.active_topics
1226
- .filter((at) => itemTopics.some((t) => this.topicMatches(t, at.topic)))
1227
- .map((at) => at.topic) || [];
1228
- const matchingAffinities = context.learned?.topic_affinities
1229
- .filter((ta) => ta.affinity_score > 0 && itemTopics.some((t) => this.topicMatches(t, ta.topic)))
1230
- .map((ta) => ta.topic) || [];
1231
- // Compute score breakdown
1232
- const staticScore = matchingInterests.length * 0.3 +
1233
- matchingTech.length * 0.2 +
1234
- (context.domains.some((d) => itemTopics.some((t) => this.topicMatches(t, d)))
1235
- ? 0.15
1236
- : 0);
1237
- const aceScore = context.ace
1238
- ? matchingTopics.length * 0.1 +
1239
- context.ace.detected_tech.filter((dt) => itemTopics.some((t) => this.topicMatches(t, dt.name))).length *
1240
- 0.05
1241
- : 0;
1242
- // Learned affinity score DEMOTED in v19 (AD-029) — must mirror
1243
- // computeRelevanceScore so the explanation matches what actually
1244
- // scored (the two previously diverged on the anti-penalty weight too:
1245
- // scorer used *0.3, this explanation used *0.5).
1246
- const learnedScore = 0;
1247
- // Anti-penalty from user-authored exclusions only (learned anti-topics
1248
- // demoted with the rest of the behavioral stack, AD-029).
1249
- let antiPenalty = 0;
1250
- for (const exclusion of context.exclusions) {
1251
- if (itemTopics.some((t) => this.topicMatches(t, exclusion))) {
1252
- antiPenalty = 1.0; // Hard exclusion
1253
- break;
1254
- }
1255
- }
1256
- const finalScore = Math.max(0, Math.min(1, staticScore + aceScore + learnedScore - antiPenalty));
1257
- const scoreBreakdown = {
1258
- embedding_similarity: null, // Not computing embedding similarity in MCP server
1259
- static_match_score: Math.round(staticScore * 100) / 100,
1260
- ace_match_score: Math.round(aceScore * 100) / 100,
1261
- learned_affinity_score: Math.round(learnedScore * 100) / 100,
1262
- anti_penalty: Math.round(antiPenalty * 100) / 100,
1263
- final_score: Math.round(finalScore * 100) / 100,
1264
- };
1265
- const matchingContext = {
1266
- matching_interests: matchingInterests,
1267
- matching_tech: matchingTech,
1268
- matching_topics: matchingTopics,
1269
- matching_affinities: matchingAffinities,
1270
- };
1271
- // Generate human-readable explanation
1272
- const explanationParts = [];
1273
- if (matchingInterests.length > 0) {
1274
- explanationParts.push(`Matches your interests: ${matchingInterests.slice(0, 3).join(", ")}`);
1275
- }
1276
- if (matchingTech.length > 0) {
1277
- explanationParts.push(`Related to your tech stack: ${matchingTech.slice(0, 3).join(", ")}`);
1278
- }
1279
- if (matchingTopics.length > 0) {
1280
- explanationParts.push(`Relevant to recent work: ${matchingTopics.slice(0, 3).join(", ")}`);
1281
- }
1282
- if (matchingAffinities.length > 0) {
1283
- explanationParts.push(`You've shown interest in: ${matchingAffinities.slice(0, 3).join(", ")}`);
1284
- }
1285
- if (antiPenalty > 0) {
1286
- explanationParts.push(`Score reduced due to excluded topics`);
1287
- }
1288
- const explanation = explanationParts.length > 0
1289
- ? explanationParts.join(". ") + "."
1290
- : "No specific matches found - may be based on general relevance.";
1291
- return {
1292
- item_id: itemId,
1293
- source_type: sourceType,
1294
- title: item.title,
1295
- score_breakdown: scoreBreakdown,
1296
- matching_context: matchingContext,
1297
- explanation,
1298
- };
1299
- }
1300
- // ===========================================================================
1301
1186
  // Feedback
1302
1187
  // ===========================================================================
1303
1188
  /**
@@ -1392,160 +1277,6 @@ export class FourDADatabase {
1392
1277
  `);
1393
1278
  }
1394
1279
  // ===========================================================================
1395
- // Agent Feedback
1396
- // ===========================================================================
1397
- /**
1398
- * Ensure the agent_feedback table exists.
1399
- * Called on first use so existing databases (created before this feature)
1400
- * get the table added without requiring a migration.
1401
- */
1402
- ensureAgentFeedbackTable() {
1403
- this.db.exec(`
1404
- CREATE TABLE IF NOT EXISTS agent_feedback (
1405
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1406
- item_id TEXT NOT NULL,
1407
- outcome TEXT NOT NULL,
1408
- context TEXT,
1409
- session_task TEXT,
1410
- recorded_at TEXT DEFAULT (datetime('now'))
1411
- );
1412
- CREATE INDEX IF NOT EXISTS idx_agent_feedback_item ON agent_feedback(item_id);
1413
- CREATE INDEX IF NOT EXISTS idx_agent_feedback_outcome ON agent_feedback(outcome);
1414
- `);
1415
- }
1416
- /**
1417
- * Record agent feedback on recommended content items
1418
- */
1419
- recordAgentFeedback(itemIds, outcome, context, sessionTask) {
1420
- this.ensureAgentFeedbackTable();
1421
- const validOutcomes = ["used", "rejected", "partially_used"];
1422
- if (!validOutcomes.includes(outcome)) {
1423
- return {
1424
- success: false,
1425
- message: `Invalid outcome: ${outcome}. Valid outcomes: ${validOutcomes.join(", ")}`,
1426
- recorded_count: 0,
1427
- };
1428
- }
1429
- if (!itemIds || itemIds.length === 0) {
1430
- return {
1431
- success: false,
1432
- message: "item_ids must contain at least one item ID",
1433
- recorded_count: 0,
1434
- };
1435
- }
1436
- try {
1437
- const stmt = this.db.prepare(`
1438
- INSERT INTO agent_feedback (item_id, outcome, context, session_task)
1439
- VALUES (?, ?, ?, ?)
1440
- `);
1441
- const insertMany = this.db.transaction((ids) => {
1442
- let count = 0;
1443
- for (const id of ids) {
1444
- stmt.run(id, outcome, context || null, sessionTask || null);
1445
- count++;
1446
- }
1447
- return count;
1448
- });
1449
- const count = insertMany(itemIds);
1450
- return {
1451
- success: true,
1452
- message: `Recorded ${outcome} feedback for ${count} item(s)`,
1453
- recorded_count: count,
1454
- };
1455
- }
1456
- catch (error) {
1457
- return {
1458
- success: false,
1459
- message: `Failed to record agent feedback: ${error instanceof Error ? error.message : String(error)}`,
1460
- recorded_count: 0,
1461
- };
1462
- }
1463
- }
1464
- /**
1465
- * Get agent feedback statistics for the given period
1466
- */
1467
- getAgentFeedbackStats(days = 30) {
1468
- this.ensureAgentFeedbackTable();
1469
- const cutoff = `datetime('now', '-${Math.max(1, Math.min(365, days))} days')`;
1470
- // Outcome totals
1471
- const outcomeRows = this.db
1472
- .prepare(`SELECT outcome, COUNT(*) as cnt
1473
- FROM agent_feedback
1474
- WHERE recorded_at >= ${cutoff}
1475
- GROUP BY outcome`)
1476
- .all();
1477
- const outcomes = { used: 0, rejected: 0, partially_used: 0, total: 0 };
1478
- for (const row of outcomeRows) {
1479
- if (row.outcome === "used")
1480
- outcomes.used = row.cnt;
1481
- else if (row.outcome === "rejected")
1482
- outcomes.rejected = row.cnt;
1483
- else if (row.outcome === "partially_used")
1484
- outcomes.partially_used = row.cnt;
1485
- outcomes.total += row.cnt;
1486
- }
1487
- // By source type — join with source_items to get source_type
1488
- const sourceRows = this.db
1489
- .prepare(`SELECT COALESCE(si.source_type, 'unknown') as source_type, af.outcome, COUNT(*) as cnt
1490
- FROM agent_feedback af
1491
- LEFT JOIN source_items si ON CAST(af.item_id AS INTEGER) = si.id
1492
- WHERE af.recorded_at >= ${cutoff}
1493
- GROUP BY source_type, af.outcome
1494
- ORDER BY cnt DESC`)
1495
- .all();
1496
- // Aggregate source rows into per-source stats
1497
- const sourceMap = new Map();
1498
- for (const row of sourceRows) {
1499
- if (!sourceMap.has(row.source_type)) {
1500
- sourceMap.set(row.source_type, { used: 0, rejected: 0, partially_used: 0, total: 0 });
1501
- }
1502
- const entry = sourceMap.get(row.source_type);
1503
- if (row.outcome === "used")
1504
- entry.used += row.cnt;
1505
- else if (row.outcome === "rejected")
1506
- entry.rejected += row.cnt;
1507
- else if (row.outcome === "partially_used")
1508
- entry.partially_used += row.cnt;
1509
- entry.total += row.cnt;
1510
- }
1511
- const bySource = Array.from(sourceMap.entries()).map(([source_type, stats]) => ({
1512
- source_type,
1513
- ...stats,
1514
- usefulness_rate: stats.total > 0 ? (stats.used + stats.partially_used * 0.5) / stats.total : 0,
1515
- }));
1516
- // Top used items
1517
- const topItems = this.db
1518
- .prepare(`SELECT
1519
- af.item_id,
1520
- si.title,
1521
- si.source_type,
1522
- SUM(CASE WHEN af.outcome = 'used' THEN 1 ELSE 0 END) as used_count,
1523
- SUM(CASE WHEN af.outcome = 'rejected' THEN 1 ELSE 0 END) as rejected_count
1524
- FROM agent_feedback af
1525
- LEFT JOIN source_items si ON CAST(af.item_id AS INTEGER) = si.id
1526
- WHERE af.recorded_at >= ${cutoff}
1527
- GROUP BY af.item_id
1528
- HAVING used_count > 0
1529
- ORDER BY used_count DESC
1530
- LIMIT 10`)
1531
- .all();
1532
- // Recent feedback entries
1533
- const recentFeedback = this.db
1534
- .prepare(`SELECT item_id, outcome, context, session_task, recorded_at
1535
- FROM agent_feedback
1536
- WHERE recorded_at >= ${cutoff}
1537
- ORDER BY recorded_at DESC
1538
- LIMIT 20`)
1539
- .all();
1540
- return {
1541
- period_days: days,
1542
- outcomes,
1543
- by_source: bySource,
1544
- top_used_items: topItems,
1545
- recent_feedback: recentFeedback,
1546
- };
1547
- }
1548
- // ===========================================================================
1549
1280
  // Helper Methods
1550
1281
  // ===========================================================================
1551
1282
  /**
package/dist/types.d.ts CHANGED
@@ -119,37 +119,6 @@ export interface UserContext {
119
119
  anti_topics: AntiTopic[];
120
120
  };
121
121
  }
122
- /**
123
- * Score breakdown for explain_relevance
124
- */
125
- export interface ScoreBreakdown {
126
- embedding_similarity: number | null;
127
- static_match_score: number;
128
- ace_match_score: number;
129
- learned_affinity_score: number;
130
- anti_penalty: number;
131
- final_score: number;
132
- }
133
- /**
134
- * Matching context elements
135
- */
136
- export interface MatchingContext {
137
- matching_interests: string[];
138
- matching_tech: string[];
139
- matching_topics: string[];
140
- matching_affinities: string[];
141
- }
142
- /**
143
- * Full relevance explanation
144
- */
145
- export interface RelevanceExplanation {
146
- item_id: number;
147
- source_type: string;
148
- title: string;
149
- score_breakdown: ScoreBreakdown;
150
- matching_context: MatchingContext;
151
- explanation: string;
152
- }
153
122
  /**
154
123
  * Valid feedback action types
155
124
  */
@@ -293,107 +262,3 @@ export interface SignalEventRow {
293
262
  data: string;
294
263
  created_at: string;
295
264
  }
296
- /**
297
- * Valid agent feedback outcome types
298
- */
299
- export type AgentFeedbackOutcome = "used" | "rejected" | "partially_used";
300
- /**
301
- * Parameters for recording agent feedback
302
- */
303
- export interface RecordAgentFeedbackParams {
304
- item_ids: string[];
305
- outcome: AgentFeedbackOutcome;
306
- context?: string;
307
- session_task?: string;
308
- }
309
- /**
310
- * Result from recording agent feedback
311
- */
312
- export interface AgentFeedbackResult {
313
- success: boolean;
314
- message: string;
315
- recorded_count: number;
316
- }
317
- /**
318
- * Parameters for getting agent feedback stats
319
- */
320
- export interface GetAgentFeedbackStatsParams {
321
- days?: number;
322
- }
323
- /**
324
- * Outcome breakdown in agent feedback stats
325
- */
326
- export interface AgentFeedbackOutcomeStats {
327
- used: number;
328
- rejected: number;
329
- partially_used: number;
330
- total: number;
331
- }
332
- /**
333
- * Per-source feedback stats
334
- */
335
- export interface AgentFeedbackSourceStats {
336
- source_type: string;
337
- used: number;
338
- rejected: number;
339
- partially_used: number;
340
- total: number;
341
- usefulness_rate: number;
342
- }
343
- /**
344
- * A frequently used item
345
- */
346
- export interface AgentFeedbackTopItem {
347
- item_id: string;
348
- title: string | null;
349
- source_type: string | null;
350
- used_count: number;
351
- rejected_count: number;
352
- }
353
- /**
354
- * A recent feedback entry
355
- */
356
- export interface AgentFeedbackRecentEntry {
357
- item_id: string;
358
- outcome: string;
359
- context: string | null;
360
- session_task: string | null;
361
- recorded_at: string;
362
- }
363
- /**
364
- * Full agent feedback stats response
365
- */
366
- export interface AgentFeedbackStats {
367
- period_days: number;
368
- outcomes: AgentFeedbackOutcomeStats;
369
- by_source: AgentFeedbackSourceStats[];
370
- top_used_items: AgentFeedbackTopItem[];
371
- recent_feedback: AgentFeedbackRecentEntry[];
372
- }
373
- /** Row from agent_feedback table */
374
- export interface AgentFeedbackRow {
375
- item_id: string;
376
- outcome: string;
377
- context: string | null;
378
- session_task: string | null;
379
- recorded_at: string;
380
- }
381
- /** Row from agent_feedback stats query — outcome counts */
382
- export interface AgentFeedbackOutcomeRow {
383
- outcome: string;
384
- cnt: number;
385
- }
386
- /** Row from agent_feedback stats query — source breakdown */
387
- export interface AgentFeedbackSourceRow {
388
- source_type: string;
389
- outcome: string;
390
- cnt: number;
391
- }
392
- /** Row from agent_feedback stats query — top items */
393
- export interface AgentFeedbackTopItemRow {
394
- item_id: string;
395
- title: string | null;
396
- source_type: string | null;
397
- used_count: number;
398
- rejected_count: number;
399
- }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@4da/mcp-server",
3
- "version": "6.0.0",
3
+ "version": "6.0.1",
4
4
  "mcpName": "io.github.4DA-Systems/4da-mcp-server",
5
- "description": "Upgrade intelligence for AI coding agents: what changes between your installed and target version (changelog, breaking changes, the files you import it from), a pre-install verdict on each bump, vulnerability scanning at osv-scanner parity across npm/pnpm/yarn, Cargo, Python and Go lockfiles, ranked upgrade plans, task-scoped briefings, decision memory. Local, no account. 11 tools standalone, 16 with the desktop app.",
5
+ "description": "Upgrade intelligence for AI coding agents: what changes between your installed and target version (changelog, breaking changes, the files you import it from), a pre-install verdict on each bump, vulnerability scanning at osv-scanner parity across npm/pnpm/yarn, Cargo, Python and Go lockfiles, ranked upgrade plans, task-scoped briefings, decision memory. Local, no account; works standalone, and reads the 4DA desktop app's scored feed when it is installed.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "bin": {
@@ -28,7 +28,10 @@
28
28
  "setup": "node dist/setup.js",
29
29
  "test": "vitest run",
30
30
  "test:watch": "vitest",
31
- "prepublishOnly": "pnpm run build"
31
+ "prepublishOnly": "pnpm run build",
32
+ "check": "node scripts/check-repo.mjs",
33
+ "contract": "node scripts/app-schema-contract.mjs",
34
+ "contract:sync": "node scripts/sync-app-schema.mjs"
32
35
  },
33
36
  "keywords": [
34
37
  "mcp",
@@ -70,12 +73,11 @@
70
73
  "license": "Apache-2.0",
71
74
  "repository": {
72
75
  "type": "git",
73
- "url": "git+https://github.com/4DA-Systems/4DA.git",
74
- "directory": "mcp-4da-server"
76
+ "url": "git+https://github.com/4DA-Systems/4da-mcp-server.git"
75
77
  },
76
- "homepage": "https://4da.ai",
78
+ "homepage": "https://4da.ai/mcp/",
77
79
  "bugs": {
78
- "url": "https://github.com/4DA-Systems/4DA/issues"
80
+ "url": "https://github.com/4DA-Systems/4da-mcp-server/issues"
79
81
  },
80
82
  "dependencies": {
81
83
  "@modelcontextprotocol/node": "^2.0.0",
@@ -93,6 +95,7 @@
93
95
  "engines": {
94
96
  "node": ">=22.0.0"
95
97
  },
98
+ "packageManager": "pnpm@10.34.6",
96
99
  "pnpm": {
97
100
  "onlyBuiltDependencies": [
98
101
  "better-sqlite3",