@agentbridge1/cli 0.0.8 → 0.0.9
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/build-info.json +4 -4
- package/dist/commands/start.js +1 -0
- package/dist/commands/watch.js +3 -2
- package/dist/contract-intelligence.js +597 -0
- package/dist/contract-verdict.js +79 -26
- package/dist/diff-reader.js +200 -0
- package/dist/intent-parser.js +178 -0
- package/dist/mcp/agentbridge-mcp.js +585 -27
- package/dist/mcp/agentbridge-mcp.js.map +4 -4
- package/dist/proof-parser.js +118 -0
- package/dist/session-state.js +15 -0
- package/dist/session.js +10 -0
- package/package.json +1 -1
|
@@ -2980,7 +2980,7 @@ var require_compile = __commonJS({
|
|
|
2980
2980
|
const schOrFunc = root.refs[ref];
|
|
2981
2981
|
if (schOrFunc)
|
|
2982
2982
|
return schOrFunc;
|
|
2983
|
-
let _sch =
|
|
2983
|
+
let _sch = resolve3.call(this, root, ref);
|
|
2984
2984
|
if (_sch === void 0) {
|
|
2985
2985
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2986
2986
|
const { schemaId } = this.opts;
|
|
@@ -3007,7 +3007,7 @@ var require_compile = __commonJS({
|
|
|
3007
3007
|
function sameSchemaEnv(s1, s2) {
|
|
3008
3008
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3009
3009
|
}
|
|
3010
|
-
function
|
|
3010
|
+
function resolve3(root, ref) {
|
|
3011
3011
|
let sch;
|
|
3012
3012
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3013
3013
|
ref = sch;
|
|
@@ -3582,7 +3582,7 @@ var require_fast_uri = __commonJS({
|
|
|
3582
3582
|
}
|
|
3583
3583
|
return uri;
|
|
3584
3584
|
}
|
|
3585
|
-
function
|
|
3585
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
3586
3586
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3587
3587
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3588
3588
|
schemelessOptions.skipEscape = true;
|
|
@@ -3809,7 +3809,7 @@ var require_fast_uri = __commonJS({
|
|
|
3809
3809
|
var fastUri = {
|
|
3810
3810
|
SCHEMES,
|
|
3811
3811
|
normalize,
|
|
3812
|
-
resolve:
|
|
3812
|
+
resolve: resolve3,
|
|
3813
3813
|
resolveComponent,
|
|
3814
3814
|
equal,
|
|
3815
3815
|
serialize,
|
|
@@ -18892,7 +18892,7 @@ var Protocol = class {
|
|
|
18892
18892
|
return;
|
|
18893
18893
|
}
|
|
18894
18894
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
18895
|
-
await new Promise((
|
|
18895
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
|
|
18896
18896
|
options?.signal?.throwIfAborted();
|
|
18897
18897
|
}
|
|
18898
18898
|
} catch (error2) {
|
|
@@ -18909,7 +18909,7 @@ var Protocol = class {
|
|
|
18909
18909
|
*/
|
|
18910
18910
|
request(request, resultSchema, options) {
|
|
18911
18911
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
18912
|
-
return new Promise((
|
|
18912
|
+
return new Promise((resolve3, reject) => {
|
|
18913
18913
|
const earlyReject = (error2) => {
|
|
18914
18914
|
reject(error2);
|
|
18915
18915
|
};
|
|
@@ -18987,7 +18987,7 @@ var Protocol = class {
|
|
|
18987
18987
|
if (!parseResult.success) {
|
|
18988
18988
|
reject(parseResult.error);
|
|
18989
18989
|
} else {
|
|
18990
|
-
|
|
18990
|
+
resolve3(parseResult.data);
|
|
18991
18991
|
}
|
|
18992
18992
|
} catch (error2) {
|
|
18993
18993
|
reject(error2);
|
|
@@ -19248,12 +19248,12 @@ var Protocol = class {
|
|
|
19248
19248
|
}
|
|
19249
19249
|
} catch {
|
|
19250
19250
|
}
|
|
19251
|
-
return new Promise((
|
|
19251
|
+
return new Promise((resolve3, reject) => {
|
|
19252
19252
|
if (signal.aborted) {
|
|
19253
19253
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
19254
19254
|
return;
|
|
19255
19255
|
}
|
|
19256
|
-
const timeoutId = setTimeout(
|
|
19256
|
+
const timeoutId = setTimeout(resolve3, interval);
|
|
19257
19257
|
signal.addEventListener("abort", () => {
|
|
19258
19258
|
clearTimeout(timeoutId);
|
|
19259
19259
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -20353,7 +20353,7 @@ var McpServer = class {
|
|
|
20353
20353
|
let task = createTaskResult.task;
|
|
20354
20354
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
20355
20355
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
20356
|
-
await new Promise((
|
|
20356
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
|
|
20357
20357
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
20358
20358
|
if (!updatedTask) {
|
|
20359
20359
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -21002,20 +21002,161 @@ var StdioServerTransport = class {
|
|
|
21002
21002
|
this.onclose?.();
|
|
21003
21003
|
}
|
|
21004
21004
|
send(message) {
|
|
21005
|
-
return new Promise((
|
|
21005
|
+
return new Promise((resolve3) => {
|
|
21006
21006
|
const json = serializeMessage(message);
|
|
21007
21007
|
if (this._stdout.write(json)) {
|
|
21008
|
-
|
|
21008
|
+
resolve3();
|
|
21009
21009
|
} else {
|
|
21010
|
-
this._stdout.once("drain",
|
|
21010
|
+
this._stdout.once("drain", resolve3);
|
|
21011
21011
|
}
|
|
21012
21012
|
});
|
|
21013
21013
|
}
|
|
21014
21014
|
};
|
|
21015
21015
|
|
|
21016
|
+
// ../mcp/agentbridge-mcp.ts
|
|
21017
|
+
var import_node_fs3 = require("node:fs");
|
|
21018
|
+
var import_node_path2 = require("node:path");
|
|
21019
|
+
|
|
21016
21020
|
// src/session.ts
|
|
21017
21021
|
var import_node_child_process2 = require("node:child_process");
|
|
21018
21022
|
|
|
21023
|
+
// src/intent-parser.ts
|
|
21024
|
+
var ACTIONS = ["fix", "add", "update", "refactor", "remove", "migrate", "rename", "revert", "delete", "implement", "improve", "patch"];
|
|
21025
|
+
var DOMAIN_KEYWORD_MAP = {
|
|
21026
|
+
auth: ["auth", "login", "logout", "session", "token", "oauth", "jwt", "password", "signin", "signup", "sign-in", "sign-up", "register", "credential", "permission", "role"],
|
|
21027
|
+
database: ["database", "db", "schema", "migration", "migrate", "prisma", "sql", "query", "table", "column", "index", "model", "seed", "orm"],
|
|
21028
|
+
payments: ["payment", "payments", "billing", "stripe", "invoice", "subscription", "checkout", "webhook"],
|
|
21029
|
+
api: ["api", "endpoint", "route", "handler", "controller", "request", "response", "rest", "graphql"],
|
|
21030
|
+
ui: ["ui", "style", "css", "component", "page", "layout", "copy", "design", "render", "display", "view", "frontend", "html", "template"],
|
|
21031
|
+
mcp: ["mcp", "agentbridge", "cursor", "rules"],
|
|
21032
|
+
tests: ["test", "tests", "spec", "vitest", "jest", "coverage", "proof"]
|
|
21033
|
+
};
|
|
21034
|
+
var SYMPTOMS = {
|
|
21035
|
+
"401": ["401", "unauthorized", "unauthenticated"],
|
|
21036
|
+
"403": ["403", "forbidden"],
|
|
21037
|
+
"404": ["404", "not found", "notfound"],
|
|
21038
|
+
"500": ["500", "internal server error", "server error"],
|
|
21039
|
+
"null": ["null", "undefined", "nan", "nil"],
|
|
21040
|
+
"crash": ["crash", "crashes", "crashed", "exception", "throws", "throw"],
|
|
21041
|
+
"loop": ["loop", "infinite loop", "recursion"],
|
|
21042
|
+
"hang": ["hang", "hangs", "timeout", "deadlock"],
|
|
21043
|
+
"slow": ["slow", "performance", "latency", "memory leak", "memory"],
|
|
21044
|
+
"duplicate": ["duplicate", "duplicated", "twice"],
|
|
21045
|
+
"missing": ["missing", "not showing", "not found"]
|
|
21046
|
+
};
|
|
21047
|
+
var ROUTE_RE = /(?<!\w)(\/[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_:_-]+)*)/g;
|
|
21048
|
+
var FILE_RE = /\b([A-Za-z][A-Za-z0-9_-]*\.[a-z]{2,4})\b/g;
|
|
21049
|
+
var PASCAL_RE = /\b([A-Z][a-z]+(?:[A-Z][a-z]*)+)\b/g;
|
|
21050
|
+
var CAMEL_FN_RE = /\b([a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)+)\b/g;
|
|
21051
|
+
var QUOTED_RE = /"([^"]+)"|'([^']+)'/g;
|
|
21052
|
+
function detectDomain(lower) {
|
|
21053
|
+
for (const [domain, keywords] of Object.entries(DOMAIN_KEYWORD_MAP)) {
|
|
21054
|
+
if (keywords.some((kw) => lower.includes(kw))) return domain;
|
|
21055
|
+
}
|
|
21056
|
+
return null;
|
|
21057
|
+
}
|
|
21058
|
+
function detectAction(lower) {
|
|
21059
|
+
for (const action of ACTIONS) {
|
|
21060
|
+
if (lower.startsWith(action) || lower.includes(` ${action} `)) return action;
|
|
21061
|
+
}
|
|
21062
|
+
return null;
|
|
21063
|
+
}
|
|
21064
|
+
function detectSymptom(lower) {
|
|
21065
|
+
for (const [symptom, patterns] of Object.entries(SYMPTOMS)) {
|
|
21066
|
+
if (patterns.some((p) => lower.includes(p))) return symptom;
|
|
21067
|
+
}
|
|
21068
|
+
return null;
|
|
21069
|
+
}
|
|
21070
|
+
function extractTargets(raw) {
|
|
21071
|
+
const targets = /* @__PURE__ */ new Set();
|
|
21072
|
+
for (const m of raw.matchAll(QUOTED_RE)) {
|
|
21073
|
+
const phrase = m[1] ?? m[2];
|
|
21074
|
+
if (phrase) targets.add(phrase.trim());
|
|
21075
|
+
}
|
|
21076
|
+
for (const m of raw.matchAll(ROUTE_RE)) {
|
|
21077
|
+
targets.add(m[1]);
|
|
21078
|
+
}
|
|
21079
|
+
for (const m of raw.matchAll(FILE_RE)) {
|
|
21080
|
+
targets.add(m[1]);
|
|
21081
|
+
}
|
|
21082
|
+
for (const m of raw.matchAll(PASCAL_RE)) {
|
|
21083
|
+
targets.add(m[1]);
|
|
21084
|
+
}
|
|
21085
|
+
for (const m of raw.matchAll(CAMEL_FN_RE)) {
|
|
21086
|
+
if (m[1].length <= 40) targets.add(m[1]);
|
|
21087
|
+
}
|
|
21088
|
+
return [...targets];
|
|
21089
|
+
}
|
|
21090
|
+
function inferLayers(domain, targets, symptom, action, rawLower) {
|
|
21091
|
+
const layers = [];
|
|
21092
|
+
const hasRoute = targets.some((t) => t.startsWith("/"));
|
|
21093
|
+
const hasMigration = action === "migrate" || targets.some((t) => t.toLowerCase().includes("migration"));
|
|
21094
|
+
if (domain === "auth") {
|
|
21095
|
+
if (symptom === "401" || symptom === "403") layers.push("route_handler", "auth_middleware");
|
|
21096
|
+
else if (hasRoute) layers.push("route_handler", "auth_middleware");
|
|
21097
|
+
else layers.push("auth_middleware");
|
|
21098
|
+
}
|
|
21099
|
+
if (domain === "api") {
|
|
21100
|
+
if (hasRoute) layers.push("route_handler");
|
|
21101
|
+
else layers.push("route_handler");
|
|
21102
|
+
}
|
|
21103
|
+
if (domain === "database") {
|
|
21104
|
+
if (hasMigration) layers.push("schema", "migration_file");
|
|
21105
|
+
else layers.push("model", "query");
|
|
21106
|
+
}
|
|
21107
|
+
if (domain === "ui") {
|
|
21108
|
+
layers.push("component", "view");
|
|
21109
|
+
}
|
|
21110
|
+
if (domain === "payments") {
|
|
21111
|
+
if (targets.some((t) => t.toLowerCase().includes("webhook")) || rawLower.includes("webhook")) {
|
|
21112
|
+
layers.push("webhook_handler");
|
|
21113
|
+
} else {
|
|
21114
|
+
layers.push("billing_handler");
|
|
21115
|
+
}
|
|
21116
|
+
}
|
|
21117
|
+
if (domain === "mcp") {
|
|
21118
|
+
layers.push("mcp_server", "config");
|
|
21119
|
+
}
|
|
21120
|
+
return layers;
|
|
21121
|
+
}
|
|
21122
|
+
function parseIntent(raw) {
|
|
21123
|
+
if (!raw?.trim()) {
|
|
21124
|
+
return { raw: raw ?? "", domain: null, targets: [], symptom: null, action: null, affected_layer: [] };
|
|
21125
|
+
}
|
|
21126
|
+
const lower = raw.toLowerCase();
|
|
21127
|
+
const domain = detectDomain(lower);
|
|
21128
|
+
const action = detectAction(lower);
|
|
21129
|
+
const symptom = detectSymptom(lower);
|
|
21130
|
+
const targets = extractTargets(raw);
|
|
21131
|
+
const affected_layer = inferLayers(domain, targets, symptom, action, lower);
|
|
21132
|
+
return { raw, domain, targets, symptom, action, affected_layer };
|
|
21133
|
+
}
|
|
21134
|
+
function buildTaskSpecificCriteria(parsed) {
|
|
21135
|
+
const extra = [];
|
|
21136
|
+
const routeTargets = parsed.targets.filter((t) => t.startsWith("/"));
|
|
21137
|
+
const fileTargets = parsed.targets.filter((t) => t.includes("."));
|
|
21138
|
+
const namedTargets = parsed.targets.filter((t) => !t.startsWith("/") && !t.includes("."));
|
|
21139
|
+
if (routeTargets.length > 0 && parsed.domain === "auth" && parsed.symptom) {
|
|
21140
|
+
extra.push(`The ${routeTargets[0]} route handler or its auth middleware chain is updated to address the ${parsed.symptom}.`);
|
|
21141
|
+
} else if (routeTargets.length > 0 && parsed.domain === "api") {
|
|
21142
|
+
extra.push(`The ${routeTargets[0]} endpoint handler is updated as intended.`);
|
|
21143
|
+
} else if (routeTargets.length > 0) {
|
|
21144
|
+
extra.push(`Changes are focused on the ${routeTargets[0]} route.`);
|
|
21145
|
+
} else if (fileTargets.length > 0) {
|
|
21146
|
+
extra.push(`Changes are focused on ${fileTargets[0]}.`);
|
|
21147
|
+
} else if (namedTargets.length > 0) {
|
|
21148
|
+
extra.push(`Changes are focused on ${namedTargets[0]}.`);
|
|
21149
|
+
}
|
|
21150
|
+
if (parsed.symptom && routeTargets.length > 0) {
|
|
21151
|
+
extra.push(`Proof exists for the ${parsed.symptom} behavior on ${routeTargets[0]}.`);
|
|
21152
|
+
} else if (parsed.symptom) {
|
|
21153
|
+
extra.push(`Proof exists that the ${parsed.symptom} condition is resolved.`);
|
|
21154
|
+
} else if (parsed.action && parsed.domain) {
|
|
21155
|
+
extra.push(`Proof exists that the ${parsed.action} to the ${parsed.domain} layer is correct.`);
|
|
21156
|
+
}
|
|
21157
|
+
return extra;
|
|
21158
|
+
}
|
|
21159
|
+
|
|
21019
21160
|
// src/session-state.ts
|
|
21020
21161
|
var import_node_fs2 = require("node:fs");
|
|
21021
21162
|
var import_node_path = require("node:path");
|
|
@@ -21175,6 +21316,15 @@ function isLocalSessionState(value) {
|
|
|
21175
21316
|
if (value.updatedAt !== void 0 && typeof value.updatedAt !== "string") return false;
|
|
21176
21317
|
if (value.closedAt !== void 0 && typeof value.closedAt !== "string") return false;
|
|
21177
21318
|
if (value.claimedPaths !== void 0 && !isStringArray(value.claimedPaths)) return false;
|
|
21319
|
+
if (value.createdBy !== void 0 && value.createdBy !== "user_start" && value.createdBy !== "agent_hello") {
|
|
21320
|
+
return false;
|
|
21321
|
+
}
|
|
21322
|
+
if (value.contractProfiles !== void 0 && !isStringArray(value.contractProfiles)) return false;
|
|
21323
|
+
if (value.expectedSurfaces !== void 0 && !isStringArray(value.expectedSurfaces)) return false;
|
|
21324
|
+
if (value.expectedFileAreas !== void 0 && !isStringArray(value.expectedFileAreas)) return false;
|
|
21325
|
+
if (value.completionCriteria !== void 0 && !isStringArray(value.completionCriteria)) return false;
|
|
21326
|
+
if (value.proofNeeded !== void 0 && !isStringArray(value.proofNeeded)) return false;
|
|
21327
|
+
if (value.riskyOmissions !== void 0 && !isStringArray(value.riskyOmissions)) return false;
|
|
21178
21328
|
if (value.lastLocalVerificationRun !== void 0 && !isLocalVerificationRun(value.lastLocalVerificationRun)) {
|
|
21179
21329
|
return false;
|
|
21180
21330
|
}
|
|
@@ -21243,6 +21393,296 @@ function writeSessionState(state) {
|
|
|
21243
21393
|
}
|
|
21244
21394
|
(0, import_node_fs2.renameSync)(tempPath, path);
|
|
21245
21395
|
}
|
|
21396
|
+
function clearSessionState() {
|
|
21397
|
+
writeSessionState({
|
|
21398
|
+
id: "none",
|
|
21399
|
+
agentId: "none",
|
|
21400
|
+
laneDomain: null,
|
|
21401
|
+
status: "closed",
|
|
21402
|
+
closeReason: "completed",
|
|
21403
|
+
changedFiles: [],
|
|
21404
|
+
crossings: [],
|
|
21405
|
+
approvals: [],
|
|
21406
|
+
domains: [],
|
|
21407
|
+
createdAt: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
21408
|
+
});
|
|
21409
|
+
}
|
|
21410
|
+
|
|
21411
|
+
// src/contract-intelligence.ts
|
|
21412
|
+
var MCP_RULE_PROFILE = "mcp_rules_config_install";
|
|
21413
|
+
var AUTH_PROFILE = "auth_login_session";
|
|
21414
|
+
var DB_PROFILE = "database_schema_migration";
|
|
21415
|
+
var UI_PROFILE = "ui_style_copy";
|
|
21416
|
+
var API_PROFILE = "api_endpoint";
|
|
21417
|
+
var TEST_PROFILE = "tests";
|
|
21418
|
+
var PAYMENTS_PROFILE = "payments_webhooks";
|
|
21419
|
+
var GENERIC_PROFILE = "generic";
|
|
21420
|
+
function unique(values) {
|
|
21421
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
21422
|
+
}
|
|
21423
|
+
function matchIntent(intent, keywords) {
|
|
21424
|
+
const lower = intent.toLowerCase();
|
|
21425
|
+
return keywords.some((keyword) => lower.includes(keyword));
|
|
21426
|
+
}
|
|
21427
|
+
function detectProfiles(intent) {
|
|
21428
|
+
const profiles = [];
|
|
21429
|
+
if (matchIntent(intent, ["mcp"]) && matchIntent(intent, ["rule", "rules", "install", "setup", "config", "configuration"])) {
|
|
21430
|
+
profiles.push(MCP_RULE_PROFILE);
|
|
21431
|
+
}
|
|
21432
|
+
if (matchIntent(intent, ["auth", "login", "session", "token", "oauth"])) {
|
|
21433
|
+
profiles.push(AUTH_PROFILE);
|
|
21434
|
+
}
|
|
21435
|
+
if (matchIntent(intent, ["database", "db", "schema", "migration", "prisma", "sql"])) {
|
|
21436
|
+
profiles.push(DB_PROFILE);
|
|
21437
|
+
}
|
|
21438
|
+
if (matchIntent(intent, ["ui", "style", "css", "copy", "layout", "component"])) {
|
|
21439
|
+
profiles.push(UI_PROFILE);
|
|
21440
|
+
}
|
|
21441
|
+
if (matchIntent(intent, ["api", "endpoint", "route", "handler", "controller"])) {
|
|
21442
|
+
profiles.push(API_PROFILE);
|
|
21443
|
+
}
|
|
21444
|
+
if (matchIntent(intent, ["test", "tests", "vitest", "jest", "proof"])) {
|
|
21445
|
+
profiles.push(TEST_PROFILE);
|
|
21446
|
+
}
|
|
21447
|
+
if (matchIntent(intent, ["payment", "payments", "billing", "stripe", "webhook"])) {
|
|
21448
|
+
profiles.push(PAYMENTS_PROFILE);
|
|
21449
|
+
}
|
|
21450
|
+
return profiles.length > 0 ? profiles : [GENERIC_PROFILE];
|
|
21451
|
+
}
|
|
21452
|
+
function profileBlueprint(profile) {
|
|
21453
|
+
switch (profile) {
|
|
21454
|
+
case MCP_RULE_PROFILE:
|
|
21455
|
+
return {
|
|
21456
|
+
expectedSurfaces: ["mcp", "rules_installation", "configuration_flow", "tests_or_manual_proof"],
|
|
21457
|
+
expectedFileAreas: [
|
|
21458
|
+
"mcp/**",
|
|
21459
|
+
"mcp/agentbridge-mcp.ts",
|
|
21460
|
+
"AGENTBRIDGE.md",
|
|
21461
|
+
".cursor/rules/**",
|
|
21462
|
+
"cli/src/mcp-config.ts",
|
|
21463
|
+
"cli/src/commands/setup-mcp.ts"
|
|
21464
|
+
],
|
|
21465
|
+
completionCriteria: [
|
|
21466
|
+
"MCP configuration path triggers AgentBridge rule installation.",
|
|
21467
|
+
"Rules are created or updated in the expected Cursor rules location.",
|
|
21468
|
+
"Existing rules/config are preserved or safely updated.",
|
|
21469
|
+
"Re-running MCP configuration is idempotent and does not duplicate rules.",
|
|
21470
|
+
"Proof exists that MCP configuration causes rules to be installed."
|
|
21471
|
+
],
|
|
21472
|
+
proofNeeded: [
|
|
21473
|
+
"Run MCP setup/configuration flow in a clean repo.",
|
|
21474
|
+
"Confirm the AgentBridge Cursor rules file is created.",
|
|
21475
|
+
"Run setup/configuration again to confirm idempotency.",
|
|
21476
|
+
"Record test/manual proof output."
|
|
21477
|
+
],
|
|
21478
|
+
riskyOmissions: [
|
|
21479
|
+
"MCP server file changed but no install trigger wired to the configuration path.",
|
|
21480
|
+
"Rules are installed only in local mode or only in server mode.",
|
|
21481
|
+
"Existing Cursor rules are overwritten.",
|
|
21482
|
+
"No idempotency check.",
|
|
21483
|
+
"No proof that the auto-install behavior actually runs."
|
|
21484
|
+
],
|
|
21485
|
+
contractProfiles: [MCP_RULE_PROFILE]
|
|
21486
|
+
};
|
|
21487
|
+
case AUTH_PROFILE:
|
|
21488
|
+
return {
|
|
21489
|
+
expectedSurfaces: ["auth", "session", "tests_or_manual_proof"],
|
|
21490
|
+
expectedFileAreas: ["auth/**", "src/**/auth/**", "src/**/session/**", "middleware/**"],
|
|
21491
|
+
completionCriteria: [
|
|
21492
|
+
"Authentication/session flow handling is updated where intended.",
|
|
21493
|
+
"Authorization boundaries remain explicit and unchanged outside scope.",
|
|
21494
|
+
"Proof exists for the auth/session behavior change."
|
|
21495
|
+
],
|
|
21496
|
+
proofNeeded: ["Run auth/session flow tests or a reproducible manual proof."],
|
|
21497
|
+
riskyOmissions: [
|
|
21498
|
+
"Auth logic changed without session or middleware checks.",
|
|
21499
|
+
"No proof of login/session behavior."
|
|
21500
|
+
],
|
|
21501
|
+
contractProfiles: [AUTH_PROFILE]
|
|
21502
|
+
};
|
|
21503
|
+
case DB_PROFILE:
|
|
21504
|
+
return {
|
|
21505
|
+
expectedSurfaces: ["database", "schema_migration", "tests_or_manual_proof"],
|
|
21506
|
+
expectedFileAreas: ["prisma/**", "migrations/**", "src/**/db/**", "src/**/database/**"],
|
|
21507
|
+
completionCriteria: [
|
|
21508
|
+
"Schema/data-layer changes are applied in intended files.",
|
|
21509
|
+
"Migration or compatibility impact is accounted for.",
|
|
21510
|
+
"Proof exists for migration/query behavior."
|
|
21511
|
+
],
|
|
21512
|
+
proofNeeded: ["Run migration/database verification command and capture output."],
|
|
21513
|
+
riskyOmissions: [
|
|
21514
|
+
"Schema changed without migration/compatibility proof.",
|
|
21515
|
+
"No evidence of migration/query validation."
|
|
21516
|
+
],
|
|
21517
|
+
contractProfiles: [DB_PROFILE]
|
|
21518
|
+
};
|
|
21519
|
+
case UI_PROFILE:
|
|
21520
|
+
return {
|
|
21521
|
+
expectedSurfaces: ["ui", "copy_or_style", "tests_or_manual_proof"],
|
|
21522
|
+
expectedFileAreas: ["src/**/components/**", "src/**/pages/**", "src/**/*.css", "src/**/*.html"],
|
|
21523
|
+
completionCriteria: [
|
|
21524
|
+
"UI/copy/style surface for the contract is updated.",
|
|
21525
|
+
"Unrelated UI areas are not changed unintentionally.",
|
|
21526
|
+
"Proof exists for the visible behavior change."
|
|
21527
|
+
],
|
|
21528
|
+
proofNeeded: ["Record manual verification steps (or visual/tests) for UI outcome."],
|
|
21529
|
+
riskyOmissions: [
|
|
21530
|
+
"UI files changed without a clear visible proof.",
|
|
21531
|
+
"Broad style changes without scope evidence."
|
|
21532
|
+
],
|
|
21533
|
+
contractProfiles: [UI_PROFILE]
|
|
21534
|
+
};
|
|
21535
|
+
case API_PROFILE:
|
|
21536
|
+
return {
|
|
21537
|
+
expectedSurfaces: ["api", "endpoint_logic", "tests_or_manual_proof"],
|
|
21538
|
+
expectedFileAreas: ["src/**/routes/**", "src/**/api/**", "src/**/controllers/**"],
|
|
21539
|
+
completionCriteria: [
|
|
21540
|
+
"Target API/endpoint behavior is changed in the correct surface.",
|
|
21541
|
+
"Request/response behavior is evidenced.",
|
|
21542
|
+
"Proof exists for endpoint behavior."
|
|
21543
|
+
],
|
|
21544
|
+
proofNeeded: ["Run endpoint tests or reproducible request/response proof."],
|
|
21545
|
+
riskyOmissions: [
|
|
21546
|
+
"Endpoint files changed without request/response evidence.",
|
|
21547
|
+
"No proof for API behavior change."
|
|
21548
|
+
],
|
|
21549
|
+
contractProfiles: [API_PROFILE]
|
|
21550
|
+
};
|
|
21551
|
+
case TEST_PROFILE:
|
|
21552
|
+
return {
|
|
21553
|
+
expectedSurfaces: ["tests", "proof"],
|
|
21554
|
+
expectedFileAreas: ["**/*.test.ts", "**/*.spec.ts", "tests/**"],
|
|
21555
|
+
completionCriteria: [
|
|
21556
|
+
"Test/proof artifacts relevant to the contract are updated.",
|
|
21557
|
+
"Test execution evidence is recorded."
|
|
21558
|
+
],
|
|
21559
|
+
proofNeeded: ["Run tests and record command + result output."],
|
|
21560
|
+
riskyOmissions: ["Tests changed but no execution proof recorded."],
|
|
21561
|
+
contractProfiles: [TEST_PROFILE]
|
|
21562
|
+
};
|
|
21563
|
+
case PAYMENTS_PROFILE:
|
|
21564
|
+
return {
|
|
21565
|
+
expectedSurfaces: ["payments", "webhooks", "tests_or_manual_proof"],
|
|
21566
|
+
expectedFileAreas: ["src/**/billing/**", "src/**/payments/**", "src/**/webhooks/**"],
|
|
21567
|
+
completionCriteria: [
|
|
21568
|
+
"Payments/webhook handling logic is updated in scope.",
|
|
21569
|
+
"Critical payment side effects are evidenced.",
|
|
21570
|
+
"Proof exists for payment/webhook behavior."
|
|
21571
|
+
],
|
|
21572
|
+
proofNeeded: ["Run payment/webhook verification flow and capture output."],
|
|
21573
|
+
riskyOmissions: [
|
|
21574
|
+
"Webhook/payment logic changed without behavior proof.",
|
|
21575
|
+
"No idempotency/effect validation for financial flows."
|
|
21576
|
+
],
|
|
21577
|
+
contractProfiles: [PAYMENTS_PROFILE]
|
|
21578
|
+
};
|
|
21579
|
+
default:
|
|
21580
|
+
return {
|
|
21581
|
+
expectedSurfaces: ["implementation_surface", "tests_or_manual_proof"],
|
|
21582
|
+
expectedFileAreas: ["**"],
|
|
21583
|
+
completionCriteria: [
|
|
21584
|
+
"Files changed align with the declared contract intent.",
|
|
21585
|
+
"Proof exists for the intended behavior change."
|
|
21586
|
+
],
|
|
21587
|
+
proofNeeded: ["Run relevant tests or provide manual proof output."],
|
|
21588
|
+
riskyOmissions: ["Code changed without proof linked to the declared intent."],
|
|
21589
|
+
contractProfiles: [GENERIC_PROFILE]
|
|
21590
|
+
};
|
|
21591
|
+
}
|
|
21592
|
+
}
|
|
21593
|
+
function buildContractIntelligence(intent, createdBy) {
|
|
21594
|
+
const normalizedIntent = intent?.trim() ?? "";
|
|
21595
|
+
const profiles = detectProfiles(normalizedIntent);
|
|
21596
|
+
const combined = profiles.map((profile) => profileBlueprint(profile));
|
|
21597
|
+
const baseCompletionCriteria = unique(combined.flatMap((item) => item.completionCriteria));
|
|
21598
|
+
const parsed = parseIntent(normalizedIntent);
|
|
21599
|
+
const taskCriteria = buildTaskSpecificCriteria(parsed);
|
|
21600
|
+
const firstTask = taskCriteria[0];
|
|
21601
|
+
const lastTask = taskCriteria[1];
|
|
21602
|
+
const completionCriteria = unique([
|
|
21603
|
+
...firstTask ? [firstTask] : [],
|
|
21604
|
+
...baseCompletionCriteria.filter((c) => !c.toLowerCase().startsWith("proof")),
|
|
21605
|
+
...lastTask ? [lastTask] : [],
|
|
21606
|
+
...baseCompletionCriteria.filter((c) => c.toLowerCase().startsWith("proof"))
|
|
21607
|
+
]);
|
|
21608
|
+
return {
|
|
21609
|
+
expectedSurfaces: unique(combined.flatMap((item) => item.expectedSurfaces)),
|
|
21610
|
+
expectedFileAreas: unique(combined.flatMap((item) => item.expectedFileAreas)),
|
|
21611
|
+
completionCriteria,
|
|
21612
|
+
proofNeeded: unique(combined.flatMap((item) => item.proofNeeded)),
|
|
21613
|
+
riskyOmissions: unique(combined.flatMap((item) => item.riskyOmissions)),
|
|
21614
|
+
contractProfiles: unique(combined.flatMap((item) => item.contractProfiles)),
|
|
21615
|
+
createdBy
|
|
21616
|
+
};
|
|
21617
|
+
}
|
|
21618
|
+
function localSessionToContractIntelligence(session) {
|
|
21619
|
+
if (session.completionCriteria?.length && session.contractProfiles?.length) {
|
|
21620
|
+
return {
|
|
21621
|
+
contractProfiles: session.contractProfiles,
|
|
21622
|
+
completionCriteria: session.completionCriteria,
|
|
21623
|
+
proofNeeded: session.proofNeeded ?? [],
|
|
21624
|
+
riskyOmissions: session.riskyOmissions ?? [],
|
|
21625
|
+
expectedSurfaces: session.expectedSurfaces ?? [],
|
|
21626
|
+
expectedFileAreas: session.expectedFileAreas ?? [],
|
|
21627
|
+
createdBy: session.createdBy ?? "agent_hello"
|
|
21628
|
+
};
|
|
21629
|
+
}
|
|
21630
|
+
return buildContractIntelligence(session.intent, session.createdBy ?? "agent_hello");
|
|
21631
|
+
}
|
|
21632
|
+
function sessionNeedsContractBackfill(session) {
|
|
21633
|
+
return !session.completionCriteria?.length || !session.contractProfiles?.length;
|
|
21634
|
+
}
|
|
21635
|
+
function ensureSessionContractIntelligence(session) {
|
|
21636
|
+
if (!sessionNeedsContractBackfill(session)) {
|
|
21637
|
+
return session;
|
|
21638
|
+
}
|
|
21639
|
+
const createdBy = session.createdBy ?? (session.agentId?.trim() === "local" ? "user_start" : "agent_hello");
|
|
21640
|
+
const contract = buildContractIntelligence(session.intent?.trim(), createdBy);
|
|
21641
|
+
const updated = {
|
|
21642
|
+
...session,
|
|
21643
|
+
createdBy,
|
|
21644
|
+
contractProfiles: contract.contractProfiles,
|
|
21645
|
+
expectedSurfaces: contract.expectedSurfaces,
|
|
21646
|
+
expectedFileAreas: contract.expectedFileAreas,
|
|
21647
|
+
completionCriteria: contract.completionCriteria,
|
|
21648
|
+
proofNeeded: contract.proofNeeded,
|
|
21649
|
+
riskyOmissions: contract.riskyOmissions
|
|
21650
|
+
};
|
|
21651
|
+
writeSessionState(updated);
|
|
21652
|
+
return updated;
|
|
21653
|
+
}
|
|
21654
|
+
function buildProofRequiredCommands(contract) {
|
|
21655
|
+
if (contract.contractProfiles.includes(MCP_RULE_PROFILE)) {
|
|
21656
|
+
return [
|
|
21657
|
+
"agentbridge verify npm run setup-mcp -- --local",
|
|
21658
|
+
"agentbridge verify npm run setup-mcp -- --local (run again to confirm idempotency)"
|
|
21659
|
+
];
|
|
21660
|
+
}
|
|
21661
|
+
if (contract.contractProfiles.includes(DB_PROFILE)) {
|
|
21662
|
+
return [
|
|
21663
|
+
"agentbridge verify npx prisma migrate status",
|
|
21664
|
+
"agentbridge verify npm test"
|
|
21665
|
+
];
|
|
21666
|
+
}
|
|
21667
|
+
if (contract.contractProfiles.includes(AUTH_PROFILE) || contract.contractProfiles.includes(API_PROFILE) || contract.contractProfiles.includes(UI_PROFILE) || contract.contractProfiles.includes(TEST_PROFILE) || contract.contractProfiles.includes(PAYMENTS_PROFILE)) {
|
|
21668
|
+
return ["agentbridge verify npm test"];
|
|
21669
|
+
}
|
|
21670
|
+
return ["agentbridge verify npm test"];
|
|
21671
|
+
}
|
|
21672
|
+
function buildLocalHelloPayload(session) {
|
|
21673
|
+
const contract = localSessionToContractIntelligence(session);
|
|
21674
|
+
const scopeSource = session.createdBy ?? (session.agentId?.trim() === "local" ? "user_start" : "agent_hello");
|
|
21675
|
+
return {
|
|
21676
|
+
contract: {
|
|
21677
|
+
id: session.id,
|
|
21678
|
+
intent: session.intent?.trim() ?? null,
|
|
21679
|
+
created_by: scopeSource
|
|
21680
|
+
},
|
|
21681
|
+
done_checklist: contract.completionCriteria.slice(0, 4),
|
|
21682
|
+
proof_required: buildProofRequiredCommands(contract),
|
|
21683
|
+
warnings: contract.riskyOmissions.slice(0, 2)
|
|
21684
|
+
};
|
|
21685
|
+
}
|
|
21246
21686
|
|
|
21247
21687
|
// src/git-status.ts
|
|
21248
21688
|
var import_node_child_process = require("node:child_process");
|
|
@@ -21340,11 +21780,20 @@ function openLocalSession(input) {
|
|
|
21340
21780
|
const claimedPaths = [...new Set((input.claimedPaths ?? []).map((path) => path.trim()).filter(Boolean))];
|
|
21341
21781
|
const baseline = captureLocalSessionBaseline();
|
|
21342
21782
|
const now = baseline.startedAt;
|
|
21783
|
+
const createdBy = input.createdBy ?? (input.agentId?.trim() === "local" ? "user_start" : "agent_hello");
|
|
21784
|
+
const contract = buildContractIntelligence(input.intent?.trim(), createdBy);
|
|
21343
21785
|
const state = {
|
|
21344
21786
|
id: `local_${Date.now().toString(36)}`,
|
|
21345
21787
|
agentId: input.agentId?.trim() || "local",
|
|
21346
21788
|
laneDomain: input.laneDomain,
|
|
21347
21789
|
intent: input.intent?.trim() || void 0,
|
|
21790
|
+
createdBy,
|
|
21791
|
+
contractProfiles: contract.contractProfiles,
|
|
21792
|
+
expectedSurfaces: contract.expectedSurfaces,
|
|
21793
|
+
expectedFileAreas: contract.expectedFileAreas,
|
|
21794
|
+
completionCriteria: contract.completionCriteria,
|
|
21795
|
+
proofNeeded: contract.proofNeeded,
|
|
21796
|
+
riskyOmissions: contract.riskyOmissions,
|
|
21348
21797
|
mode: input.mode,
|
|
21349
21798
|
changeRequestId: input.changeRequestId,
|
|
21350
21799
|
claimedPaths,
|
|
@@ -22135,6 +22584,84 @@ function toolJson(data) {
|
|
|
22135
22584
|
]
|
|
22136
22585
|
};
|
|
22137
22586
|
}
|
|
22587
|
+
function isRecord2(value) {
|
|
22588
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22589
|
+
}
|
|
22590
|
+
function needsRulesAutoInstall(hello) {
|
|
22591
|
+
return isRecord2(hello) && hello.rules_status === "not_installed";
|
|
22592
|
+
}
|
|
22593
|
+
function formatUnknownError(err) {
|
|
22594
|
+
if (err instanceof Error) return err.message;
|
|
22595
|
+
return String(err);
|
|
22596
|
+
}
|
|
22597
|
+
async function autoInstallRulesForProject(cfg, projectId) {
|
|
22598
|
+
const installPath = `/v1/dev/projects/${encodeURIComponent(projectId)}/rules`;
|
|
22599
|
+
const installRes = await bridgeJson(cfg, "GET", installPath);
|
|
22600
|
+
if (!installRes.ok) {
|
|
22601
|
+
return {
|
|
22602
|
+
status: "failed",
|
|
22603
|
+
step: "install_agentbridge_rules",
|
|
22604
|
+
error: formatHttpFailure(installPath, installRes.status, installRes.text, installRes.json)
|
|
22605
|
+
};
|
|
22606
|
+
}
|
|
22607
|
+
if (!isRecord2(installRes.json) || !Array.isArray(installRes.json.files)) {
|
|
22608
|
+
return {
|
|
22609
|
+
status: "failed",
|
|
22610
|
+
step: "install_agentbridge_rules",
|
|
22611
|
+
error: "Rules payload is missing a valid files[] list."
|
|
22612
|
+
};
|
|
22613
|
+
}
|
|
22614
|
+
const repoRoot = process.env.AGENTBRIDGE_REPO_ROOT?.trim() || process.cwd();
|
|
22615
|
+
const writtenFiles = [];
|
|
22616
|
+
try {
|
|
22617
|
+
for (const file of installRes.json.files) {
|
|
22618
|
+
if (!isRecord2(file) || typeof file.path !== "string" || typeof file.content !== "string") {
|
|
22619
|
+
throw new Error("Invalid rules file entry in server response.");
|
|
22620
|
+
}
|
|
22621
|
+
const absolutePath = (0, import_node_path2.resolve)(repoRoot, file.path);
|
|
22622
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path2.dirname)(absolutePath), { recursive: true });
|
|
22623
|
+
(0, import_node_fs3.writeFileSync)(absolutePath, `${file.content}
|
|
22624
|
+
`, "utf8");
|
|
22625
|
+
writtenFiles.push(file.path);
|
|
22626
|
+
}
|
|
22627
|
+
} catch (err) {
|
|
22628
|
+
return {
|
|
22629
|
+
status: "failed",
|
|
22630
|
+
step: "write_rules_files",
|
|
22631
|
+
error: formatUnknownError(err)
|
|
22632
|
+
};
|
|
22633
|
+
}
|
|
22634
|
+
const markPath = `/v1/dev/projects/${encodeURIComponent(projectId)}/rules/mark-installed`;
|
|
22635
|
+
const markRes = await bridgeJson(cfg, "POST", markPath, {});
|
|
22636
|
+
if (!markRes.ok) {
|
|
22637
|
+
return {
|
|
22638
|
+
status: "failed",
|
|
22639
|
+
step: "mark_rules_installed",
|
|
22640
|
+
error: formatHttpFailure(markPath, markRes.status, markRes.text, markRes.json)
|
|
22641
|
+
};
|
|
22642
|
+
}
|
|
22643
|
+
return {
|
|
22644
|
+
status: "installed",
|
|
22645
|
+
repo_root: repoRoot,
|
|
22646
|
+
written_files: writtenFiles
|
|
22647
|
+
};
|
|
22648
|
+
}
|
|
22649
|
+
function localHelloResult(action, session, extras) {
|
|
22650
|
+
const prepared = ensureSessionContractIntelligence(session);
|
|
22651
|
+
const scopeSource = prepared.agentId === "local" ? "user_start" : "agent_hello";
|
|
22652
|
+
const checklist = buildLocalHelloPayload(prepared);
|
|
22653
|
+
return toolJson({
|
|
22654
|
+
mode: "local",
|
|
22655
|
+
action,
|
|
22656
|
+
contract_id: prepared.id,
|
|
22657
|
+
intent: prepared.intent ?? null,
|
|
22658
|
+
scope_source: scopeSource,
|
|
22659
|
+
status: prepared.status,
|
|
22660
|
+
next_action: "Contract declared. Start implementation now; agentbridge watch will track this work contract.",
|
|
22661
|
+
...checklist,
|
|
22662
|
+
...extras ?? {}
|
|
22663
|
+
});
|
|
22664
|
+
}
|
|
22138
22665
|
function formatHttpFailure(path, status, text, json) {
|
|
22139
22666
|
if (json && typeof json === "object" && "error" in json) {
|
|
22140
22667
|
return `AgentBridge ${path} returned ${status}: ${JSON.stringify(json.error)}`;
|
|
@@ -22227,18 +22754,41 @@ async function main() {
|
|
|
22227
22754
|
async (args) => {
|
|
22228
22755
|
if (cfg.localOnly) {
|
|
22229
22756
|
const existing = readSessionState();
|
|
22757
|
+
const declaredIntent = args.intent?.trim() || args.note?.trim();
|
|
22230
22758
|
if (isActiveLocalSession(existing)) {
|
|
22231
|
-
|
|
22232
|
-
|
|
22233
|
-
|
|
22234
|
-
|
|
22235
|
-
|
|
22759
|
+
if (existing.agentId === "local") {
|
|
22760
|
+
return localHelloResult("reuse", existing, {
|
|
22761
|
+
scope_locked: true
|
|
22762
|
+
});
|
|
22763
|
+
}
|
|
22764
|
+
const currentIntent = existing.intent?.trim();
|
|
22765
|
+
if (!declaredIntent || declaredIntent === currentIntent) {
|
|
22766
|
+
return localHelloResult("reuse", existing);
|
|
22767
|
+
}
|
|
22768
|
+
const canReplace = existing.changedFiles.length === 0 && existing.crossings.length === 0 && existing.approvals.length === 0;
|
|
22769
|
+
if (!canReplace) {
|
|
22770
|
+
return toolError(
|
|
22771
|
+
`A different AgentBridge contract is already active.
|
|
22772
|
+
|
|
22773
|
+
Current contract: ${currentIntent ?? "(unknown intent)"}
|
|
22774
|
+
Close the current contract in watch, then call agent_hello again with your new intent.`
|
|
22775
|
+
);
|
|
22776
|
+
}
|
|
22777
|
+
clearSessionState();
|
|
22778
|
+
const replaced = openLocalSession({
|
|
22779
|
+
agentId: "mcp",
|
|
22780
|
+
laneDomain: null,
|
|
22781
|
+
intent: declaredIntent,
|
|
22782
|
+
domains: [],
|
|
22783
|
+
mode: "local_supervision"
|
|
22784
|
+
});
|
|
22785
|
+
return localHelloResult("replaced", replaced, {
|
|
22786
|
+
replaced_contract_id: existing.id
|
|
22236
22787
|
});
|
|
22237
22788
|
}
|
|
22238
|
-
const declaredIntent = args.intent?.trim() || args.note?.trim();
|
|
22239
22789
|
if (!declaredIntent || isVagueIntent(declaredIntent)) {
|
|
22240
22790
|
return toolError(
|
|
22241
|
-
'No active AgentBridge contract.\n\
|
|
22791
|
+
'No active AgentBridge contract.\n\nAgent must declare a concrete scope before editing files:\n agent_hello({ intent: "Fix auth 401 on /rooms endpoint" })\n\nOr run in a terminal: agentbridge start "Fix auth 401 on /rooms endpoint"'
|
|
22242
22792
|
);
|
|
22243
22793
|
}
|
|
22244
22794
|
const session = openLocalSession({
|
|
@@ -22248,12 +22798,7 @@ async function main() {
|
|
|
22248
22798
|
domains: [],
|
|
22249
22799
|
mode: "local_supervision"
|
|
22250
22800
|
});
|
|
22251
|
-
return
|
|
22252
|
-
mode: "local",
|
|
22253
|
-
action: "created",
|
|
22254
|
-
contract: session,
|
|
22255
|
-
message: "Local work contract created."
|
|
22256
|
-
});
|
|
22801
|
+
return localHelloResult("created", session);
|
|
22257
22802
|
}
|
|
22258
22803
|
const resolvedProjectId = args.project_id ?? cfg.projectId;
|
|
22259
22804
|
if (!resolvedProjectId) {
|
|
@@ -22271,7 +22816,20 @@ async function main() {
|
|
|
22271
22816
|
const res = await bridgeJson(cfg, "POST", path, body);
|
|
22272
22817
|
if (!res.ok)
|
|
22273
22818
|
return toolError(formatHttpFailure(path, res.status, res.text, res.json));
|
|
22274
|
-
|
|
22819
|
+
if (!needsRulesAutoInstall(res.json)) {
|
|
22820
|
+
return toolJson(res.json);
|
|
22821
|
+
}
|
|
22822
|
+
const autoRulesInstall = await autoInstallRulesForProject(cfg, resolvedProjectId);
|
|
22823
|
+
if (isRecord2(res.json)) {
|
|
22824
|
+
return toolJson({
|
|
22825
|
+
...res.json,
|
|
22826
|
+
auto_rules_install: autoRulesInstall
|
|
22827
|
+
});
|
|
22828
|
+
}
|
|
22829
|
+
return toolJson({
|
|
22830
|
+
hello: res.json,
|
|
22831
|
+
auto_rules_install: autoRulesInstall
|
|
22832
|
+
});
|
|
22275
22833
|
}
|
|
22276
22834
|
);
|
|
22277
22835
|
server.registerTool(
|