@arcbridge/mcp-server 0.2.0 → 0.2.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/dist/index.js CHANGED
@@ -189,15 +189,17 @@ Use \`arcbridge_get_project_status\` to see the current state.`
189
189
  ...allWarnings.map((w) => `- ${w}`)
190
190
  ] : [],
191
191
  "",
192
- "## Next Steps \u2014 PLAN FIRST, BUILD SECOND",
192
+ "## Next Steps \u2014 TAILOR FIRST, BUILD SECOND",
193
193
  "",
194
- "**Do not start implementing yet.** First plan the full project roadmap:",
194
+ "**Do not start implementing yet.** The generated building blocks, quality scenarios, and phase tasks are a generic starting template. Tailor them to this project first:",
195
195
  "",
196
196
  "1. **Activate the architect role** \u2014 run `arcbridge_activate_role` with role `architect`",
197
197
  "2. **Review the spec** \u2014 read `.arcbridge/spec.md` (if provided) and understand the full scope",
198
- "3. **Review and adapt the phase plan** \u2014 run `arcbridge_get_phase_plan`. The 4 generated phases are a starting template. For larger projects, add more phases by editing `.arcbridge/plan/phases.yaml` and running `arcbridge_reindex`.",
199
- "4. **Plan real tasks for ALL phases** \u2014 Phase 0-1 tasks are ready to use. Phase 2+ tasks are examples only \u2014 replace them with real tasks from the project's requirements using `arcbridge_create_task`.",
200
- "5. **Only then start building** \u2014 use `arcbridge_get_current_tasks` to see what to do next",
198
+ "3. **Tailor building blocks** \u2014 edit `.arcbridge/arc42/05-building-blocks.md`: delete blocks that don't apply, add blocks for your real modules, and declare `interfaces` between blocks (drift detection depends on this)",
199
+ "4. **Tailor quality scenarios** \u2014 edit `.arcbridge/arc42/10-quality-scenarios.yaml`: delete irrelevant scenarios, add ones that match your actual requirements",
200
+ "5. **Tailor phase tasks** \u2014 Phase 0-1 tasks are ready to use. Phase 2+ tasks are examples only \u2014 **delete them** (edit `.arcbridge/plan/tasks/<phase>.yaml` or use `arcbridge_delete_task`) and create real tasks from the project's requirements using `arcbridge_create_task`. Add more phases with `arcbridge_create_phase` if needed.",
201
+ "6. **Reindex** \u2014 run `arcbridge_reindex` to pick up your changes",
202
+ "7. **Then start building** \u2014 use `arcbridge_get_current_tasks` to see what to do next",
201
203
  "",
202
204
  "Use `arcbridge_get_project_status` to see the full project status."
203
205
  ];
@@ -1073,40 +1075,62 @@ If you need a new block, add it to \`.arcbridge/arc42/05-building-blocks.md\` an
1073
1075
 
1074
1076
  // src/tools/delete-task.ts
1075
1077
  import { z as z10 } from "zod";
1076
- import { deleteTaskFromYaml } from "@arcbridge/core";
1078
+ import { deleteTaskFromYaml, refreshFromDocs as refreshFromDocs4 } from "@arcbridge/core";
1077
1079
  function registerDeleteTask(server, ctx) {
1078
1080
  server.tool(
1079
1081
  "arcbridge_delete_task",
1080
- "Delete a task permanently. Use this to remove example/template tasks or duplicates. For tasks that were planned but are no longer relevant, prefer `arcbridge_update_task` with status 'cancelled' instead \u2014 this preserves the decision trail.",
1082
+ "Delete one or more tasks permanently. Use this to remove example/template tasks or duplicates. Pass task_ids (array) for batch deletion, or task_id (string) for a single task. For tasks that were planned but are no longer relevant, prefer `arcbridge_update_task` with status 'cancelled' instead \u2014 this preserves the decision trail.",
1081
1083
  {
1082
1084
  target_dir: z10.string().describe("Absolute path to the project directory"),
1083
- task_id: z10.string().describe("Task ID to delete")
1085
+ task_id: z10.string().optional().describe("Single task ID to delete (deprecated \u2014 use task_ids)"),
1086
+ task_ids: z10.array(z10.string()).optional().describe("Task IDs to delete (preferred)")
1084
1087
  },
1085
1088
  async (params) => {
1086
1089
  const db = ensureDb(ctx, params.target_dir);
1087
1090
  if (!db) return notInitialized();
1088
- const task = db.prepare("SELECT id, title, phase_id FROM tasks WHERE id = ?").get(params.task_id);
1089
- if (!task) {
1090
- return textResult(
1091
- `Task '${params.task_id}' not found. Use \`arcbridge_get_current_tasks\` to see available tasks.`
1092
- );
1091
+ const ids = params.task_ids ?? (params.task_id ? [params.task_id] : []);
1092
+ if (ids.length === 0) {
1093
+ return textResult("Provide `task_ids` (array) or `task_id` (string) to delete.");
1094
+ }
1095
+ const results = [];
1096
+ const warnings = [];
1097
+ for (const id of ids) {
1098
+ const task = db.prepare("SELECT id, title, phase_id FROM tasks WHERE id = ?").get(id);
1099
+ if (!task) {
1100
+ warnings.push(`Task '${id}' not found \u2014 skipped`);
1101
+ continue;
1102
+ }
1103
+ const yamlResult = deleteTaskFromYaml(params.target_dir, task.phase_id, id);
1104
+ if (yamlResult.success === false) {
1105
+ warnings.push(`${task.id}: ${yamlResult.warning ?? "YAML delete failed"}`);
1106
+ } else {
1107
+ results.push(`- **${task.id}**: "${task.title}"`);
1108
+ if (yamlResult.warning) {
1109
+ warnings.push(`${task.id}: ${yamlResult.warning}`);
1110
+ }
1111
+ }
1093
1112
  }
