@arcbridge/mcp-server 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
  ];
@@ -754,7 +756,7 @@ import { refreshFromDocs as refreshFromDocs3 } from "@arcbridge/core";
754
756
  function registerGetCurrentTasks(server, ctx) {
755
757
  server.tool(
756
758
  "arcbridge_get_current_tasks",
757
- "Get tasks for the current in-progress phase, with their building blocks, quality scenarios, and acceptance criteria.",
759
+ "Get tasks for the current phase (in-progress, or first planned if none is in-progress), with their building blocks, quality scenarios, and acceptance criteria.",
758
760
  {
759
761
  target_dir: z7.string().describe("Absolute path to the project directory"),
760
762
  status: z7.enum(["todo", "in-progress", "done", "blocked"]).optional().describe("Filter tasks by status")
@@ -763,15 +765,20 @@ function registerGetCurrentTasks(server, ctx) {
763
765
  const db = ensureDb(ctx, params.target_dir);
764
766
  if (!db) return notInitialized();
765
767
  refreshFromDocs3(db, params.target_dir);
766
- const currentPhase = db.prepare(
768
+ let currentPhase = db.prepare(
767
769
  "SELECT id, name FROM phases WHERE status = 'in-progress' ORDER BY phase_number LIMIT 1"
768
770
  ).get();
771
+ if (!currentPhase) {
772
+ currentPhase = db.prepare(
773
+ "SELECT id, name FROM phases WHERE status = 'planned' ORDER BY phase_number LIMIT 1"
774
+ ).get();
775
+ }
769
776
  if (!currentPhase) {
770
777
  return {
771
778
  content: [
772
779
  {
773
780
  type: "text",
774
- text: "No phase is currently in-progress. Use `arcbridge_get_phase_plan` to see all phases."
781
+ text: "No active or planned phases found. Use `arcbridge_get_phase_plan` to see all phases."
775
782
  }
776
783
  ]
777
784
  };
@@ -1073,40 +1080,62 @@ If you need a new block, add it to \`.arcbridge/arc42/05-building-blocks.md\` an
1073
1080
 
1074
1081
  // src/tools/delete-task.ts
1075
1082
  import { z as z10 } from "zod";
1076
- import { deleteTaskFromYaml } from "@arcbridge/core";
1083
+ import { deleteTaskFromYaml, refreshFromDocs as refreshFromDocs4 } from "@arcbridge/core";
1077
1084
  function registerDeleteTask(server, ctx) {
1078
1085
  server.tool(
1079
1086
  "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.",
1087
+ "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
1088
  {
1082
1089
  target_dir: z10.string().describe("Absolute path to the project directory"),
1083
- task_id: z10.string().describe("Task ID to delete")
1090
+ task_id: z10.string().optional().describe("Single task ID to delete (deprecated \u2014 use task_ids)"),
1091
+ task_ids: z10.array(z10.string()).optional().describe("Task IDs to delete (preferred)")
1084
1092
  },
1085
1093
  async (params) => {
1086
1094
  const db = ensureDb(ctx, params.target_dir);
1087
1095
  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
- );
1096
+ const ids = params.task_ids ?? (params.task_id ? [params.task_id] : []);
1097
+ if (ids.length === 0) {
1098
+ return textResult("Provide `task_ids` (array) or `task_id` (string) to delete.");
1099
+ }
1100
+ const results = [];
1101
+ const warnings = [];
1102
+ for (const id of ids) {
1103
+ const task = db.prepare("SELECT id, title, phase_id FROM tasks WHERE id = ?").get(id);
1104
+ if (!task) {
1105
+ warnings.push(`Task '${id}' not found \u2014 skipped`);
1106
+ continue;
1107
+ }
1108
+ const yamlResult = deleteTaskFromYaml(params.target_dir, task.phase_id, id);
1109
+ if (yamlResult.success === false) {
1110
+ warnings.push(`${task.id}: ${yamlResult.warning ?? "YAML delete failed"}`);
1111
+ } else {
1112
+ results.push(`- **${task.id}**: "${task.title}"`);
1113
+ if (yamlResult.warning) {
1114
+ warnings.push(`${task.id}: ${yamlResult.warning}`);
1115
+ }
1116
+ }
1093
1117
  }
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}`);
1118
+ if (results.length > 0) {
1119
+ refreshFromDocs4(db, params.target_dir);
1120
+ }
1121
+ const lines = [];
1122
+ if (results.length > 0) {
1123
+ lines.push(`Deleted ${results.length} task${results.length === 1 ? "" : "s"}:`, "", ...results);
1124
+ }
1125
+ if (warnings.length > 0) {
1126
+ lines.push("", "**Warnings:**", ...warnings.map((w) => `- ${w}`));
1127
+ }
1128
+ if (results.length === 0 && warnings.length > 0) {
1129
+ lines.unshift("No tasks were deleted.");
1101
1130
  }
1102
- return textResult(msg);
1131
+ return textResult(lines.join("\n"));
1103
1132
  }
1104
1133
  );
1105
1134
  }
1106
1135
 
1107
1136
  // src/tools/create-phase.ts
1108
1137
  import { z as z11 } from "zod";
1109
- import { addPhaseToYaml, refreshFromDocs as refreshFromDocs4 } from "@arcbridge/core";
1138
+ import { addPhaseToYaml, refreshFromDocs as refreshFromDocs5 } from "@arcbridge/core";
1110
1139
  function registerCreatePhase(server, ctx) {
1111
1140
  server.tool(
1112
1141
  "arcbridge_create_phase",
@@ -1121,7 +1150,7 @@ function registerCreatePhase(server, ctx) {
1121
1150
  async (params) => {
1122
1151
  const db = ensureDb(ctx, params.target_dir);
1123
1152
  if (!db) return notInitialized();
1124
- refreshFromDocs4(db, params.target_dir);
1153
+ refreshFromDocs5(db, params.target_dir);
1125
1154
  const maxPhase = db.prepare("SELECT MAX(phase_number) as max FROM phases").get();
1126
1155
  const phaseNumber = params.phase_number ?? (maxPhase.max ?? -1) + 1;
1127
1156
  const existing = db.prepare("SELECT id FROM phases WHERE phase_number = ?").get(phaseNumber);
@@ -1144,7 +1173,7 @@ function registerCreatePhase(server, ctx) {
1144
1173
  `Failed to create phase: ${yamlResult.warning ?? "YAML update failed"}`
1145
1174
  );
1146
1175
  }
1147
- refreshFromDocs4(db, params.target_dir);
1176
+ refreshFromDocs5(db, params.target_dir);
1148
1177
  const lines = [
1149
1178
  `Phase created: **${phaseId}**`,
1150
1179
  "",
@@ -1168,16 +1197,60 @@ function registerCreatePhase(server, ctx) {
1168
1197
  );
1169
1198
  }
1170
1199
 
1171
- // src/tools/get-relevant-adrs.ts
1200
+ // src/tools/delete-phase.ts
1172
1201
  import { z as z12 } from "zod";
1202
+ import { deletePhaseFromYaml, refreshFromDocs as refreshFromDocs6 } from "@arcbridge/core";
1203
+ function registerDeletePhase(server, ctx) {
1204
+ server.tool(
1205
+ "arcbridge_delete_phase",
1206
+ "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.",
1207
+ {
1208
+ target_dir: z12.string().describe("Absolute path to the project directory"),
1209
+ phase_id: z12.string().describe("Phase ID to delete")
1210
+ },
1211
+ async (params) => {
1212
+ const db = ensureDb(ctx, params.target_dir);
1213
+ if (!db) return notInitialized();
1214
+ const phase = db.prepare("SELECT id, name, phase_number, status FROM phases WHERE id = ?").get(params.phase_id);
1215
+ if (!phase) {
1216
+ return textResult(
1217
+ `Phase '${params.phase_id}' not found. Use \`arcbridge_get_phase_plan\` to see available phases.`
1218
+ );
1219
+ }
1220
+ if (phase.status !== "planned") {
1221
+ return textResult(
1222
+ `Cannot delete phase **${phase.id}** (status: ${phase.status}). Only phases with status 'planned' can be deleted.`
1223
+ );
1224
+ }
1225
+ const taskCount = db.prepare("SELECT COUNT(*) as count FROM tasks WHERE phase_id = ?").get(params.phase_id);
1226
+ const yamlResult = deletePhaseFromYaml(params.target_dir, params.phase_id);
1227
+ if (!yamlResult.success) {
1228
+ return textResult(
1229
+ `Failed to delete phase: ${yamlResult.warning ?? "Unknown error"}`
1230
+ );
1231
+ }
1232
+ refreshFromDocs6(db, params.target_dir);
1233
+ const lines = [
1234
+ `Phase **${phase.id}** deleted: "${phase.name}" (phase ${phase.phase_number})`
1235
+ ];
1236
+ if (taskCount.count > 0) {
1237
+ lines.push(`${taskCount.count} task${taskCount.count === 1 ? "" : "s"} removed.`);
1238
+ }
1239
+ return textResult(lines.join("\n"));
1240
+ }
1241
+ );
1242
+ }
1243
+
1244
+ // src/tools/get-relevant-adrs.ts
1245
+ import { z as z13 } from "zod";
1173
1246
  function registerGetRelevantAdrs(server, ctx) {
1174
1247
  server.tool(
1175
1248
  "arcbridge_get_relevant_adrs",
1176
1249
  "Get architectural decision records (ADRs) relevant to a specific file path or building block.",
1177
1250
  {
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")
1251
+ target_dir: z13.string().describe("Absolute path to the project directory"),
1252
+ file_path: z13.string().optional().describe("File path to find relevant ADRs for"),
1253
+ building_block: z13.string().optional().describe("Building block ID to find relevant ADRs for")
1181
1254
  },
1182
1255
  async (params) => {
1183
1256
  const db = ensureDb(ctx, params.target_dir);
@@ -1261,24 +1334,24 @@ function formatAdrs(adrs, title) {
1261
1334
  }
1262
1335
 
1263
1336
  // src/tools/reindex.ts
1264
- import { z as z13 } from "zod";
1265
- import { indexProject as indexProject2, refreshFromDocs as refreshFromDocs5 } from "@arcbridge/core";
1337
+ import { z as z14 } from "zod";
1338
+ import { indexProject as indexProject2, refreshFromDocs as refreshFromDocs7 } from "@arcbridge/core";
1266
1339
  function registerReindex(server, ctx) {
1267
1340
  server.tool(
1268
1341
  "arcbridge_reindex",
1269
1342
  "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
1343
  {
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')")
1344
+ target_dir: z14.string().describe("Absolute path to the project directory"),
1345
+ tsconfig_path: z14.string().optional().describe("Override tsconfig.json path (default: auto-detect). Only used for TypeScript projects."),
1346
+ service: z14.string().optional().describe("Service name for monorepo projects (default: 'main')"),
1347
+ language: z14.enum(["typescript", "csharp", "auto"]).optional().describe("Project language. 'auto' detects from project files (default: 'auto')")
1275
1348
  },
1276
1349
  async (params) => {
1277
1350
  const start = Date.now();
1278
1351
  const db = ensureDb(ctx, params.target_dir);
1279
1352
  if (!db) return notInitialized();
1280
1353
  try {
1281
- const docWarnings = refreshFromDocs5(db, params.target_dir);
1354
+ const docWarnings = refreshFromDocs7(db, params.target_dir);
1282
1355
  const result = await indexProject2(db, {
1283
1356
  projectRoot: params.target_dir,
1284
1357
  tsconfigPath: params.tsconfig_path,
@@ -1317,16 +1390,16 @@ function registerReindex(server, ctx) {
1317
1390
  }
1318
1391
 
1319
1392
  // src/tools/search-symbols.ts
1320
- import { z as z14 } from "zod";
1393
+ import { z as z15 } from "zod";
1321
1394
  function registerSearchSymbols(server, ctx) {
1322
1395
  server.tool(
1323
1396
  "arcbridge_search_symbols",
1324
1397
  "Search code symbols by name, kind, file path, or building block. Supports TypeScript and C#. Returns matching symbols with type signatures.",
1325
1398
  {
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([
1399
+ target_dir: z15.string().describe("Absolute path to the project directory"),
1400
+ query: z15.string().optional().describe("Search term to match against symbol names"),
1401
+ service: z15.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services."),
1402
+ kind: z15.enum([
1330
1403
  "function",
1331
1404
  "class",
1332
1405
  "type",
@@ -1338,10 +1411,10 @@ function registerSearchSymbols(server, ctx) {
1338
1411
  "hook",
1339
1412
  "context"
1340
1413
  ]).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)")
1414
+ file_path: z15.string().optional().describe("Filter by file path (prefix match)"),
1415
+ is_exported: z15.boolean().optional().describe("Filter by export status"),
1416
+ building_block: z15.string().optional().describe("Filter by building block ID (matches against code_paths)"),
1417
+ limit: z15.number().int().min(1).max(200).default(50).describe("Maximum results to return (default: 50)")
1345
1418
  },
1346
1419
  async (params) => {
1347
1420
  const db = ensureDb(ctx, params.target_dir);
@@ -1428,7 +1501,7 @@ function registerSearchSymbols(server, ctx) {
1428
1501
  }
1429
1502
 
1430
1503
  // src/tools/get-symbol.ts
1431
- import { z as z15 } from "zod";
1504
+ import { z as z16 } from "zod";
1432
1505
  import { readFileSync, existsSync as existsSync3 } from "fs";
1433
1506
  import { join as join3 } from "path";
1434
1507
  function registerGetSymbol(server, ctx) {
@@ -1436,11 +1509,11 @@ function registerGetSymbol(server, ctx) {
1436
1509
  "arcbridge_get_symbol",
1437
1510
  "Get detailed information about a specific TypeScript symbol including its source code, type signature, and relationships.",
1438
1511
  {
1439
- target_dir: z15.string().describe("Absolute path to the project directory"),
1440
- symbol_id: z15.string().describe(
1512
+ target_dir: z16.string().describe("Absolute path to the project directory"),
1513
+ symbol_id: z16.string().describe(
1441
1514
  "Symbol ID (e.g. 'src/utils.ts::formatName#function')"
1442
1515
  ),
1443
- include_source: z15.boolean().default(true).describe("Include source code snippet (default: true)")
1516
+ include_source: z16.boolean().default(true).describe("Include source code snippet (default: true)")
1444
1517
  },
1445
1518
  async (params) => {
1446
1519
  const db = ensureDb(ctx, params.target_dir);
@@ -1538,21 +1611,21 @@ Use \`arcbridge_search_symbols\` to find symbols by name.`
1538
1611
  }
1539
1612
 
1540
1613
  // src/tools/get-dependency-graph.ts
1541
- import { z as z16 } from "zod";
1614
+ import { z as z17 } from "zod";
1542
1615
  function registerGetDependencyGraph(server, ctx) {
1543
1616
  server.tool(
1544
1617
  "arcbridge_get_dependency_graph",
1545
1618
  "Get the dependency graph for a module or file. Shows imports, calls, type usage, and inheritance relationships between symbols.",
1546
1619
  {
1547
- target_dir: z16.string().describe("Absolute path to the project directory"),
1548
- module: z16.string().describe(
1620
+ target_dir: z17.string().describe("Absolute path to the project directory"),
1621
+ module: z17.string().describe(
1549
1622
  "Module path relative to project root (e.g. 'src/lib/auth')"
1550
1623
  ),
1551
- direction: z16.enum(["dependencies", "dependents", "both"]).default("both").describe(
1624
+ direction: z17.enum(["dependencies", "dependents", "both"]).default("both").describe(
1552
1625
  "Graph direction: 'dependencies' (what this module uses), 'dependents' (what uses this module), or 'both'"
1553
1626
  ),
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.")
1627
+ depth: z17.number().int().min(1).max(5).default(1).describe("How many levels to traverse (default: 1, max: 5)"),
1628
+ service: z17.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services.")
1556
1629
  },
1557
1630
  async (params) => {
1558
1631
  const maybeDb = ensureDb(ctx, params.target_dir);
@@ -1699,16 +1772,16 @@ function formatEdges(edges, modulePath, direction) {
1699
1772
  }
1700
1773
 
1701
1774
  // src/tools/get-component-graph.ts
1702
- import { z as z17 } from "zod";
1775
+ import { z as z18 } from "zod";
1703
1776
  function registerGetComponentGraph(server, ctx) {
1704
1777
  server.tool(
1705
1778
  "arcbridge_get_component_graph",
1706
1779
  "Get the React component graph: component hierarchy, props, state, context usage, and server/client boundaries.",
1707
1780
  {
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)")
1781
+ target_dir: z18.string().describe("Absolute path to the project directory"),
1782
+ file_path: z18.string().optional().describe("Filter to components in a specific file or directory prefix"),
1783
+ client_only: z18.boolean().optional().describe("Only show client components ('use client')"),
1784
+ with_state: z18.boolean().optional().describe("Only show components that use state (useState/useReducer)")
1712
1785
  },
1713
1786
  async (params) => {
1714
1787
  const db = ensureDb(ctx, params.target_dir);
@@ -1812,16 +1885,16 @@ function registerGetComponentGraph(server, ctx) {
1812
1885
  }
1813
1886
 
1814
1887
  // src/tools/get-route-map.ts
1815
- import { z as z18 } from "zod";
1888
+ import { z as z19 } from "zod";
1816
1889
  function registerGetRouteMap(server, ctx) {
1817
1890
  server.tool(
1818
1891
  "arcbridge_get_route_map",
1819
1892
  "Get the route map: pages, layouts, API routes, and their hierarchy. Works with Next.js, ASP.NET controllers, and minimal APIs.",
1820
1893
  {
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.")
1894
+ target_dir: z19.string().describe("Absolute path to the project directory"),
1895
+ kind: z19.enum(["page", "layout", "loading", "error", "not-found", "api-route", "middleware"]).optional().describe("Filter by route kind"),
1896
+ route_prefix: z19.string().optional().describe("Filter by route path prefix (e.g. '/dashboard' or '/api/orders')"),
1897
+ service: z19.string().optional().describe("Filter by service name (for multi-project solutions). Omit to show all services.")
1825
1898
  },
1826
1899
  async (params) => {
1827
1900
  const db = ensureDb(ctx, params.target_dir);
@@ -1897,13 +1970,13 @@ function registerGetRouteMap(server, ctx) {
1897
1970
  }
1898
1971
 
1899
1972
  // src/tools/get-boundary-analysis.ts
1900
- import { z as z19 } from "zod";
1973
+ import { z as z20 } from "zod";
1901
1974
  function registerGetBoundaryAnalysis(server, ctx) {
1902
1975
  server.tool(
1903
1976
  "arcbridge_get_boundary_analysis",
1904
1977
  "Analyze server/client boundaries in a Next.js project. Identifies client components, server components, server actions, and potential boundary violations.",
1905
1978
  {
1906
- target_dir: z19.string().describe("Absolute path to the project directory")
1979
+ target_dir: z20.string().describe("Absolute path to the project directory")
1907
1980
  },
1908
1981
  async (params) => {
1909
1982
  const db = ensureDb(ctx, params.target_dir);
@@ -2007,15 +2080,15 @@ function registerGetBoundaryAnalysis(server, ctx) {
2007
2080
  }
2008
2081
 
2009
2082
  // src/tools/check-drift.ts
2010
- import { z as z20 } from "zod";
2083
+ import { z as z21 } from "zod";
2011
2084
  import { detectDrift, writeDriftLog } from "@arcbridge/core";
2012
2085
  function registerCheckDrift(server, ctx) {
2013
2086
  server.tool(
2014
2087
  "arcbridge_check_drift",
2015
2088
  "Detect architecture drift: undocumented modules, missing code paths, cross-block dependency violations, and stale ADR references.",
2016
2089
  {
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)")
2090
+ target_dir: z21.string().describe("Absolute path to the project directory"),
2091
+ persist: z21.boolean().default(true).describe("Write findings to drift_log table (default: true)")
2019
2092
  },
2020
2093
  async (params) => {
2021
2094
  const start = Date.now();
@@ -2087,16 +2160,16 @@ function registerCheckDrift(server, ctx) {
2087
2160
  }
2088
2161
 
2089
2162
  // src/tools/get-guidance.ts
2090
- import { z as z21 } from "zod";
2163
+ import { z as z22 } from "zod";
2091
2164
  import { loadConfig as loadConfig3 } from "@arcbridge/core";
2092
2165
  function registerGetGuidance(server, ctx) {
2093
2166
  server.tool(
2094
2167
  "arcbridge_get_guidance",
2095
2168
  "Get context-aware architectural guidance for a code change. Surfaces relevant quality scenarios, patterns, constraints, and questions to consider.",
2096
2169
  {
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([
2170
+ target_dir: z22.string().describe("Absolute path to the project directory"),
2171
+ file_path: z22.string().optional().describe("File path you're working on (to determine building block and context)"),
2172
+ action: z22.enum([
2100
2173
  "adding-component",
2101
2174
  "adding-api-route",
2102
2175
  "adding-hook",
@@ -2294,14 +2367,14 @@ function getActionGuidance(action, projectType) {
2294
2367
  }
2295
2368
 
2296
2369
  // src/tools/get-open-questions.ts
2297
- import { z as z22 } from "zod";
2370
+ import { z as z23 } from "zod";
2298
2371
  function registerGetOpenQuestions(server, ctx) {
2299
2372
  server.tool(
2300
2373
  "arcbridge_get_open_questions",
2301
2374
  "Surface architectural gaps: untested quality scenarios, building blocks without boundaries, unresolved drift, and tasks missing acceptance criteria.",
2302
2375
  {
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")
2376
+ target_dir: z23.string().describe("Absolute path to the project directory"),
2377
+ scope: z23.string().optional().describe("Focus scope: 'current-phase', 'building-block:<id>', or omit for project-wide")
2305
2378
  },
2306
2379
  async (params) => {
2307
2380
  const db = ensureDb(ctx, params.target_dir);
@@ -2411,7 +2484,7 @@ function registerGetOpenQuestions(server, ctx) {
2411
2484
  }
2412
2485
 
2413
2486
  // src/tools/propose-arc42-update.ts
2414
- import { z as z23 } from "zod";
2487
+ import { z as z24 } from "zod";
2415
2488
  import {
2416
2489
  resolveRef,
2417
2490
  getChangedFiles,
@@ -2423,9 +2496,9 @@ function registerProposeArc42Update(server, ctx) {
2423
2496
  "arcbridge_propose_arc42_update",
2424
2497
  "Analyze code changes since a reference point and generate specific, actionable proposals for updating arc42 documentation.",
2425
2498
  {
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")
2499
+ target_dir: z24.string().describe("Absolute path to the project directory"),
2500
+ changes_since: z24.string().default("last-sync").describe("Reference point: 'last-commit', 'last-sync', 'last-phase', or a git ref"),
2501
+ update_sync_point: z24.boolean().default(false).describe("Update the stored sync commit to HEAD after generating proposals")
2429
2502
  },
2430
2503
  async (params) => {
2431
2504
  const db = ensureDb(ctx, params.target_dir);
@@ -2613,7 +2686,7 @@ function findCrossBlockConsumers(db, symbolId, sourceBlockId, blocks) {
2613
2686
  }
2614
2687
 
2615
2688
  // src/tools/get-practice-review.ts
2616
- import { z as z24 } from "zod";
2689
+ import { z as z25 } from "zod";
2617
2690
  import {
2618
2691
  resolveRef as resolveRef2,
2619
2692
  getChangedFiles as getChangedFiles2,
@@ -2625,8 +2698,8 @@ function registerGetPracticeReview(server, ctx) {
2625
2698
  "arcbridge_get_practice_review",
2626
2699
  "Structured, practice-aware review of recent code changes across 5 dimensions: Architecture, Security, Testing, Documentation, and Complexity.",
2627
2700
  {
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'")
2701
+ target_dir: z25.string().describe("Absolute path to the project directory"),
2702
+ since: z25.string().default("last-commit").describe("Reference point: 'last-commit', 'last-session', or 'last-phase'")
2630
2703
  },
2631
2704
  async (params) => {
2632
2705
  const db = ensureDb(ctx, params.target_dir);
@@ -2942,7 +3015,7 @@ function reviewComplexity(db, changedFiles, findings) {
2942
3015
  }
2943
3016
 
2944
3017
  // src/tools/complete-phase.ts
2945
- import { z as z25 } from "zod";
3018
+ import { z as z26 } from "zod";
2946
3019
  import {
2947
3020
  detectDrift as detectDrift3,
2948
3021
  writeDriftLog as writeDriftLog2,
@@ -2952,7 +3025,7 @@ import {
2952
3025
  applyInferences,
2953
3026
  verifyScenarios,
2954
3027
  loadConfig as loadConfig4,
2955
- refreshFromDocs as refreshFromDocs6,
3028
+ refreshFromDocs as refreshFromDocs8,
2956
3029
  syncPhaseToYaml,
2957
3030
  transaction
2958
3031
  } from "@arcbridge/core";
@@ -2961,17 +3034,17 @@ function registerCompletePhase(server, ctx) {
2961
3034
  "arcbridge_complete_phase",
2962
3035
  "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
3036
  {
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")
3037
+ target_dir: z26.string().describe("Absolute path to the project directory"),
3038
+ phase_id: z26.string().optional().describe("Phase ID to complete (defaults to current in-progress phase)"),
3039
+ notes: z26.string().optional().describe("Optional notes about this phase completion"),
3040
+ auto_infer: z26.boolean().default(true).describe("Automatically infer task statuses from code state before checking gates"),
3041
+ run_tests: z26.boolean().default(false).describe("Run linked tests for quality scenarios before checking the quality gate")
2969
3042
  },
2970
3043
  async (params) => {
2971
3044
  const start = Date.now();
2972
3045
  const db = ensureDb(ctx, params.target_dir);
2973
3046
  if (!db) return notInitialized();
2974
- refreshFromDocs6(db, params.target_dir);
3047
+ refreshFromDocs8(db, params.target_dir);
2975
3048
  let phase;
2976
3049
  if (params.phase_id) {
2977
3050
  phase = db.prepare("SELECT id, name, phase_number, status, gate_status FROM phases WHERE id = ?").get(params.phase_id);
@@ -3180,18 +3253,18 @@ function registerCompletePhase(server, ctx) {
3180
3253
  }
3181
3254
 
3182
3255
  // src/tools/activate-role.ts
3183
- import { z as z26 } from "zod";
3256
+ import { z as z27 } from "zod";
3184
3257
  import { loadRole, loadRoles } from "@arcbridge/core";
3185
3258
  function registerActivateRole(server, ctx) {
3186
3259
  server.tool(
3187
3260
  "arcbridge_activate_role",
3188
3261
  "Activate an agent role: loads the role's system prompt, required tools, quality focus, and pre-loaded architectural context.",
3189
3262
  {
3190
- target_dir: z26.string().describe("Absolute path to the project directory"),
3191
- role: z26.string().describe(
3263
+ target_dir: z27.string().describe("Absolute path to the project directory"),
3264
+ role: z27.string().describe(
3192
3265
  "Role ID to activate (e.g., 'architect', 'implementer', 'security-reviewer')"
3193
3266
  ),
3194
- building_block: z26.string().optional().describe("Focus on a specific building block (for implementer/code-reviewer roles)")
3267
+ building_block: z27.string().optional().describe("Focus on a specific building block (for implementer/code-reviewer roles)")
3195
3268
  },
3196
3269
  async (params) => {
3197
3270
  const db = ensureDb(ctx, params.target_dir);
@@ -3493,18 +3566,18 @@ function getRoleDefinition(roleId) {
3493
3566
  }
3494
3567
 
3495
3568
  // src/tools/verify-scenarios.ts
3496
- import { z as z27 } from "zod";
3569
+ import { z as z28 } from "zod";
3497
3570
  import { verifyScenarios as verifyScenarios2, loadConfig as loadConfig5 } from "@arcbridge/core";
3498
3571
  function registerVerifyScenarios(server, ctx) {
3499
3572
  server.tool(
3500
3573
  "arcbridge_verify_scenarios",
3501
3574
  "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
3575
  {
3503
- target_dir: z27.string().describe("Absolute path to the project directory"),
3504
- scenario_ids: z27.array(z27.string()).optional().describe(
3576
+ target_dir: z28.string().describe("Absolute path to the project directory"),
3577
+ scenario_ids: z28.array(z28.string()).optional().describe(
3505
3578
  "Specific scenario IDs to verify (e.g., ['SEC-01', 'PERF-01']). If omitted, verifies all automatic scenarios."
3506
3579
  ),
3507
- test_command: z27.string().optional().describe(
3580
+ test_command: z28.string().optional().describe(
3508
3581
  "Override the test command from config (e.g., 'npx jest'). File paths are appended as arguments."
3509
3582
  )
3510
3583
  },
@@ -3571,7 +3644,7 @@ function registerVerifyScenarios(server, ctx) {
3571
3644
  }
3572
3645
 
3573
3646
  // src/tools/run-role-check.ts
3574
- import { z as z28 } from "zod";
3647
+ import { z as z29 } from "zod";
3575
3648
  import {
3576
3649
  loadRole as loadRole2,
3577
3650
  loadRoles as loadRoles2,
@@ -3586,11 +3659,11 @@ function registerRunRoleCheck(server, ctx) {
3586
3659
  "arcbridge_run_role_check",
3587
3660
  "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
3661
  {
3589
- target_dir: z28.string().describe("Absolute path to the project directory"),
3590
- role: z28.string().describe(
3662
+ target_dir: z29.string().describe("Absolute path to the project directory"),
3663
+ role: z29.string().describe(
3591
3664
  "Role ID to run checks for (e.g., 'security-reviewer', 'quality-guardian', 'architect', 'phase-manager', 'code-reviewer')"
3592
3665
  ),
3593
- scope: z28.enum(SCOPE_VALUES).default("current-phase").describe(
3666
+ scope: z29.enum(SCOPE_VALUES).default("current-phase").describe(
3594
3667
  "Scope of analysis: 'last-commit' (recent changes), 'current-phase' (since phase start), 'full-project' (everything)"
3595
3668
  )
3596
3669
  },
@@ -4011,17 +4084,17 @@ function runCustomRoleCheck(db, lines, roleDef) {
4011
4084
  }
4012
4085
 
4013
4086
  // src/tools/update-scenario-status.ts
4014
- import { z as z29 } from "zod";
4087
+ import { z as z30 } from "zod";
4015
4088
  import { syncScenarioToYaml, transaction as transaction2 } from "@arcbridge/core";
4016
4089
  function registerUpdateScenarioStatus(server, ctx) {
4017
4090
  server.tool(
4018
4091
  "arcbridge_update_scenario_status",
4019
4092
  "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
4093
  {
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(
4094
+ target_dir: z30.string().describe("Absolute path to the project directory"),
4095
+ scenario_id: z30.string().describe("Quality scenario ID (e.g., 'SEC-01', 'PERF-01')"),
4096
+ status: z30.enum(["passing", "failing", "untested", "partial"]).describe("New status for the scenario"),
4097
+ linked_tests: z30.array(z30.string()).optional().describe(
4025
4098
  "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
4099
  )
4027
4100
  },
@@ -4102,33 +4175,33 @@ ${invalid.map((p) => ` - ${p}`).join("\n")}`
4102
4175
  }
4103
4176
 
4104
4177
  // src/tools/record-activity.ts
4105
- import { z as z30 } from "zod";
4178
+ import { z as z31 } from "zod";
4106
4179
  import { insertActivity as insertActivity2, getSessionTotals } from "@arcbridge/core";
4107
4180
  function registerRecordActivity(server, ctx) {
4108
4181
  server.tool(
4109
4182
  "arcbridge_record_activity",
4110
4183
  "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
4184
  {
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")
4185
+ target_dir: z31.string().describe("Absolute path to the project directory"),
4186
+ tool_name: z31.string().describe("Name of the tool or action performed (e.g., 'arcbridge_update_task', 'code_edit')"),
4187
+ action: z31.string().optional().describe("Human-readable label (e.g., 'implement login form')"),
4188
+ model: z31.string().optional().describe("Model identifier (e.g., 'claude-sonnet-4-20250514')"),
4189
+ agent_role: z31.string().optional().describe("Active ArcBridge role (e.g., 'implementer')"),
4190
+ task_id: z31.string().optional().describe("Associated task ID"),
4191
+ phase_id: z31.string().optional().describe("Associated phase ID"),
4192
+ input_tokens: z31.number().int().nonnegative().optional().describe("Input/prompt tokens"),
4193
+ output_tokens: z31.number().int().nonnegative().optional().describe("Output/completion tokens"),
4194
+ total_tokens: z31.number().int().nonnegative().optional().describe("Total tokens (auto-computed if input+output given)"),
4195
+ cost_usd: z31.number().nonnegative().optional().describe("Estimated cost in USD"),
4196
+ duration_ms: z31.number().int().nonnegative().optional().describe("Wall-clock duration in ms"),
4197
+ drift_count: z31.number().int().nonnegative().optional().describe("Current drift count"),
4198
+ drift_errors: z31.number().int().nonnegative().optional().describe("Current drift errors"),
4199
+ test_pass_count: z31.number().int().nonnegative().optional().describe("Passing tests"),
4200
+ test_fail_count: z31.number().int().nonnegative().optional().describe("Failing tests"),
4201
+ lint_clean: z31.boolean().optional().describe("Whether lint passes cleanly"),
4202
+ typecheck_clean: z31.boolean().optional().describe("Whether typecheck passes cleanly"),
4203
+ notes: z31.string().optional().describe("Free-form notes"),
4204
+ metadata: z31.record(z31.unknown()).optional().describe("Additional key-value metadata")
4132
4205
  },
4133
4206
  async (params) => {
4134
4207
  const db = ensureDb(ctx, params.target_dir);
@@ -4183,23 +4256,23 @@ function registerRecordActivity(server, ctx) {
4183
4256
  }
4184
4257
 
4185
4258
  // src/tools/get-metrics.ts
4186
- import { z as z31 } from "zod";
4259
+ import { z as z32 } from "zod";
4187
4260
  import { queryMetrics } from "@arcbridge/core";
4188
4261
  function registerGetMetrics(server, ctx) {
4189
4262
  server.tool(
4190
4263
  "arcbridge_get_metrics",
4191
4264
  "Query agent activity metrics \u2014 filter by model, task, phase, or time range. Group by model/task/phase/tool/day for aggregated views.",
4192
4265
  {
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)")
4266
+ target_dir: z32.string().describe("Absolute path to the project directory"),
4267
+ task_id: z32.string().optional().describe("Filter by task ID"),
4268
+ phase_id: z32.string().optional().describe("Filter by phase ID"),
4269
+ model: z32.string().optional().describe("Filter by model name"),
4270
+ agent_role: z32.string().optional().describe("Filter by agent role"),
4271
+ tool_name: z32.string().optional().describe("Filter by tool name"),
4272
+ since: z32.string().optional().describe("ISO 8601 timestamp \u2014 activity after this time"),
4273
+ until: z32.string().optional().describe("ISO 8601 timestamp \u2014 activity before this time"),
4274
+ group_by: z32.enum(["model", "task", "phase", "tool", "day", "none"]).default("none").describe("Group results for aggregation"),
4275
+ limit: z32.number().int().min(1).max(500).default(50).describe("Max rows in detail view (group_by=none)")
4203
4276
  },
4204
4277
  async (params) => {
4205
4278
  const db = ensureDb(ctx, params.target_dir);
@@ -4282,23 +4355,23 @@ function mdCell(val) {
4282
4355
  }
4283
4356
 
4284
4357
  // src/tools/export-metrics.ts
4285
- import { z as z32 } from "zod";
4358
+ import { z as z33 } from "zod";
4286
4359
  import { exportMetrics } from "@arcbridge/core";
4287
4360
  function registerExportMetrics(server, ctx) {
4288
4361
  server.tool(
4289
4362
  "arcbridge_export_metrics",
4290
4363
  "Export agent activity metrics to a file (JSON, CSV, or Markdown) in .arcbridge/metrics/ for git commits or reporting.",
4291
4364
  {
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)")
4365
+ target_dir: z33.string().describe("Absolute path to the project directory"),
4366
+ format: z33.enum(["json", "csv", "markdown"]).default("json").describe("Export format"),
4367
+ task_id: z33.string().optional().describe("Filter by task ID"),
4368
+ phase_id: z33.string().optional().describe("Filter by phase ID"),
4369
+ model: z33.string().optional().describe("Filter by model name"),
4370
+ agent_role: z33.string().optional().describe("Filter by agent role"),
4371
+ tool_name: z33.string().optional().describe("Filter by tool name"),
4372
+ since: z33.string().optional().describe("ISO 8601 \u2014 activity after this time"),
4373
+ until: z33.string().optional().describe("ISO 8601 \u2014 activity before this time"),
4374
+ max_rows: z33.number().int().min(1).default(1e5).describe("Maximum rows to export (default: 100,000)")
4302
4375
  },
4303
4376
  async (params) => {
4304
4377
  const db = ensureDb(ctx, params.target_dir);
@@ -4327,6 +4400,103 @@ You can commit this file to preserve the activity record in git.`
4327
4400
  );
4328
4401
  }
4329
4402
 
4403
+ // src/tools/update-arc42-section.ts
4404
+ import { z as z34 } from "zod";
4405
+ import { join as join4 } from "path";
4406
+ import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
4407
+ function splitFrontmatter(raw) {
4408
+ if (!raw.startsWith("---")) {
4409
+ return { frontmatterBlock: "", body: raw };
4410
+ }
4411
+ const endIndex = raw.indexOf("\n---", 3);
4412
+ if (endIndex < 0) {
4413
+ return { frontmatterBlock: "", body: raw };
4414
+ }
4415
+ const fmEnd = endIndex + 4;
4416
+ return {
4417
+ frontmatterBlock: raw.slice(0, fmEnd),
4418
+ body: raw.slice(fmEnd).replace(/^\n/, "")
4419
+ };
4420
+ }
4421
+ var VALID_SECTIONS = [
4422
+ "01-introduction",
4423
+ "02-constraints",
4424
+ "03-context",
4425
+ "04-solution-strategy",
4426
+ "06-runtime-views",
4427
+ "07-deployment",
4428
+ "08-crosscutting",
4429
+ "11-risks-debt"
4430
+ ];
4431
+ var SECTION_LABELS = {
4432
+ "01-introduction": "Introduction & Goals",
4433
+ "02-constraints": "Architecture Constraints",
4434
+ "03-context": "Context & Scope",
4435
+ "04-solution-strategy": "Solution Strategy",
4436
+ "06-runtime-views": "Runtime Views",
4437
+ "07-deployment": "Deployment View",
4438
+ "08-crosscutting": "Crosscutting Concepts",
4439
+ "11-risks-debt": "Risks & Technical Debt"
4440
+ };
4441
+ function registerUpdateArc42Section(server, ctx) {
4442
+ server.tool(
4443
+ "arcbridge_update_arc42_section",
4444
+ "Read or update an arc42 documentation section. Omit `content` to read the current section. Provide `content` to replace the markdown body (frontmatter is preserved automatically). Use this for sections without dedicated tools: introduction, constraints, context, solution strategy, runtime views, deployment, crosscutting concepts, risks & debt. For building blocks use `arcbridge_get_building_blocks`, for quality scenarios use `arcbridge_get_quality_scenarios`.",
4445
+ {
4446
+ target_dir: z34.string().describe("Absolute path to the project directory"),
4447
+ section: z34.enum(VALID_SECTIONS).describe(
4448
+ "Arc42 section to read or update: " + VALID_SECTIONS.map((s) => `${s} (${SECTION_LABELS[s]})`).join(", ")
4449
+ ),
4450
+ content: z34.string().optional().describe(
4451
+ "New markdown content for the section body. Omit to read the current content. Frontmatter is preserved automatically \u2014 only provide the markdown body."
4452
+ )
4453
+ },
4454
+ async (params) => {
4455
+ const db = ensureDb(ctx, params.target_dir);
4456
+ if (!db) return notInitialized();
4457
+ const filePath = join4(
4458
+ params.target_dir,
4459
+ ".arcbridge",
4460
+ "arc42",
4461
+ `${params.section}.md`
4462
+ );
4463
+ if (!existsSync4(filePath)) {
4464
+ return textResult(
4465
+ `Section file \`${params.section}.md\` not found. Run \`arcbridge_init_project\` first.`
4466
+ );
4467
+ }
4468
+ if (params.content === void 0) {
4469
+ const raw2 = readFileSync2(filePath, "utf-8");
4470
+ const { body } = splitFrontmatter(raw2);
4471
+ const label2 = SECTION_LABELS[params.section];
4472
+ const trimmedBody = body.trim();
4473
+ const startsWithHeading = /^#\s+/.test(trimmedBody);
4474
+ const outputLines = [];
4475
+ if (!startsWithHeading) {
4476
+ outputLines.push(`# ${label2}`, "");
4477
+ }
4478
+ outputLines.push(
4479
+ `**File:** \`.arcbridge/arc42/${params.section}.md\``,
4480
+ "",
4481
+ trimmedBody
4482
+ );
4483
+ return textResult(outputLines.join("\n"));
4484
+ }
4485
+ const raw = readFileSync2(filePath, "utf-8");
4486
+ const { frontmatterBlock } = splitFrontmatter(raw);
4487
+ const updated = frontmatterBlock ? `${frontmatterBlock}
4488
+ ${params.content}
4489
+ ` : `${params.content}
4490
+ `;
4491
+ writeFileSync2(filePath, updated, "utf-8");
4492
+ const label = SECTION_LABELS[params.section];
4493
+ return textResult(
4494
+ `Updated **${label}** (\`${params.section}.md\`). Frontmatter preserved.`
4495
+ );
4496
+ }
4497
+ );
4498
+ }
4499
+
4330
4500
  // src/server.ts
4331
4501
  var require2 = createRequire(import.meta.url);
4332
4502
  var { version } = require2("../package.json");
@@ -4348,6 +4518,7 @@ function createArcBridgeServer() {
4348
4518
  registerCreateTask(server, ctx);
4349
4519
  registerDeleteTask(server, ctx);
4350
4520
  registerCreatePhase(server, ctx);
4521
+ registerDeletePhase(server, ctx);
4351
4522
  registerReindex(server, ctx);
4352
4523
  registerSearchSymbols(server, ctx);
4353
4524
  registerGetSymbol(server, ctx);
@@ -4365,6 +4536,7 @@ function createArcBridgeServer() {
4365
4536
  registerVerifyScenarios(server, ctx);
4366
4537
  registerUpdateScenarioStatus(server, ctx);
4367
4538
  registerRunRoleCheck(server, ctx);
4539
+ registerUpdateArc42Section(server, ctx);
4368
4540
  registerRecordActivity(server, ctx);
4369
4541
  registerGetMetrics(server, ctx);
4370
4542
  registerExportMetrics(server, ctx);