@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/README.md +14 -4
- package/dist/index.js +326 -154
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|
|
192
|
+
"## Next Steps \u2014 TAILOR FIRST, BUILD SECOND",
|
|
193
193
|
"",
|
|
194
|
-
"**Do not start implementing yet.**
|
|
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. **
|
|
199
|
-
"4. **
|
|
200
|
-
"5. **
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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("
|
|
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
|
|
1089
|
-
if (
|
|
1090
|
-
return textResult(
|
|
1091
|
-
|
|
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
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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:
|
|
1179
|
-
file_path:
|
|
1180
|
-
building_block:
|
|
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
|
|
1265
|
-
import { indexProject as indexProject2, refreshFromDocs as
|
|
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:
|
|
1272
|
-
tsconfig_path:
|
|
1273
|
-
service:
|
|
1274
|
-
language:
|
|
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 =
|
|
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
|
|
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:
|
|
1327
|
-
query:
|
|
1328
|
-
service:
|
|
1329
|
-
kind:
|
|
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:
|
|
1342
|
-
is_exported:
|
|
1343
|
-
building_block:
|
|
1344
|
-
limit:
|
|
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
|
|
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:
|
|
1440
|
-
symbol_id:
|
|
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:
|
|
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
|
|
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:
|
|
1548
|
-
module:
|
|
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:
|
|
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:
|
|
1555
|
-
service:
|
|
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
|
|
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:
|
|
1709
|
-
file_path:
|
|
1710
|
-
client_only:
|
|
1711
|
-
with_state:
|
|
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
|
|
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:
|
|
1822
|
-
kind:
|
|
1823
|
-
route_prefix:
|
|
1824
|
-
service:
|
|
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
|
|
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:
|
|
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
|
|
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:
|
|
2018
|
-
persist:
|
|
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
|
|
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:
|
|
2098
|
-
file_path:
|
|
2099
|
-
action:
|
|
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
|
|
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:
|
|
2304
|
-
scope:
|
|
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
|
|
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:
|
|
2427
|
-
changes_since:
|
|
2428
|
-
update_sync_point:
|
|
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
|
|
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:
|
|
2629
|
-
since:
|
|
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
|
|
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
|
|
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:
|
|
2965
|
-
phase_id:
|
|
2966
|
-
notes:
|
|
2967
|
-
auto_infer:
|
|
2968
|
-
run_tests:
|
|
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
|
-
|
|
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
|
|
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:
|
|
3191
|
-
role:
|
|
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:
|
|
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
|
|
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:
|
|
3504
|
-
scenario_ids:
|
|
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:
|
|
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
|
|
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:
|
|
3590
|
-
role:
|
|
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:
|
|
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
|
|
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:
|
|
4022
|
-
scenario_id:
|
|
4023
|
-
status:
|
|
4024
|
-
linked_tests:
|
|
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
|
|
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:
|
|
4113
|
-
tool_name:
|
|
4114
|
-
action:
|
|
4115
|
-
model:
|
|
4116
|
-
agent_role:
|
|
4117
|
-
task_id:
|
|
4118
|
-
phase_id:
|
|
4119
|
-
input_tokens:
|
|
4120
|
-
output_tokens:
|
|
4121
|
-
total_tokens:
|
|
4122
|
-
cost_usd:
|
|
4123
|
-
duration_ms:
|
|
4124
|
-
drift_count:
|
|
4125
|
-
drift_errors:
|
|
4126
|
-
test_pass_count:
|
|
4127
|
-
test_fail_count:
|
|
4128
|
-
lint_clean:
|
|
4129
|
-
typecheck_clean:
|
|
4130
|
-
notes:
|
|
4131
|
-
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
|
|
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:
|
|
4194
|
-
task_id:
|
|
4195
|
-
phase_id:
|
|
4196
|
-
model:
|
|
4197
|
-
agent_role:
|
|
4198
|
-
tool_name:
|
|
4199
|
-
since:
|
|
4200
|
-
until:
|
|
4201
|
-
group_by:
|
|
4202
|
-
limit:
|
|
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
|
|
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:
|
|
4293
|
-
format:
|
|
4294
|
-
task_id:
|
|
4295
|
-
phase_id:
|
|
4296
|
-
model:
|
|
4297
|
-
agent_role:
|
|
4298
|
-
tool_name:
|
|
4299
|
-
since:
|
|
4300
|
-
until:
|
|
4301
|
-
max_rows:
|
|
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);
|