1094
- const yamlResult = deleteTaskFromYaml(params.target_dir, task.phase_id, params.task_id);
1095
- db.prepare("DELETE FROM tasks WHERE id = ?").run(params.task_id);
1096
- const msg = `Task **${task.id}** deleted: "${task.title}"`;
1097
- if (yamlResult.warning) {
1098
- return textResult(`${msg}
1099
-
1100
- **Warning:** ${yamlResult.warning}`);
1113
+ if (results.length > 0) {
1114
+ refreshFromDocs4(db, params.target_dir);
1101
1115
  }
1102
- return textResult(msg);
1116
+ const lines = [];
1117
+ if (results.length > 0) {
1118
+ lines.push(`Deleted ${results.length} task${results.length === 1 ? "" : "s"}:`, "", ...results);
1119
+ }
1120
+ if (warnings.length > 0) {
1121
+ lines.push("", "**Warnings:**", ...warnings.map((w) => `- ${w}`));
1122
+ }
1123
+ if (results.length === 0 && warnings.length > 0) {
1124
+ lines.unshift("No tasks were deleted.");
1125
+ }
1126
+ return textResult(lines.join("\n"));
1103
1127
  }
1104
1128
  );
1105
1129
  }
1106
1130
 
1107
1131
  // src/tools/create-phase.ts
1108
1132
  import { z as z11 } from "zod";
