@arcbridge/mcp-server 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -40,8 +40,8 @@ function registerInitProject(server, ctx) {
40
40
  "Initialize ArcBridge in a project directory. Creates .arcbridge/ with arc42 documentation, phase plan, agent roles, SQLite database, and platform-specific configs.",
41
41
  {
42
42
  name: z.string().min(1).describe("Project name"),
43
- template: z.enum(["nextjs-app-router", "react-vite", "api-service", "dotnet-webapi"]).default("nextjs-app-router").describe(
44
- "Project template: nextjs-app-router (Next.js with App Router, SSR/SSG), react-vite (React SPA with Vite, client-only), api-service (Node.js API with Express/Fastify/Hono), dotnet-webapi (ASP.NET Core Web API, C#)"
43
+ template: z.enum(["nextjs-app-router", "react-vite", "api-service", "dotnet-webapi", "unity-game"]).default("nextjs-app-router").describe(
44
+ "Project template: nextjs-app-router (Next.js with App Router, SSR/SSG), react-vite (React SPA with Vite, client-only), api-service (Node.js API with Express/Fastify/Hono), dotnet-webapi (ASP.NET Core Web API, C#), unity-game (Unity game project, C#, code-heavy)"
45
45
  ),
46
46
  features: z.array(z.enum(["auth", "database", "api"])).default([]).describe("Features to scaffold"),
47
47
  quality_priorities: z.array(z.string()).default(["security", "performance", "accessibility", "maintainability"]).describe("Quality priorities in order"),
@@ -1104,16 +1104,80 @@ function registerDeleteTask(server, ctx) {
1104
1104
  );
1105
1105
  }
1106
1106
 
1107
- // src/tools/get-relevant-adrs.ts
1107
+ // src/tools/create-phase.ts
1108
1108
  import { z as z11 } from "zod";
1109
+ import { addPhaseToYaml, refreshFromDocs as refreshFromDocs4 } from "@arcbridge/core";
1110
+ function registerCreatePhase(server, ctx) {
1111
+ server.tool(
1112
+ "arcbridge_create_phase",
1113
+ "Create a new phase in the project plan. Use this to add phases beyond the initial 4-phase template when the project scope requires it.",
1114
+ {
1115
+ target_dir: z11.string().describe("Absolute path to the project directory"),
1116
+ name: z11.string().min(1).describe("Phase name (e.g., 'Integrations', 'Performance Optimization')"),
1117
+ description: z11.string().min(1).describe("What this phase covers"),
1118
+ phase_number: z11.number().int().min(0).optional().describe("Phase number (default: next after highest existing phase)"),
1119
+ gate_requirements: z11.array(z11.string()).default([]).describe("Requirements that must be met to complete this phase")
1120
+ },
1121
+ async (params) => {
1122
+ const db = ensureDb(ctx, params.target_dir);
1123
+ if (!db) return notInitialized();
1124
+ refreshFromDocs4(db, params.target_dir);
1125
+ const maxPhase = db.prepare("SELECT MAX(phase_number) as max FROM phases").get();
1126
+ const phaseNumber = params.phase_number ?? (maxPhase.max ?? -1) + 1;
1127
+ const existing = db.prepare("SELECT id FROM phases WHERE phase_number = ?").get(phaseNumber);
1128
+ if (existing) {
1129
+ return textResult(
1130
+ `Phase number ${phaseNumber} already exists (\`${existing.id}\`). Choose a different number or omit to auto-assign.`
1131
+ );
1132
+ }
1133
+ const slug = params.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 30) || "unnamed";
1134
+ const phaseId = `phase-${phaseNumber}-${slug}`;
1135
+ const yamlResult = addPhaseToYaml(params.target_dir, {
1136
+ id: phaseId,
1137
+ name: params.name,
1138
+ phase_number: phaseNumber,
1139
+ description: params.description,
1140
+ gate_requirements: params.gate_requirements
1141
+ });
1142
+ if (!yamlResult.success) {
1143
+ return textResult(
1144
+ `Failed to create phase: ${yamlResult.warning ?? "YAML update failed"}`
1145
+ );
1146
+ }
1147
+ refreshFromDocs4(db, params.target_dir);
1148
+ const lines = [
1149
+ `Phase created: **${phaseId}**`,
1150
+ "",
1151
+ `**Name:** ${params.name}`,
1152
+ `**Number:** ${phaseNumber}`,
1153
+ `**Status:** planned`,
1154
+ `**Description:** ${params.description}`
1155
+ ];
1156
+ if (params.gate_requirements.length > 0) {
1157
+ lines.push("", "**Gate requirements:**");
1158
+ for (const r of params.gate_requirements) {
1159
+ lines.push(`- [ ] ${r}`);
1160
+ }
1161
+ }
1162
+ lines.push(
1163
+ "",
1164
+ `Use \`arcbridge_create_task\` with phase ID \`${phaseId}\` to add tasks.`
1165
+ );
1166
+ return textResult(lines.join("\n"));
1167
+ }
1168
+ );
1169
+ }
1170
+
1171
+ // src/tools/get-relevant-adrs.ts
1172
+ import { z as z12 } from "zod";
1109
1173
  function registerGetRelevantAdrs(server, ctx) {
1110
1174
  server.tool(
1111
1175
  "arcbridge_get_relevant_adrs",
1112
1176
  "Get architectural decision records (ADRs) relevant to a specific file path or building block.",
1113
1177
  {
1114
- target_dir: z11.string().describe("Absolute path to the project directory"),
1115
- file_path: z11.string().optional().describe("File path to find relevant ADRs for"),
1116
- building_block: z11.string().optional().describe("Building block ID to find relevant ADRs for")
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")
1117
1181
  },
1118
1182
  async (params) => {
1119
1183
  const db = ensureDb(ctx, params.target_dir);
@@ -1197,24 +1261,24 @@ function formatAdrs(adrs, title) {
1197
1261
  }
1198
1262
 
1199
1263
  // src/tools/reindex.ts
1200
- import { z as z12 } from "zod";
1201
- import { indexProject as indexProject2, refreshFromDocs as refreshFromDocs4 } from "@arcbridge/core";
1264
+ import { z as z13 } from "zod";
1265
+ import { indexProject as indexProject2, refreshFromDocs as refreshFromDocs5 } from "@arcbridge/core";
1202
1266
  function registerReindex(server, ctx) {
1203
1267
  server.tool(
1204
1268
  "arcbridge_reindex",
1205
1269
  "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.",
1206
1270
  {
1207
- target_dir: z12.string().describe("Absolute path to the project directory"),
1208
- tsconfig_path: z12.string().optional().describe("Override tsconfig.json path (default: auto-detect). Only used for TypeScript projects."),
1209
- service: z12.string().optional().describe("Service name for monorepo projects (default: 'main')"),
1210
- language: z12.enum(["typescript", "csharp", "auto"]).optional().describe("Project language. 'auto' detects from project files (default: 'auto')")
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')")
1211
1275
  },
1212
1276
  async (params) => {
1213
1277
  const start = Date.now();
1214
1278
  const db = ensureDb(ctx, params.target_dir);
1215
1279
  if (!db) return notInitialized();
1216
1280
  try {
1217
- const docWarnings = refreshFromDocs4(db, params.target_dir);
1281
+ const docWarnings = refreshFromDocs5(db, params.target_dir);
1218
1282
  const result = await indexProject2(db, {
1219
1283
  projectRoot: params.target_dir,
1220
1284
  tsconfigPath: params.tsconfig_path,
@@ -1253,16 +1317,16 @@ function registerReindex(server, ctx) {
1253
1317
  }
1254
1318
 
1255
1319
  // src/tools/search-symbols.ts
1256
- import { z as z13 } from "zod";
1320
+ import { z as z14 } from "zod";
1257
1321
  function registerSearchSymbols(server, ctx) {
1258
1322
  server.tool(
1259
1323
  "arcbridge_search_symbols",
1260
1324
  "Search code symbols by name, kind, file path, or building block. Supports TypeScript and C#. Returns matching symbols with type signatures.",
1261
1325
  {
1262
- target_dir: z13.string().describe("Absolute path to the project directory"),
1263
- query: z13.string().optional().describe("Search term to match against symbol names"),
1264
- service: z13.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services."),
1265
- kind: z13.enum([
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([
1266
1330
  "function",
1267
1331
  "class",
1268
1332
  "type",
@@ -1274,10 +1338,10 @@ function registerSearchSymbols(server, ctx) {
1274
1338
  "hook",
1275
1339
  "context"
1276
1340
  ]).optional().describe("Filter by symbol kind"),
1277
- file_path: z13.string().optional().describe("Filter by file path (prefix match)"),
1278
- is_exported: z13.boolean().optional().describe("Filter by export status"),
1279
- building_block: z13.string().optional().describe("Filter by building block ID (matches against code_paths)"),
1280
- limit: z13.number().int().min(1).max(200).default(50).describe("Maximum results to return (default: 50)")
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)")
1281
1345
  },
1282
1346
  async (params) => {
1283
1347
  const db = ensureDb(ctx, params.target_dir);
@@ -1364,7 +1428,7 @@ function registerSearchSymbols(server, ctx) {
1364
1428
  }
1365
1429
 
1366
1430
  // src/tools/get-symbol.ts
1367
- import { z as z14 } from "zod";
1431
+ import { z as z15 } from "zod";
1368
1432
  import { readFileSync, existsSync as existsSync3 } from "fs";
1369
1433
  import { join as join3 } from "path";
1370
1434
  function registerGetSymbol(server, ctx) {
@@ -1372,11 +1436,11 @@ function registerGetSymbol(server, ctx) {
1372
1436
  "arcbridge_get_symbol",
1373
1437
  "Get detailed information about a specific TypeScript symbol including its source code, type signature, and relationships.",
1374
1438
  {
1375
- target_dir: z14.string().describe("Absolute path to the project directory"),
1376
- symbol_id: z14.string().describe(
1439
+ target_dir: z15.string().describe("Absolute path to the project directory"),
1440
+ symbol_id: z15.string().describe(
1377
1441
  "Symbol ID (e.g. 'src/utils.ts::formatName#function')"
1378
1442
  ),
1379
- include_source: z14.boolean().default(true).describe("Include source code snippet (default: true)")
1443
+ include_source: z15.boolean().default(true).describe("Include source code snippet (default: true)")
1380
1444
  },
1381
1445
  async (params) => {
1382
1446
  const db = ensureDb(ctx, params.target_dir);
@@ -1474,21 +1538,21 @@ Use \`arcbridge_search_symbols\` to find symbols by name.`
1474
1538
  }
1475
1539
 
1476
1540
  // src/tools/get-dependency-graph.ts
1477
- import { z as z15 } from "zod";
1541
+ import { z as z16 } from "zod";
1478
1542
  function registerGetDependencyGraph(server, ctx) {
1479
1543
  server.tool(
1480
1544
  "arcbridge_get_dependency_graph",
1481
1545
  "Get the dependency graph for a module or file. Shows imports, calls, type usage, and inheritance relationships between symbols.",
1482
1546
  {
1483
- target_dir: z15.string().describe("Absolute path to the project directory"),
1484
- module: z15.string().describe(
1547
+ target_dir: z16.string().describe("Absolute path to the project directory"),
1548
+ module: z16.string().describe(
1485
1549
  "Module path relative to project root (e.g. 'src/lib/auth')"
1486
1550
  ),
1487
- direction: z15.enum(["dependencies", "dependents", "both"]).default("both").describe(
1551
+ direction: z16.enum(["dependencies", "dependents", "both"]).default("both").describe(
1488
1552
  "Graph direction: 'dependencies' (what this module uses), 'dependents' (what uses this module), or 'both'"
1489
1553
  ),
1490
- depth: z15.number().int().min(1).max(5).default(1).describe("How many levels to traverse (default: 1, max: 5)"),
1491
- service: z15.string().optional().describe("Filter by service name (for multi-project solutions). Omit to search all services.")
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.")
1492
1556
  },
1493
1557
  async (params) => {
1494
1558
  const maybeDb = ensureDb(ctx, params.target_dir);
@@ -1635,16 +1699,16 @@ function formatEdges(edges, modulePath, direction) {
1635
1699
  }
1636
1700
 
1637
1701
  // src/tools/get-component-graph.ts
1638
- import { z as z16 } from "zod";
1702
+ import { z as z17 } from "zod";
1639
1703
  function registerGetComponentGraph(server, ctx) {
1640
1704
  server.tool(
1641
1705
  "arcbridge_get_component_graph",
1642
1706
  "Get the React component graph: component hierarchy, props, state, context usage, and server/client boundaries.",
1643
1707
  {
1644
- target_dir: z16.string().describe("Absolute path to the project directory"),
1645
- file_path: z16.string().optional().describe("Filter to components in a specific file or directory prefix"),
1646
- client_only: z16.boolean().optional().describe("Only show client components ('use client')"),
1647
- with_state: z16.boolean().optional().describe("Only show components that use state (useState/useReducer)")
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)")
1648
1712
  },
1649
1713
  async (params) => {
1650
1714
  const db = ensureDb(ctx, params.target_dir);
@@ -1748,16 +1812,16 @@ function registerGetComponentGraph(server, ctx) {
1748
1812
  }
1749
1813
 
1750
1814
  // src/tools/get-route-map.ts
1751
- import { z as z17 } from "zod";
1815
+ import { z as z18 } from "zod";
1752
1816
  function registerGetRouteMap(server, ctx) {
1753
1817
  server.tool(
1754
1818
  "arcbridge_get_route_map",
1755
1819
  "Get the route map: pages, layouts, API routes, and their hierarchy. Works with Next.js, ASP.NET controllers, and minimal APIs.",
1756
1820
  {
1757
- target_dir: z17.string().describe("Absolute path to the project directory"),
1758
- kind: z17.enum(["page", "layout", "loading", "error", "not-found", "api-route", "middleware"]).optional().describe("Filter by route kind"),
1759
- route_prefix: z17.string().optional().describe("Filter by route path prefix (e.g. '/dashboard' or '/api/orders')"),
1760
- service: z17.string().optional().describe("Filter by service name (for multi-project solutions). Omit to show all services.")
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.")
1761
1825
  },
1762
1826
  async (params) => {
1763
1827
  const db = ensureDb(ctx, params.target_dir);
@@ -1833,13 +1897,13 @@ function registerGetRouteMap(server, ctx) {
1833
1897
  }
1834
1898
 
1835
1899
  // src/tools/get-boundary-analysis.ts
1836
- import { z as z18 } from "zod";
1900
+ import { z as z19 } from "zod";
1837
1901
  function registerGetBoundaryAnalysis(server, ctx) {
1838
1902
  server.tool(
1839
1903
  "arcbridge_get_boundary_analysis",
1840
1904
  "Analyze server/client boundaries in a Next.js project. Identifies client components, server components, server actions, and potential boundary violations.",
1841
1905
  {
1842
- target_dir: z18.string().describe("Absolute path to the project directory")
1906
+ target_dir: z19.string().describe("Absolute path to the project directory")
1843
1907
  },
1844
1908
  async (params) => {
1845
1909
  const db = ensureDb(ctx, params.target_dir);
@@ -1943,15 +2007,15 @@ function registerGetBoundaryAnalysis(server, ctx) {
1943
2007
  }
1944
2008
 
1945
2009
  // src/tools/check-drift.ts
1946
- import { z as z19 } from "zod";
2010
+ import { z as z20 } from "zod";
1947
2011
  import { detectDrift, writeDriftLog } from "@arcbridge/core";
1948
2012
  function registerCheckDrift(server, ctx) {
1949
2013
  server.tool(
1950
2014
  "arcbridge_check_drift",
1951
2015
  "Detect architecture drift: undocumented modules, missing code paths, cross-block dependency violations, and stale ADR references.",
1952
2016
  {
1953
- target_dir: z19.string().describe("Absolute path to the project directory"),
1954
- persist: z19.boolean().default(true).describe("Write findings to drift_log table (default: true)")
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)")
1955
2019
  },
1956
2020
  async (params) => {
1957
2021
  const start = Date.now();
@@ -2023,16 +2087,16 @@ function registerCheckDrift(server, ctx) {
2023
2087
  }
2024
2088
 
2025
2089
  // src/tools/get-guidance.ts
2026
- import { z as z20 } from "zod";
2090
+ import { z as z21 } from "zod";
2027
2091
  import { loadConfig as loadConfig3 } from "@arcbridge/core";
2028
2092
  function registerGetGuidance(server, ctx) {
2029
2093
  server.tool(
2030
2094
  "arcbridge_get_guidance",
2031
2095
  "Get context-aware architectural guidance for a code change. Surfaces relevant quality scenarios, patterns, constraints, and questions to consider.",
2032
2096
  {
2033
- target_dir: z20.string().describe("Absolute path to the project directory"),
2034
- file_path: z20.string().optional().describe("File path you're working on (to determine building block and context)"),
2035
- action: z20.enum([
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([
2036
2100
  "adding-component",
2037
2101
  "adding-api-route",
2038
2102
  "adding-hook",
@@ -2230,14 +2294,14 @@ function getActionGuidance(action, projectType) {
2230
2294
  }
2231
2295
 
2232
2296
  // src/tools/get-open-questions.ts
2233
- import { z as z21 } from "zod";
2297
+ import { z as z22 } from "zod";
2234
2298
  function registerGetOpenQuestions(server, ctx) {
2235
2299
  server.tool(
2236
2300
  "arcbridge_get_open_questions",
2237
2301
  "Surface architectural gaps: untested quality scenarios, building blocks without boundaries, unresolved drift, and tasks missing acceptance criteria.",
2238
2302
  {
2239
- target_dir: z21.string().describe("Absolute path to the project directory"),
2240
- scope: z21.string().optional().describe("Focus scope: 'current-phase', 'building-block:<id>', or omit for project-wide")
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")
2241
2305
  },
2242
2306
  async (params) => {
2243
2307
  const db = ensureDb(ctx, params.target_dir);
@@ -2347,7 +2411,7 @@ function registerGetOpenQuestions(server, ctx) {
2347
2411
  }
2348
2412
 
2349
2413
  // src/tools/propose-arc42-update.ts
2350
- import { z as z22 } from "zod";
2414
+ import { z as z23 } from "zod";
2351
2415
  import {
2352
2416
  resolveRef,
2353
2417
  getChangedFiles,
@@ -2359,9 +2423,9 @@ function registerProposeArc42Update(server, ctx) {
2359
2423
  "arcbridge_propose_arc42_update",
2360
2424
  "Analyze code changes since a reference point and generate specific, actionable proposals for updating arc42 documentation.",
2361
2425
  {
2362
- target_dir: z22.string().describe("Absolute path to the project directory"),
2363
- changes_since: z22.string().default("last-sync").describe("Reference point: 'last-commit', 'last-sync', 'last-phase', or a git ref"),
2364
- update_sync_point: z22.boolean().default(false).describe("Update the stored sync commit to HEAD after generating proposals")
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")
2365
2429
  },
2366
2430
  async (params) => {
2367
2431
  const db = ensureDb(ctx, params.target_dir);
@@ -2549,7 +2613,7 @@ function findCrossBlockConsumers(db, symbolId, sourceBlockId, blocks) {
2549
2613
  }
2550
2614
 
2551
2615
  // src/tools/get-practice-review.ts
2552
- import { z as z23 } from "zod";
2616
+ import { z as z24 } from "zod";
2553
2617
  import {
2554
2618
  resolveRef as resolveRef2,
2555
2619
  getChangedFiles as getChangedFiles2,
@@ -2561,8 +2625,8 @@ function registerGetPracticeReview(server, ctx) {
2561
2625
  "arcbridge_get_practice_review",
2562
2626
  "Structured, practice-aware review of recent code changes across 5 dimensions: Architecture, Security, Testing, Documentation, and Complexity.",
2563
2627
  {
2564
- target_dir: z23.string().describe("Absolute path to the project directory"),
2565
- since: z23.string().default("last-commit").describe("Reference point: 'last-commit', 'last-session', or 'last-phase'")
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'")
2566
2630
  },
2567
2631
  async (params) => {
2568
2632
  const db = ensureDb(ctx, params.target_dir);
@@ -2878,7 +2942,7 @@ function reviewComplexity(db, changedFiles, findings) {
2878
2942
  }
2879
2943
 
2880
2944
  // src/tools/complete-phase.ts
2881
- import { z as z24 } from "zod";
2945
+ import { z as z25 } from "zod";
2882
2946
  import {
2883
2947
  detectDrift as detectDrift3,
2884
2948
  writeDriftLog as writeDriftLog2,
@@ -2888,7 +2952,7 @@ import {
2888
2952
  applyInferences,
2889
2953
  verifyScenarios,
2890
2954
  loadConfig as loadConfig4,
2891
- refreshFromDocs as refreshFromDocs5,
2955
+ refreshFromDocs as refreshFromDocs6,
2892
2956
  syncPhaseToYaml,
2893
2957
  transaction
2894
2958
  } from "@arcbridge/core";
@@ -2897,17 +2961,17 @@ function registerCompletePhase(server, ctx) {
2897
2961
  "arcbridge_complete_phase",
2898
2962
  "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.",
2899
2963
  {
2900
- target_dir: z24.string().describe("Absolute path to the project directory"),
2901
- phase_id: z24.string().optional().describe("Phase ID to complete (defaults to current in-progress phase)"),
2902
- notes: z24.string().optional().describe("Optional notes about this phase completion"),
2903
- auto_infer: z24.boolean().default(true).describe("Automatically infer task statuses from code state before checking gates"),
2904
- run_tests: z24.boolean().default(false).describe("Run linked tests for quality scenarios before checking the quality gate")
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")
2905
2969
  },
2906
2970
  async (params) => {
2907
2971
  const start = Date.now();
2908
2972
  const db = ensureDb(ctx, params.target_dir);
2909
2973
  if (!db) return notInitialized();
2910
- refreshFromDocs5(db, params.target_dir);
2974
+ refreshFromDocs6(db, params.target_dir);
2911
2975
  let phase;
2912
2976
  if (params.phase_id) {
2913
2977
  phase = db.prepare("SELECT id, name, phase_number, status, gate_status FROM phases WHERE id = ?").get(params.phase_id);
@@ -3116,18 +3180,18 @@ function registerCompletePhase(server, ctx) {
3116
3180
  }
3117
3181
 
3118
3182
  // src/tools/activate-role.ts
3119
- import { z as z25 } from "zod";
3183
+ import { z as z26 } from "zod";
3120
3184
  import { loadRole, loadRoles } from "@arcbridge/core";
3121
3185
  function registerActivateRole(server, ctx) {
3122
3186
  server.tool(
3123
3187
  "arcbridge_activate_role",
3124
3188
  "Activate an agent role: loads the role's system prompt, required tools, quality focus, and pre-loaded architectural context.",
3125
3189
  {
3126
- target_dir: z25.string().describe("Absolute path to the project directory"),
3127
- role: z25.string().describe(
3190
+ target_dir: z26.string().describe("Absolute path to the project directory"),
3191
+ role: z26.string().describe(
3128
3192
  "Role ID to activate (e.g., 'architect', 'implementer', 'security-reviewer')"
3129
3193
  ),
3130
- building_block: z25.string().optional().describe("Focus on a specific building block (for implementer/code-reviewer roles)")
3194
+ building_block: z26.string().optional().describe("Focus on a specific building block (for implementer/code-reviewer roles)")
3131
3195
  },
3132
3196
  async (params) => {
3133
3197
  const db = ensureDb(ctx, params.target_dir);
@@ -3429,18 +3493,18 @@ function getRoleDefinition(roleId) {
3429
3493
  }
3430
3494
 
3431
3495
  // src/tools/verify-scenarios.ts
3432
- import { z as z26 } from "zod";
3496
+ import { z as z27 } from "zod";
3433
3497
  import { verifyScenarios as verifyScenarios2, loadConfig as loadConfig5 } from "@arcbridge/core";
3434
3498
  function registerVerifyScenarios(server, ctx) {
3435
3499
  server.tool(
3436
3500
  "arcbridge_verify_scenarios",
3437
3501
  "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.",
3438
3502
  {
3439
- target_dir: z26.string().describe("Absolute path to the project directory"),
3440
- scenario_ids: z26.array(z26.string()).optional().describe(
3503
+ target_dir: z27.string().describe("Absolute path to the project directory"),
3504
+ scenario_ids: z27.array(z27.string()).optional().describe(
3441
3505
  "Specific scenario IDs to verify (e.g., ['SEC-01', 'PERF-01']). If omitted, verifies all automatic scenarios."
3442
3506
  ),
3443
- test_command: z26.string().optional().describe(
3507
+ test_command: z27.string().optional().describe(
3444
3508
  "Override the test command from config (e.g., 'npx jest'). File paths are appended as arguments."
3445
3509
  )
3446
3510
  },
@@ -3507,7 +3571,7 @@ function registerVerifyScenarios(server, ctx) {
3507
3571
  }
3508
3572
 
3509
3573
  // src/tools/run-role-check.ts
3510
- import { z as z27 } from "zod";
3574
+ import { z as z28 } from "zod";
3511
3575
  import {
3512
3576
  loadRole as loadRole2,
3513
3577
  loadRoles as loadRoles2,
@@ -3522,11 +3586,11 @@ function registerRunRoleCheck(server, ctx) {
3522
3586
  "arcbridge_run_role_check",
3523
3587
  "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.",
3524
3588
  {
3525
- target_dir: z27.string().describe("Absolute path to the project directory"),
3526
- role: z27.string().describe(
3589
+ target_dir: z28.string().describe("Absolute path to the project directory"),
3590
+ role: z28.string().describe(
3527
3591
  "Role ID to run checks for (e.g., 'security-reviewer', 'quality-guardian', 'architect', 'phase-manager', 'code-reviewer')"
3528
3592
  ),
3529
- scope: z27.enum(SCOPE_VALUES).default("current-phase").describe(
3593
+ scope: z28.enum(SCOPE_VALUES).default("current-phase").describe(
3530
3594
  "Scope of analysis: 'last-commit' (recent changes), 'current-phase' (since phase start), 'full-project' (everything)"
3531
3595
  )
3532
3596
  },
@@ -3947,17 +4011,17 @@ function runCustomRoleCheck(db, lines, roleDef) {
3947
4011
  }
3948
4012
 
3949
4013
  // src/tools/update-scenario-status.ts
3950
- import { z as z28 } from "zod";
4014
+ import { z as z29 } from "zod";
3951
4015
  import { syncScenarioToYaml, transaction as transaction2 } from "@arcbridge/core";
3952
4016
  function registerUpdateScenarioStatus(server, ctx) {
3953
4017
  server.tool(
3954
4018
  "arcbridge_update_scenario_status",
3955
4019
  "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.",
3956
4020
  {
3957
- target_dir: z28.string().describe("Absolute path to the project directory"),
3958
- scenario_id: z28.string().describe("Quality scenario ID (e.g., 'SEC-01', 'PERF-01')"),
3959
- status: z28.enum(["passing", "failing", "untested", "partial"]).describe("New status for the scenario"),
3960
- linked_tests: z28.array(z28.string()).optional().describe(
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(
3961
4025
  "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'."
3962
4026
  )
3963
4027
  },
@@ -4038,33 +4102,33 @@ ${invalid.map((p) => ` - ${p}`).join("\n")}`
4038
4102
  }
4039
4103
 
4040
4104
  // src/tools/record-activity.ts
4041
- import { z as z29 } from "zod";
4105
+ import { z as z30 } from "zod";
4042
4106
  import { insertActivity as insertActivity2, getSessionTotals } from "@arcbridge/core";
4043
4107
  function registerRecordActivity(server, ctx) {
4044
4108
  server.tool(
4045
4109
  "arcbridge_record_activity",
4046
4110
  "Record agent activity \u2014 model, tokens, cost, duration, and optional quality snapshot. Use this to track what work was done and measure agent performance.",
4047
4111
  {
4048
- target_dir: z29.string().describe("Absolute path to the project directory"),
4049
- tool_name: z29.string().describe("Name of the tool or action performed (e.g., 'arcbridge_update_task', 'code_edit')"),
4050
- action: z29.string().optional().describe("Human-readable label (e.g., 'implement login form')"),
4051
- model: z29.string().optional().describe("Model identifier (e.g., 'claude-sonnet-4-20250514')"),
4052
- agent_role: z29.string().optional().describe("Active ArcBridge role (e.g., 'implementer')"),
4053
- task_id: z29.string().optional().describe("Associated task ID"),
4054
- phase_id: z29.string().optional().describe("Associated phase ID"),
4055
- input_tokens: z29.number().int().nonnegative().optional().describe("Input/prompt tokens"),
4056
- output_tokens: z29.number().int().nonnegative().optional().describe("Output/completion tokens"),
4057
- total_tokens: z29.number().int().nonnegative().optional().describe("Total tokens (auto-computed if input+output given)"),
4058
- cost_usd: z29.number().nonnegative().optional().describe("Estimated cost in USD"),
4059
- duration_ms: z29.number().int().nonnegative().optional().describe("Wall-clock duration in ms"),
4060
- drift_count: z29.number().int().nonnegative().optional().describe("Current drift count"),
4061
- drift_errors: z29.number().int().nonnegative().optional().describe("Current drift errors"),
4062
- test_pass_count: z29.number().int().nonnegative().optional().describe("Passing tests"),
4063
- test_fail_count: z29.number().int().nonnegative().optional().describe("Failing tests"),
4064
- lint_clean: z29.boolean().optional().describe("Whether lint passes cleanly"),
4065
- typecheck_clean: z29.boolean().optional().describe("Whether typecheck passes cleanly"),
4066
- notes: z29.string().optional().describe("Free-form notes"),
4067
- metadata: z29.record(z29.unknown()).optional().describe("Additional key-value metadata")
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")
4068
4132
  },
4069
4133
  async (params) => {
4070
4134
  const db = ensureDb(ctx, params.target_dir);
@@ -4119,23 +4183,23 @@ function registerRecordActivity(server, ctx) {
4119
4183
  }
4120
4184
 
4121
4185
  // src/tools/get-metrics.ts
4122
- import { z as z30 } from "zod";
4186
+ import { z as z31 } from "zod";
4123
4187
  import { queryMetrics } from "@arcbridge/core";
4124
4188
  function registerGetMetrics(server, ctx) {
4125
4189
  server.tool(
4126
4190
  "arcbridge_get_metrics",
4127
4191
  "Query agent activity metrics \u2014 filter by model, task, phase, or time range. Group by model/task/phase/tool/day for aggregated views.",
4128
4192
  {
4129
- target_dir: z30.string().describe("Absolute path to the project directory"),
4130
- task_id: z30.string().optional().describe("Filter by task ID"),
4131
- phase_id: z30.string().optional().describe("Filter by phase ID"),
4132
- model: z30.string().optional().describe("Filter by model name"),
4133
- agent_role: z30.string().optional().describe("Filter by agent role"),
4134
- tool_name: z30.string().optional().describe("Filter by tool name"),
4135
- since: z30.string().optional().describe("ISO 8601 timestamp \u2014 activity after this time"),
4136
- until: z30.string().optional().describe("ISO 8601 timestamp \u2014 activity before this time"),
4137
- group_by: z30.enum(["model", "task", "phase", "tool", "day", "none"]).default("none").describe("Group results for aggregation"),
4138
- limit: z30.number().int().min(1).max(500).default(50).describe("Max rows in detail view (group_by=none)")
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)")
4139
4203
  },
4140
4204
  async (params) => {
4141
4205
  const db = ensureDb(ctx, params.target_dir);
@@ -4218,23 +4282,23 @@ function mdCell(val) {
4218
4282
  }
4219
4283
 
4220
4284
  // src/tools/export-metrics.ts
4221
- import { z as z31 } from "zod";
4285
+ import { z as z32 } from "zod";
4222
4286
  import { exportMetrics } from "@arcbridge/core";
4223
4287
  function registerExportMetrics(server, ctx) {
4224
4288
  server.tool(
4225
4289
  "arcbridge_export_metrics",
4226
4290
  "Export agent activity metrics to a file (JSON, CSV, or Markdown) in .arcbridge/metrics/ for git commits or reporting.",
4227
4291
  {
4228
- target_dir: z31.string().describe("Absolute path to the project directory"),
4229
- format: z31.enum(["json", "csv", "markdown"]).default("json").describe("Export format"),
4230
- task_id: z31.string().optional().describe("Filter by task ID"),
4231
- phase_id: z31.string().optional().describe("Filter by phase ID"),
4232
- model: z31.string().optional().describe("Filter by model name"),
4233
- agent_role: z31.string().optional().describe("Filter by agent role"),
4234
- tool_name: z31.string().optional().describe("Filter by tool name"),
4235
- since: z31.string().optional().describe("ISO 8601 \u2014 activity after this time"),
4236
- until: z31.string().optional().describe("ISO 8601 \u2014 activity before this time"),
4237
- max_rows: z31.number().int().min(1).default(1e5).describe("Maximum rows to export (default: 100,000)")
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)")
4238
4302
  },
4239
4303
  async (params) => {
4240
4304
  const db = ensureDb(ctx, params.target_dir);
@@ -4283,6 +4347,7 @@ function createArcBridgeServer() {
4283
4347
  registerUpdateTask(server, ctx);
4284
4348
  registerCreateTask(server, ctx);
4285
4349
  registerDeleteTask(server, ctx);
4350
+ registerCreatePhase(server, ctx);
4286
4351
  registerReindex(server, ctx);
4287
4352
  registerSearchSymbols(server, ctx);
4288
4353
  registerGetSymbol(server, ctx);