1109
- import { addPhaseToYaml, refreshFromDocs as refreshFromDocs4 } from "@arcbridge/core";
1133
+ import { addPhaseToYaml, refreshFromDocs as refreshFromDocs5 } from "@arcbridge/core";
1110
1134
  function registerCreatePhase(server, ctx) {
1111
1135
  server.tool(
1112
1136
  "arcbridge_create_phase",
@@ -1121,7 +1145,7 @@ function registerCreatePhase(server, ctx) {
1121
1145
  async (params) => {
1122
1146
  const db = ensureDb(ctx, params.target_dir);
1123
1147
  if (!db) return notInitialized();
1124
- refreshFromDocs4(db, params.target_dir);
1148
+ refreshFromDocs5(db, params.target_dir);
1125
1149
  const maxPhase = db.prepare("SELECT MAX(phase_number) as max FROM phases").get();
1126
1150
  const phaseNumber = params.phase_number ?? (maxPhase.max ?? -1) + 1;
1127
1151
  const existing = db.prepare("SELECT id FROM phases WHERE phase_number = ?").get(phaseNumber);
@@ -1144,7 +1168,7 @@ function registerCreatePhase(server, ctx) {
1144
1168
  `Failed to create phase: ${yamlResult.warning ?? "YAML update failed"}`
1145
1169
  );
1146
1170
  }
1147
- refreshFromDocs4(db, params.target_dir);
1171
+ refreshFromDocs5(db, params.target_dir);
1148
1172
  const lines = [
1149
1173
  `Phase created: **${phaseId}**`,
1150
1174
  "",
@@ -1168,16 +1192,60 @@ function registerCreatePhase(server, ctx) {
1168
1192
  );
1169
1193
  }
1170
1194
 
1171
- // src/tools/get-relevant-adrs.ts
1195
+ // src/tools/delete-phase.ts
1172
1196
  import { z as z12 } from "zod";
1197
+ import { deletePhaseFromYaml, refreshFromDocs as refreshFromDocs6 } from "@arcbridge/core";
1198
+ function registerDeletePhase(server, ctx) {
1199
+ server.tool(
1200
+ "arcbridge_delete_phase",
1201
+ "Delete a phase and all its tasks permanently. Use this to remove template phases that don't apply to this project. Phases with status 'in-progress' or 'done' cannot be deleted \u2014 change their status first if you really need to remove them.",
1202
+ {
1203
+ target_dir: z12.string().describe("Absolute path to the project directory"),
1204
+ phase_id: z12.string().describe("Phase ID to delete")
1205
+ },
1206
+ async (params) => {
1207
+ const db = ensureDb(ctx, params.target_dir);
1208
+ if (!db) return notInitialized();
1209
+ const phase = db.prepare("SELECT id, name, phase_number, status FROM phases WHERE id = ?").get(params.phase_id);
1210
+ if (!phase) {
1211
+ return textResult(
1212
+ `Phase '${params.phase_id}' not found. Use \`arcbridge_get_phase_plan\` to see available phases.`
1213
+ );
1214
+ }
1215
+ if (phase.status !== "planned") {
1216
+ return textResult(
1217
+ `Cannot delete phase **${phase.id}** (status: ${phase.status}). Only phases with status 'planned' can be deleted.`
1218
+ );
1219
+ }
1220
+ const taskCount = db.prepare("SELECT COUNT(*) as count FROM tasks WHERE phase_id = ?").get(params.phase_id);
1221
+ const yamlResult = deletePhaseFromYaml(params.target_dir, params.phase_id);
1222
+ if (!yamlResult.success) {
1223
+ return textResult(
1224
+ `Failed to delete phase: ${yamlResult.warning ?? "Unknown error"}`
1225
+ );
1226
+ }
1227
+ refreshFromDocs6(db, params.target_dir);
1228
+ const lines = [
1229
+ `Phase **${phase.id}** deleted: "${phase.name}" (phase ${phase.phase_number})`
1230
+ ];
1231
+ if (taskCount.count > 0) {
1232
+ lines.push(`${taskCount.count} task${taskCount.count === 1 ? "" : "s"} removed.`);
1233
+ }
1234
+ return textResult(lines.join("\n"));
1235
+ }
1236
+ );
1237
+ }
1238
+
1239
+ // src/tools/get-relevant-adrs.ts
1240
+ import { z as z13 } from "zod";
1173
1241
  function registerGetRelevantAdrs(server, ctx) {
1174
1242
  server.tool(
1175
1243
  "arcbridge_get_relevant_adrs",
1176
1244
  "Get architectural decision records (ADRs) relevant to a specific file path or building block.",
1177
1245
  {
1178
- target_dir: z12.string().describe("Absolute path to the project directory"),
1179
- file_path: z12.string().optional().describe("File path to find relevant ADRs for"),
1180
- building_block: z12.string().optional().describe("Building block ID to find relevant ADRs for")
1246
+ target_dir: z13.string().describe("Absolute path to the project directory"),
1247
+ file_path: z13.string().optional().describe("File path to find relevant ADRs for"),
1248
+ building_block: z13.string().optional().describe("Building block ID to find relevant ADRs for")
1181
1249
  },
1182
1250
  async (params) => {
1183
1251
  const db = ensureDb(ctx, params.target_dir);
@@ -1261,24 +1329,24 @@ function formatAdrs(adrs, title) {
1261
1329
  }
1262
1330
 
1263
1331
  // src/tools/reindex.ts
1264
- import { z as z13 } from "zod";
1265
- import { indexProject as indexProject2, refreshFromDocs as refreshFromDocs5 } from "@arcbridge/core";
1332
+ import { z as z14 } from "zod";
1333
+ import { indexProject as indexProject2, refreshFromDocs as refreshFromDocs7 } from "@arcbridge/core";
1266
1334
  function registerReindex(server, ctx) {
1267
1335
  server.tool(
1268
1336
  "arcbridge_reindex",
1269
1337
  "Re-index the project: refreshes architecture docs from arc42/YAML files, then reindexes code symbols (TypeScript & C#/.NET). This is the first step of the sync pipeline \u2014 use it to pick up manual doc edits and code changes.",
1270
1338
  {
1271
- target_dir: z13.string().describe("Absolute path to the project directory"),
1272
- tsconfig_path: z13.string().optional().describe("Override tsconfig.json path (default: auto-detect). Only used for TypeScript projects."),
1273
- service: z13.string().optional().describe("Service name for monorepo projects (default: 'main')"),
1274
- language: z13.enum(["typescript", "csharp", "auto"]).optional().describe("Project language. 'auto' detects from project files (default: 'auto')")
1339
+ target_dir: z14.string().describe("Absolute path to the project directory"),
1340
+ tsconfig_path: z14.string().optional().describe("Override tsconfig.json path (default: auto-detect). Only used for TypeScript projects."),
1341
+ service: z14.string().optional().describe("Service name for monorepo projects (default: 'main')"),
1342
+ language: z14.enum(["typescript", "csharp", "auto"]).optional().describe("Project language. 'auto' detects from project files (default: 'auto')")
1275
1343
  },
1276
1344
  async (params) => {
1277
1345
  const start = Date.now();
1278
1346
  const db = ensureDb(ctx, params.target_dir);
1279
1347
  if (!db) return notInitialized();
1280
1348
  try {
1281
- const docWarnings = refreshFromDocs5(db, params.target_dir);
1349
+ const docWarnings = refreshFromDocs7(db, params.target_dir);
1282
1350
  const result = await indexProject2(db, {
1283
1351
  projectRoot: params.target_dir,
1284
1352
  tsconfigPath: params.tsconfig_path,
@@ -1317,16 +1385,16 @@ function registerReindex(server, ctx) {
1317
1385
  }
1318
1386
 
1319
1387
  // src/tools/search-symbols.ts
1320
- import { z as z14 } from "zod";
1388
+ import { z as z15 } from "zod";
1321
1389
  function registerSearchSymbols(server, ctx) {
1322
1390
  server.tool(
1323
1391
  "arcbridge_search_symbols",
1324
1392
  "Search code symbols by name, kind, file path, or building block. Supports TypeScript and C#. Returns matching symbols with type signatures.",
1325
1393
  {
1326
- target_dir: z14.string().describe("Absolute path to the project directory"),
1327
- query: z14.string().optional().describe("Search term to match against symbol names"),
1328
- service: z14.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services."),
1329
- kind: z14.enum([
1394
+ target_dir: z15.string().describe("Absolute path to the project directory"),
1395
+ query: z15.string().optional().describe("Search term to match against symbol names"),
1396
+ service: z15.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services."),
1397
+ kind: z15.enum([
1330
1398
  "function",
1331
1399
  "class",
1332
1400
  "type",
@@ -1338,10 +1406,10 @@ function registerSearchSymbols(server, ctx) {
1338
1406
  "hook",
1339
1407
  "context"
1340
1408
  ]).optional().describe("Filter by symbol kind"),
1341
- file_path: z14.string().optional().describe("Filter by file path (prefix match)"),
1342
- is_exported: z14.boolean().optional().describe("Filter by export status"),
1343
- building_block: z14.string().optional().describe("Filter by building block ID (matches against code_paths)"),
1344
- limit: z14.number().int().min(1).max(200).default(50).describe("Maximum results to return (default: 50)")
1409
+ file_path: z15.string().optional().describe("Filter by file path (prefix match)"),
1410
+ is_exported: z15.boolean().optional().describe("Filter by export status"),
1411
+ building_block: z15.string().optional().describe("Filter by building block ID (matches against code_paths)"),
1412
+ limit: z15.number().int().min(1).max(200).default(50).describe("Maximum results to return (default: 50)")
1345
1413
  },
1346
1414
  async (params) => {
1347
1415
  const db = ensureDb(ctx, params.target_dir);
@@ -1428,7 +1496,7 @@ function registerSearchSymbols(server, ctx) {
1428
1496
  }
1429
1497
 
1430
1498
  // src/tools/get-symbol.ts
1431
- import { z as z15 } from "zod";
1499
+ import { z as z16 } from "zod";
1432
1500
  import { readFileSync, existsSync as existsSync3 } from "fs";
1433
1501
  import { join as join3 } from "path";
1434
1502
  function registerGetSymbol(server, ctx) {
@@ -1436,11 +1504,11 @@ function registerGetSymbol(server, ctx) {
1436
1504
  "arcbridge_get_symbol",
1437
1505
  "Get detailed information about a specific TypeScript symbol including its source code, type signature, and relationships.",
1438
1506
  {
1439
- target_dir: z15.string().describe("Absolute path to the project directory"),
1440
- symbol_id: z15.string().describe(
1507
+ target_dir: z16.string().describe("Absolute path to the project directory"),
1508
+ symbol_id: z16.string().describe(
1441
1509
  "Symbol ID (e.g. 'src/utils.ts::formatName#function')"
1442
1510
  ),
1443
- include_source: z15.boolean().default(true).describe("Include source code snippet (default: true)")
1511
+ include_source: z16.boolean().default(true).describe("Include source code snippet (default: true)")
1444
1512
  },
1445
1513
  async (params) => {
1446
1514
  const db = ensureDb(ctx, params.target_dir);
@@ -1538,21 +1606,21 @@ Use \`arcbridge_search_symbols\` to find symbols by name.`
1538
1606
  }
1539
1607
 
1540
1608
  // src/tools/get-dependency-graph.ts
1541
- import { z as z16 } from "zod";
1609
+ import { z as z17 } from "zod";
1542
1610
  function registerGetDependencyGraph(server, ctx) {
1543
1611
  server.tool(
1544
1612
  "arcbridge_get_dependency_graph",
1545
1613
  "Get the dependency graph for a module or file. Shows imports, calls, type usage, and inheritance relationships between symbols.",
1546
1614
  {
1547
- target_dir: z16.string().describe("Absolute path to the project directory"),
1548
- module: z16.string().describe(
1615
+ target_dir: z17.string().describe("Absolute path to the project directory"),
1616
+ module: z17.string().describe(
1549
1617
  "Module path relative to project root (e.g. 'src/lib/auth')"
1550
1618
  ),
1551
- direction: z16.enum(["dependencies", "dependents", "both"]).default("both").describe(
1619
+ direction: z17.enum(["dependencies", "dependents", "both"]).default("both").describe(
1552
1620
  "Graph direction: 'dependencies' (what this module uses), 'dependents' (what uses this module), or 'both'"
1553
1621
  ),
1554
- depth: z16.number().int().min(1).max(5).default(1).describe("How many levels to traverse (default: 1, max: 5)"),
1555
- service: z16.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services.")
1622
+ depth: z17.number().int().min(1).max(5).default(1).describe("How many levels to traverse (default: 1, max: 5)"),
1623
+ service: z17.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services.")
1556
1624
  },
1557
1625
  async (params) => {
1558
1626
  const maybeDb = ensureDb(ctx, params.target_dir);
@@ -1699,16 +1767,16 @@ function formatEdges(edges, modulePath, direction) {
1699
1767
  }
1700
1768
 
1701
1769
  // src/tools/get-component-graph.ts
1702
- import { z as z17 } from "zod";
1770
+ import { z as z18 } from "zod";
1703
1771
  function registerGetComponentGraph(server, ctx) {
1704
1772
  server.tool(
1705
1773
  "arcbridge_get_component_graph",
1706
1774
  "Get the React component graph: component hierarchy, props, state, context usage, and server/client boundaries.",
1707
1775
  {
1708
- target_dir: z17.string().describe("Absolute path to the project directory"),
1709
- file_path: z17.string().optional().describe("Filter to components in a specific file or directory prefix"),
1710
- client_only: z17.boolean().optional().describe("Only show client components ('use client')"),
1711
- with_state: z17.boolean().optional().describe("Only show components that use state (useState/useReducer)")
1776
+ target_dir: z18.string().describe("Absolute path to the project directory"),
1777
+ file_path: z18.string().optional().describe("Filter to components in a specific file or directory prefix"),
1778
+ client_only: z18.boolean().optional().describe("Only show client components ('use client')"),
1779
+ with_state: z18.boolean().optional().describe("Only show components that use state (useState/useReducer)")
1712
1780
  },
1713
1781
  async (params) => {
1714
1782
  const db = ensureDb(ctx, params.target_dir);
@@ -1812,16 +1880,16 @@ function registerGetComponentGraph(server, ctx) {
1812
1880
  }
1813
1881
 
1814
1882
  // src/tools/get-route-map.ts
1815
- import { z as z18 } from "zod";
1883
+ import { z as z19 } from "zod";
1816
1884
  function registerGetRouteMap(server, ctx) {
1817
1885
  server.tool(
1818
1886
  "arcbridge_get_route_map",
1819
1887
  "Get the route map: pages, layouts, API routes, and their hierarchy. Works with Next.js, ASP.NET controllers, and minimal APIs.",
1820
1888
  {
1821
- target_dir: z18.string().describe("Absolute path to the project directory"),
1822
- kind: z18.enum(["page", "layout", "loading", "error", "not-found", "api-route", "middleware"]).optional().describe("Filter by route kind"),
1823
- route_prefix: z18.string().optional().describe("Filter by route path prefix (e.g. '/dashboard' or '/api/orders')"),
1824
- service: z18.string().optional().describe("Filter by service name (for multi-project solutions). Omit to show all services.")
1889
+ target_dir: z19.string().describe("Absolute path to the project directory"),
1890
+ kind: z19.enum(["page", "layout", "loading", "error", "not-found", "api-route", "middleware"]).optional().describe("Filter by route kind"),
1891
+ route_prefix: z19.string().optional().describe("Filter by route path prefix (e.g. '/dashboard' or '/api/orders')"),
1892
+ service: z19.string().optional().describe("Filter by service name (for multi-project solutions). Omit to show all services.")
1825
1893
  },
1826
1894
  async (params) => {
1827
1895
  const db = ensureDb(ctx, params.target_dir);
@@ -1897,13 +1965,13 @@ function registerGetRouteMap(server, ctx) {
1897
1965
  }
1898
1966
 
1899
1967
  // src/tools/get-boundary-analysis.ts
1900
- import { z as z19 } from "zod";
1968
+ import { z as z20 } from "zod";
1901
1969
  function registerGetBoundaryAnalysis(server, ctx) {
1902
1970
  server.tool(
1903
1971
  "arcbridge_get_boundary_analysis",
1904
1972
  "Analyze server/client boundaries in a Next.js project. Identifies client components, server components, server actions, and potential boundary violations.",
1905
1973
  {
1906
- target_dir: z19.string().describe("Absolute path to the project directory")
1974
+ target_dir: z20.string().describe("Absolute path to the project directory")
1907
1975
  },
1908
1976
  async (params) => {
1909
1977
  const db = ensureDb(ctx, params.target_dir);
@@ -2007,15 +2075,15 @@ function registerGetBoundaryAnalysis(server, ctx) {
2007
2075
  }
2008
2076
 
2009
2077
  // src/tools/check-drift.ts
2010
- import { z as z20 } from "zod";
2078
+ import { z as z21 } from "zod";
2011
2079
  import { detectDrift, writeDriftLog } from "@arcbridge/core";
2012
2080
  function registerCheckDrift(server, ctx) {
2013
2081
  server.tool(
2014
2082
  "arcbridge_check_drift",
2015
2083
  "Detect architecture drift: undocumented modules, missing code paths, cross-block dependency violations, and stale ADR references.",
2016
2084
  {
2017
- target_dir: z20.string().describe("Absolute path to the project directory"),
2018
- persist: z20.boolean().default(true).describe("Write findings to drift_log table (default: true)")
2085
+ target_dir: z21.string().describe("Absolute path to the project directory"),
2086
+ persist: z21.boolean().default(true).describe("Write findings to drift_log table (default: true)")
2019
2087
  },
2020
2088
  async (params) => {
2021
2089
  const start = Date.now();
@@ -2087,16 +2155,16 @@ function registerCheckDrift(server, ctx) {
2087
2155
  }
2088
2156
 
2089
2157
  // src/tools/get-guidance.ts
2090
- import { z as z21 } from "zod";
2158
+ import { z as z22 } from "zod";
2091
2159
  import { loadConfig as loadConfig3 } from "@arcbridge/core";
2092
2160
  function registerGetGuidance(server, ctx) {
2093
2161
  server.tool(
2094
2162
  "arcbridge_get_guidance",
2095
2163
  "Get context-aware architectural guidance for a code change. Surfaces relevant quality scenarios, patterns, constraints, and questions to consider.",
2096
2164
  {
2097
- target_dir: z21.string().describe("Absolute path to the project directory"),
2098
- file_path: z21.string().optional().describe("File path you're working on (to determine building block and context)"),
2099
- action: z21.enum([
2165
+ target_dir: z22.string().describe("Absolute path to the project directory"),
2166
+ file_path: z22.string().optional().describe("File path you're working on (to determine building block and context)"),
2167
+ action: z22.enum([
2100
2168
  "adding-component",
2101
2169
  "adding-api-route",
2102
2170
  "adding-hook",
@@ -2294,14 +2362,14 @@ function getActionGuidance(action, projectType) {
2294
2362
  }
2295
2363
 
2296
2364
  // src/tools/get-open-questions.ts
2297
- import { z as z22 } from "zod";
2365
+ import { z as z23 } from "zod";
2298
2366
  function registerGetOpenQuestions(server, ctx) {
2299
2367
  server.tool(
2300
2368
  "arcbridge_get_open_questions",
2301
2369
  "Surface architectural gaps: untested quality scenarios, building blocks without boundaries, unresolved drift, and tasks missing acceptance criteria.",
2302
2370
  {
2303
- target_dir: z22.string().describe("Absolute path to the project directory"),
2304
- scope: z22.string().optional().describe("Focus scope: 'current-phase', 'building-block:<id>', or omit for project-wide")
2371
+ target_dir: z23.string().describe("Absolute path to the project directory"),
2372
+ scope: z23.string().optional().describe("Focus scope: 'current-phase', 'building-block:<id>', or omit for project-wide")
2305
2373
  },
2306
2374
  async (params) => {
2307
2375
  const db = ensureDb(ctx, params.target_dir);
@@ -2411,7 +2479,7 @@ function registerGetOpenQuestions(server, ctx) {
2411
2479
  }
2412
2480
 
2413
2481
  // src/tools/propose-arc42-update.ts
2414
- import { z as z23 } from "zod";
2482
+ import { z as z24 } from "zod";
2415
2483
  import {
2416
2484
  resolveRef,
2417
2485
  getChangedFiles,
@@ -2423,9 +2491,9 @@ function registerProposeArc42Update(server, ctx) {
2423
2491
  "arcbridge_propose_arc42_update",
2424
2492
  "Analyze code changes since a reference point and generate specific, actionable proposals for updating arc42 documentation.",
2425
2493
  {
2426
- target_dir: z23.string().describe("Absolute path to the project directory"),
2427
- changes_since: z23.string().default("last-sync").describe("Reference point: 'last-commit', 'last-sync', 'last-phase', or a git ref"),
2428
- update_sync_point: z23.boolean().default(false).describe("Update the stored sync commit to HEAD after generating proposals")
2494
+ target_dir: z24.string().describe("Absolute path to the project directory"),
2495
+ changes_since: z24.string().default("last-sync").describe("Reference point: 'last-commit', 'last-sync', 'last-phase', or a git ref"),
2496
+ update_sync_point: z24.boolean().default(false).describe("Update the stored sync commit to HEAD after generating proposals")
2429
2497
  },
2430
2498
  async (params) => {
2431
2499
  const db = ensureDb(ctx, params.target_dir);
@@ -2613,7 +2681,7 @@ function findCrossBlockConsumers(db, symbolId, sourceBlockId, blocks) {
2613
2681
  }
2614
2682
 
2615
2683
  // src/tools/get-practice-review.ts
2616
- import { z as z24 } from "zod";
2684
+ import { z as z25 } from "zod";
2617
2685
  import {
2618
2686
  resolveRef as resolveRef2,
2619
2687
  getChangedFiles as getChangedFiles2,
@@ -2625,8 +2693,8 @@ function registerGetPracticeReview(server, ctx) {
2625
2693
  "arcbridge_get_practice_review",
2626
2694
  "Structured, practice-aware review of recent code changes across 5 dimensions: Architecture, Security, Testing, Documentation, and Complexity.",
2627
2695
  {
2628
- target_dir: z24.string().describe("Absolute path to the project directory"),
2629
- since: z24.string().default("last-commit").describe("Reference point: 'last-commit', 'last-session', or 'last-phase'")
2696
+ target_dir: z25.string().describe("Absolute path to the project directory"),
2697
+ since: z25.string().default("last-commit").describe("Reference point: 'last-commit', 'last-session', or 'last-phase'")
2630
2698
  },
2631
2699
  async (params) => {
2632
2700
  const db = ensureDb(ctx, params.target_dir);
@@ -2942,7 +3010,7 @@ function reviewComplexity(db, changedFiles, findings) {
2942
3010
  }
2943
3011
 
2944
3012
  // src/tools/complete-phase.ts
2945
- import { z as z25 } from "zod";
3013
+ import { z as z26 } from "zod";
2946
3014
  import {
2947
3015
  detectDrift as detectDrift3,
2948
3016
  writeDriftLog as writeDriftLog2,
@@ -2952,7 +3020,7 @@ import {
2952
3020
  applyInferences,
2953
3021
  verifyScenarios,
2954
3022
  loadConfig as loadConfig4,
2955
- refreshFromDocs as refreshFromDocs6,
3023
+ refreshFromDocs as refreshFromDocs8,
2956
3024
  syncPhaseToYaml,
2957
3025
  transaction
2958
3026
  } from "@arcbridge/core";
@@ -2961,17 +3029,17 @@ function registerCompletePhase(server, ctx) {
2961
3029
  "arcbridge_complete_phase",
2962
3030
  "Attempt to complete a phase by validating all gates: tasks done, no critical drift, quality scenarios passing. Transitions the phase to 'complete' if all gates pass.",
2963
3031
  {
2964
- target_dir: z25.string().describe("Absolute path to the project directory"),
2965
- phase_id: z25.string().optional().describe("Phase ID to complete (defaults to current in-progress phase)"),
2966
- notes: z25.string().optional().describe("Optional notes about this phase completion"),
2967
- auto_infer: z25.boolean().default(true).describe("Automatically infer task statuses from code state before checking gates"),
2968
- run_tests: z25.boolean().default(false).describe("Run linked tests for quality scenarios before checking the quality gate")
3032
+ target_dir: z26.string().describe("Absolute path to the project directory"),
3033
+ phase_id: z26.string().optional().describe("Phase ID to complete (defaults to current in-progress phase)"),
3034
+ notes: z26.string().optional().describe("Optional notes about this phase completion"),
3035
+ auto_infer: z26.boolean().default(true).describe("Automatically infer task statuses from code state before checking gates"),
3036
+ run_tests: z26.boolean().default(false).describe("Run linked tests for quality scenarios before checking the quality gate")
2969
3037
  },
2970
3038
  async (params) => {
2971
3039
  const start = Date.now();
2972
3040
  const db = ensureDb(ctx, params.target_dir);
2973
3041
  if (!db) return notInitialized();
2974
- refreshFromDocs6(db, params.target_dir);
3042
+ refreshFromDocs8(db, params.target_dir);
2975
3043
  let phase;
2976
3044
  if (params.phase_id) {
2977
3045
  phase = db.prepare("SELECT id, name, phase_number, status, gate_status FROM phases WHERE id = ?").get(params.phase_id);
@@ -3180,18 +3248,18 @@ function registerCompletePhase(server, ctx) {
3180
3248
  }
3181
3249
 
3182
3250
  // src/tools/activate-role.ts
3183
- import { z as z26 } from "zod";
3251
+ import { z as z27 } from "zod";
3184
3252
  import { loadRole, loadRoles } from "@arcbridge/core";
3185
3253
  function registerActivateRole(server, ctx) {
3186
3254
  server.tool(
3187
3255
  "arcbridge_activate_role",
3188
3256
  "Activate an agent role: loads the role's system prompt, required tools, quality focus, and pre-loaded architectural context.",
3189
3257
  {
3190
- target_dir: z26.string().describe("Absolute path to the project directory"),
3191
- role: z26.string().describe(
3258
+ target_dir: z27.string().describe("Absolute path to the project directory"),
3259
+ role: z27.string().describe(
3192
3260
  "Role ID to activate (e.g., 'architect', 'implementer', 'security-reviewer')"
3193
3261
  ),
3194
- building_block: z26.string().optional().describe("Focus on a specific building block (for implementer/code-reviewer roles)")
3262
+ building_block: z27.string().optional().describe("Focus on a specific building block (for implementer/code-reviewer roles)")
3195
3263
  },
3196
3264
  async (params) => {
3197
3265
  const db = ensureDb(ctx, params.target_dir);
@@ -3493,18 +3561,18 @@ function getRoleDefinition(roleId) {
3493
3561
  }
3494
3562
 
3495
3563
  // src/tools/verify-scenarios.ts
3496
- import { z as z27 } from "zod";
3564
+ import { z as z28 } from "zod";
3497
3565
  import { verifyScenarios as verifyScenarios2, loadConfig as loadConfig5 } from "@arcbridge/core";
3498
3566
  function registerVerifyScenarios(server, ctx) {
3499
3567
  server.tool(
3500
3568
  "arcbridge_verify_scenarios",
3501
3569
  "Run linked tests for quality scenarios and update their pass/fail status. Only runs scenarios with verification='automatic' or 'semi-automatic' and non-empty linked_tests.",
3502
3570
  {
3503
- target_dir: z27.string().describe("Absolute path to the project directory"),
3504
- scenario_ids: z27.array(z27.string()).optional().describe(
3571
+ target_dir: z28.string().describe("Absolute path to the project directory"),
3572
+ scenario_ids: z28.array(z28.string()).optional().describe(
3505
3573
  "Specific scenario IDs to verify (e.g., ['SEC-01', 'PERF-01']). If omitted, verifies all automatic scenarios."
3506
3574
  ),
3507
- test_command: z27.string().optional().describe(
3575
+ test_command: z28.string().optional().describe(
3508
3576
  "Override the test command from config (e.g., 'npx jest'). File paths are appended as arguments."
3509
3577
  )
3510
3578
  },
@@ -3571,7 +3639,7 @@ function registerVerifyScenarios(server, ctx) {
3571
3639
  }
3572
3640
 
3573
3641
  // src/tools/run-role-check.ts
3574
- import { z as z28 } from "zod";
3642
+ import { z as z29 } from "zod";
3575
3643
  import {
3576
3644
  loadRole as loadRole2,
3577
3645
  loadRoles as loadRoles2,
@@ -3586,11 +3654,11 @@ function registerRunRoleCheck(server, ctx) {
3586
3654
  "arcbridge_run_role_check",
3587
3655
  "Run a role-specific architectural analysis: resolves the role and executes relevant checks (drift, quality scenarios, boundaries, changed files) based on the role's focus areas.",
3588
3656
  {
3589
- target_dir: z28.string().describe("Absolute path to the project directory"),
3590
- role: z28.string().describe(
3657
+ target_dir: z29.string().describe("Absolute path to the project directory"),
3658
+ role: z29.string().describe(
3591
3659
  "Role ID to run checks for (e.g., 'security-reviewer', 'quality-guardian', 'architect', 'phase-manager', 'code-reviewer')"
3592
3660
  ),
3593
- scope: z28.enum(SCOPE_VALUES).default("current-phase").describe(
3661
+ scope: z29.enum(SCOPE_VALUES).default("current-phase").describe(
3594
3662
  "Scope of analysis: 'last-commit' (recent changes), 'current-phase' (since phase start), 'full-project' (everything)"
3595
3663
  )
3596
3664
  },
@@ -4011,17 +4079,17 @@ function runCustomRoleCheck(db, lines, roleDef) {
4011
4079
  }
4012
4080
 
4013
4081
  // src/tools/update-scenario-status.ts
4014
- import { z as z29 } from "zod";
4082
+ import { z as z30 } from "zod";
4015
4083
  import { syncScenarioToYaml, transaction as transaction2 } from "@arcbridge/core";
4016
4084
  function registerUpdateScenarioStatus(server, ctx) {
4017
4085
  server.tool(
4018
4086
  "arcbridge_update_scenario_status",
4019
4087
  "Update a quality scenario's status and optionally link test files. Use this to mark scenarios as passing/failing after manual verification, or to link test files so `arcbridge_verify_scenarios` can run them automatically.",
4020
4088
  {
4021
- target_dir: z29.string().describe("Absolute path to the project directory"),
4022
- scenario_id: z29.string().describe("Quality scenario ID (e.g., 'SEC-01', 'PERF-01')"),
4023
- status: z29.enum(["passing", "failing", "untested", "partial"]).describe("New status for the scenario"),
4024
- linked_tests: z29.array(z29.string()).optional().describe(
4089
+ target_dir: z30.string().describe("Absolute path to the project directory"),
4090
+ scenario_id: z30.string().describe("Quality scenario ID (e.g., 'SEC-01', 'PERF-01')"),
4091
+ status: z30.enum(["passing", "failing", "untested", "partial"]).describe("New status for the scenario"),
4092
+ linked_tests: z30.array(z30.string()).optional().describe(
4025
4093
  "Test file paths to link to this scenario (e.g., ['src/__tests__/auth.test.ts']). Once linked, `arcbridge_verify_scenarios` can run them automatically. Also sets verification to 'semi-automatic' if currently 'manual'."
4026
4094
  )
4027
4095
  },
@@ -4102,33 +4170,33 @@ ${invalid.map((p) => ` - ${p}`).join("\n")}`
4102
4170
  }
4103
4171
 
4104
4172
  // src/tools/record-activity.ts
4105
- import { z as z30 } from "zod";
4173
+ import { z as z31 } from "zod";
4106
4174
  import { insertActivity as insertActivity2, getSessionTotals } from "@arcbridge/core";
4107
4175
  function registerRecordActivity(server, ctx) {
4108
4176
  server.tool(
4109
4177
  "arcbridge_record_activity",
4110
4178
  "Record agent activity \u2014 model, tokens, cost, duration, and optional quality snapshot. Use this to track what work was done and measure agent performance.",
4111
4179
  {
4112
- target_dir: z30.string().describe("Absolute path to the project directory"),
4113
- tool_name: z30.string().describe("Name of the tool or action performed (e.g., 'arcbridge_update_task', 'code_edit')"),
4114
- action: z30.string().optional().describe("Human-readable label (e.g., 'implement login form')"),
4115
- model: z30.string().optional().describe("Model identifier (e.g., 'claude-sonnet-4-20250514')"),
4116
- agent_role: z30.string().optional().describe("Active ArcBridge role (e.g., 'implementer')"),
4117
- task_id: z30.string().optional().describe("Associated task ID"),
4118
- phase_id: z30.string().optional().describe("Associated phase ID"),
4119
- input_tokens: z30.number().int().nonnegative().optional().describe("Input/prompt tokens"),
4120
- output_tokens: z30.number().int().nonnegative().optional().describe("Output/completion tokens"),
4121
- total_tokens: z30.number().int().nonnegative().optional().describe("Total tokens (auto-computed if input+output given)"),
4122
- cost_usd: z30.number().nonnegative().optional().describe("Estimated cost in USD"),
4123
- duration_ms: z30.number().int().nonnegative().optional().describe("Wall-clock duration in ms"),
4124
- drift_count: z30.number().int().nonnegative().optional().describe("Current drift count"),
4125
- drift_errors: z30.number().int().nonnegative().optional().describe("Current drift errors"),
4126
- test_pass_count: z30.number().int().nonnegative().optional().describe("Passing tests"),
4127
- test_fail_count: z30.number().int().nonnegative().optional().describe("Failing tests"),
4128
- lint_clean: z30.boolean().optional().describe("Whether lint passes cleanly"),
4129
- typecheck_clean: z30.boolean().optional().describe("Whether typecheck passes cleanly"),
4130
- notes: z30.string().optional().describe("Free-form notes"),
4131
- metadata: z30.record(z30.unknown()).optional().describe("Additional key-value metadata")
4180
+ target_dir: z31.string().describe("Absolute path to the project directory"),
4181
+ tool_name: z31.string().describe("Name of the tool or action performed (e.g., 'arcbridge_update_task', 'code_edit')"),
4182
+ action: z31.string().optional().describe("Human-readable label (e.g., 'implement login form')"),
4183
+ model: z31.string().optional().describe("Model identifier (e.g., 'claude-sonnet-4-20250514')"),
4184
+ agent_role: z31.string().optional().describe("Active ArcBridge role (e.g., 'implementer')"),
4185
+ task_id: z31.string().optional().describe("Associated task ID"),
4186
+ phase_id: z31.string().optional().describe("Associated phase ID"),
4187
+ input_tokens: z31.number().int().nonnegative().optional().describe("Input/prompt tokens"),
4188
+ output_tokens: z31.number().int().nonnegative().optional().describe("Output/completion tokens"),
4189
+ total_tokens: z31.number().int().nonnegative().optional().describe("Total tokens (auto-computed if input+output given)"),
4190
+ cost_usd: z31.number().nonnegative().optional().describe("Estimated cost in USD"),
4191
+ duration_ms: z31.number().int().nonnegative().optional().describe("Wall-clock duration in ms"),
4192
+ drift_count: z31.number().int().nonnegative().optional().describe("Current drift count"),
4193
+ drift_errors: z31.number().int().nonnegative().optional().describe("Current drift errors"),
4194
+ test_pass_count: z31.number().int().nonnegative().optional().describe("Passing tests"),
4195
+ test_fail_count: z31.number().int().nonnegative().optional().describe("Failing tests"),
4196
+ lint_clean: z31.boolean().optional().describe("Whether lint passes cleanly"),
4197
+ typecheck_clean: z31.boolean().optional().describe("Whether typecheck passes cleanly"),
4198
+ notes: z31.string().optional().describe("Free-form notes"),
4199
+ metadata: z31.record(z31.unknown()).optional().describe("Additional key-value metadata")
4132
4200
  },
4133
4201
  async (params) => {
4134
4202
  const db = ensureDb(ctx, params.target_dir);
@@ -4183,23 +4251,23 @@ function registerRecordActivity(server, ctx) {
4183
4251
  }
4184
4252
 
4185
4253
  // src/tools/get-metrics.ts
4186
- import { z as z31 } from "zod";
4254
+ import { z as z32 } from "zod";
4187
4255
  import { queryMetrics } from "@arcbridge/core";
4188
4256
  function registerGetMetrics(server, ctx) {
4189
4257
  server.tool(
4190
4258
  "arcbridge_get_metrics",
4191
4259
  "Query agent activity metrics \u2014 filter by model, task, phase, or time range. Group by model/task/phase/tool/day for aggregated views.",
4192
4260
  {
4193
- target_dir: z31.string().describe("Absolute path to the project directory"),
4194
- task_id: z31.string().optional().describe("Filter by task ID"),
4195
- phase_id: z31.string().optional().describe("Filter by phase ID"),
4196
- model: z31.string().optional().describe("Filter by model name"),
4197
- agent_role: z31.string().optional().describe("Filter by agent role"),
4198
- tool_name: z31.string().optional().describe("Filter by tool name"),
4199
- since: z31.string().optional().describe("ISO 8601 timestamp \u2014 activity after this time"),
4200
- until: z31.string().optional().describe("ISO 8601 timestamp \u2014 activity before this time"),
4201
- group_by: z31.enum(["model", "task", "phase", "tool", "day", "none"]).default("none").describe("Group results for aggregation"),
4202
- limit: z31.number().int().min(1).max(500).default(50).describe("Max rows in detail view (group_by=none)")
4261
+ target_dir: z32.string().describe("Absolute path to the project directory"),
4262
+ task_id: z32.string().optional().describe("Filter by task ID"),
4263
+ phase_id: z32.string().optional().describe("Filter by phase ID"),
4264
+ model: z32.string().optional().describe("Filter by model name"),
4265
+ agent_role: z32.string().optional().describe("Filter by agent role"),
4266
+ tool_name: z32.string().optional().describe("Filter by tool name"),
4267
+ since: z32.string().optional().describe("ISO 8601 timestamp \u2014 activity after this time"),
4268
+ until: z32.string().optional().describe("ISO 8601 timestamp \u2014 activity before this time"),
4269
+ group_by: z32.enum(["model", "task", "phase", "tool", "day", "none"]).default("none").describe("Group results for aggregation"),
4270
+ limit: z32.number().int().min(1).max(500).default(50).describe("Max rows in detail view (group_by=none)")
4203
4271
  },
4204
4272
  async (params) => {
4205
4273
  const db = ensureDb(ctx, params.target_dir);
@@ -4282,23 +4350,23 @@ function mdCell(val) {
4282
4350
  }
4283
4351
 
4284
4352
  // src/tools/export-metrics.ts
4285
- import { z as z32 } from "zod";
4353
+ import { z as z33 } from "zod";
4286
4354
  import { exportMetrics } from "@arcbridge/core";
4287
4355
  function registerExportMetrics(server, ctx) {
4288
4356
  server.tool(
4289
4357
  "arcbridge_export_metrics",
4290
4358
  "Export agent activity metrics to a file (JSON, CSV, or Markdown) in .arcbridge/metrics/ for git commits or reporting.",
4291
4359
  {
4292
- target_dir: z32.string().describe("Absolute path to the project directory"),
4293
- format: z32.enum(["json", "csv", "markdown"]).default("json").describe("Export format"),
4294
- task_id: z32.string().optional().describe("Filter by task ID"),
4295
- phase_id: z32.string().optional().describe("Filter by phase ID"),
4296
- model: z32.string().optional().describe("Filter by model name"),
4297
- agent_role: z32.string().optional().describe("Filter by agent role"),
4298
- tool_name: z32.string().optional().describe("Filter by tool name"),
4299
- since: z32.string().optional().describe("ISO 8601 \u2014 activity after this time"),
4300
- until: z32.string().optional().describe("ISO 8601 \u2014 activity before this time"),
4301
- max_rows: z32.number().int().min(1).default(1e5).describe("Maximum rows to export (default: 100,000)")
4360
+ target_dir: z33.string().describe("Absolute path to the project directory"),
4361
+ format: z33.enum(["json", "csv", "markdown"]).default("json").describe("Export format"),
4362
+ task_id: z33.string().optional().describe("Filter by task ID"),
4363
+ phase_id: z33.string().optional().describe("Filter by phase ID"),
4364
+ model: z33.string().optional().describe("Filter by model name"),
4365
+ agent_role: z33.string().optional().describe("Filter by agent role"),
4366
+ tool_name: z33.string().optional().describe("Filter by tool name"),
4367
+ since: z33.string().optional().describe("ISO 8601 \u2014 activity after this time"),
4368
+ until: z33.string().optional().describe("ISO 8601 \u2014 activity before this time"),
4369
+ max_rows: z33.number().int().min(1).default(1e5).describe("Maximum rows to export (default: 100,000)")
4302
4370
  },
4303
4371
  async (params) => {
4304
4372
  const db = ensureDb(ctx, params.target_dir);
@@ -4348,6 +4416,7 @@ function createArcBridgeServer() {
4348
4416
  registerCreateTask(server, ctx);
4349
4417
  registerDeleteTask(server, ctx);
4350
4418
  registerCreatePhase(server, ctx);
4419
+ registerDeletePhase(server, ctx);
4351
4420
  registerReindex(server, ctx);
4352
4421
  registerSearchSymbols(server, ctx);
4353
4422
  registerGetSymbol(server, ctx);