@agentbridge1/cli 0.0.8 → 0.0.10
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 +86 -52
- package/dist/contract-intelligence.js +597 -0
- package/dist/contract-verdict.js +79 -26
- package/dist/diff-reader.js +200 -0
- package/dist/git-status.js +4 -1
- package/dist/intent-parser.js +178 -0
- package/dist/local-proof.js +5 -0
- package/dist/mcp/agentbridge-mcp.js +591 -28
- package/dist/mcp/agentbridge-mcp.js.map +4 -4
- package/dist/proof-parser.js +118 -0
- package/dist/session-state.js +20 -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");
|
|
@@ -21064,6 +21205,9 @@ function normalizePath2(path) {
|
|
|
21064
21205
|
function isProofNoiseFile(file) {
|
|
21065
21206
|
const normalized = normalizePath2(file);
|
|
21066
21207
|
const lower = normalized.toLowerCase();
|
|
21208
|
+
if (lower === ".agentbridge" || lower.endsWith("/.agentbridge") || lower.includes(".agentbridge/")) {
|
|
21209
|
+
return true;
|
|
21210
|
+
}
|
|
21067
21211
|
if (lower === "agentbridge.md" || lower === ".cursor" || lower.startsWith(".cursor/")) {
|
|
21068
21212
|
return true;
|
|
21069
21213
|
}
|
|
@@ -21175,6 +21319,15 @@ function isLocalSessionState(value) {
|
|
|
21175
21319
|
if (value.updatedAt !== void 0 && typeof value.updatedAt !== "string") return false;
|
|
21176
21320
|
if (value.closedAt !== void 0 && typeof value.closedAt !== "string") return false;
|
|
21177
21321
|
if (value.claimedPaths !== void 0 && !isStringArray(value.claimedPaths)) return false;
|
|
21322
|
+
if (value.createdBy !== void 0 && value.createdBy !== "user_start" && value.createdBy !== "agent_hello") {
|
|
21323
|
+
return false;
|
|
21324
|
+
}
|
|
21325
|
+
if (value.contractProfiles !== void 0 && !isStringArray(value.contractProfiles)) return false;
|
|
21326
|
+
if (value.expectedSurfaces !== void 0 && !isStringArray(value.expectedSurfaces)) return false;
|
|
21327
|
+
if (value.expectedFileAreas !== void 0 && !isStringArray(value.expectedFileAreas)) return false;
|
|
21328
|
+
if (value.completionCriteria !== void 0 && !isStringArray(value.completionCriteria)) return false;
|
|
21329
|
+
if (value.proofNeeded !== void 0 && !isStringArray(value.proofNeeded)) return false;
|
|
21330
|
+
if (value.riskyOmissions !== void 0 && !isStringArray(value.riskyOmissions)) return false;
|
|
21178
21331
|
if (value.lastLocalVerificationRun !== void 0 && !isLocalVerificationRun(value.lastLocalVerificationRun)) {
|
|
21179
21332
|
return false;
|
|
21180
21333
|
}
|
|
@@ -21243,6 +21396,296 @@ function writeSessionState(state) {
|
|
|
21243
21396
|
}
|
|
21244
21397
|
(0, import_node_fs2.renameSync)(tempPath, path);
|
|
21245
21398
|
}
|
|
21399
|
+
function clearSessionState() {
|
|
21400
|
+
writeSessionState({
|
|
21401
|
+
id: "none",
|
|
21402
|
+
agentId: "none",
|
|
21403
|
+
laneDomain: null,
|
|
21404
|
+
status: "closed",
|
|
21405
|
+
closeReason: "completed",
|
|
21406
|
+
changedFiles: [],
|
|
21407
|
+
crossings: [],
|
|
21408
|
+
approvals: [],
|
|
21409
|
+
domains: [],
|
|
21410
|
+
createdAt: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
21411
|
+
});
|
|
21412
|
+
}
|
|
21413
|
+
|
|
21414
|
+
// src/contract-intelligence.ts
|
|
21415
|
+
var MCP_RULE_PROFILE = "mcp_rules_config_install";
|
|
21416
|
+
var AUTH_PROFILE = "auth_login_session";
|
|
21417
|
+
var DB_PROFILE = "database_schema_migration";
|
|
21418
|
+
var UI_PROFILE = "ui_style_copy";
|
|
21419
|
+
var API_PROFILE = "api_endpoint";
|
|
21420
|
+
var TEST_PROFILE = "tests";
|
|
21421
|
+
var PAYMENTS_PROFILE = "payments_webhooks";
|
|
21422
|
+
var GENERIC_PROFILE = "generic";
|
|
21423
|
+
function unique(values) {
|
|
21424
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
21425
|
+
}
|
|
21426
|
+
function matchIntent(intent, keywords) {
|
|
21427
|
+
const lower = intent.toLowerCase();
|
|
21428
|
+
return keywords.some((keyword) => lower.includes(keyword));
|
|
21429
|
+
}
|
|
21430
|
+
function detectProfiles(intent) {
|
|
21431
|
+
const profiles = [];
|
|
21432
|
+
if (matchIntent(intent, ["mcp"]) && matchIntent(intent, ["rule", "rules", "install", "setup", "config", "configuration"])) {
|
|
21433
|
+
profiles.push(MCP_RULE_PROFILE);
|
|
21434
|
+
}
|
|
21435
|
+
if (matchIntent(intent, ["auth", "login", "session", "token", "oauth"])) {
|
|
21436
|
+
profiles.push(AUTH_PROFILE);
|
|
21437
|
+
}
|
|
21438
|
+
if (matchIntent(intent, ["database", "db", "schema", "migration", "prisma", "sql"])) {
|
|
21439
|
+
profiles.push(DB_PROFILE);
|
|
21440
|
+
}
|
|
21441
|
+
if (matchIntent(intent, ["ui", "style", "css", "copy", "layout", "component"])) {
|
|
21442
|
+
profiles.push(UI_PROFILE);
|
|
21443
|
+
}
|
|
21444
|
+
if (matchIntent(intent, ["api", "endpoint", "route", "handler", "controller"])) {
|
|
21445
|
+
profiles.push(API_PROFILE);
|
|
21446
|
+
}
|
|
21447
|
+
if (matchIntent(intent, ["test", "tests", "vitest", "jest", "proof"])) {
|
|
21448
|
+
profiles.push(TEST_PROFILE);
|
|
21449
|
+
}
|
|
21450
|
+
if (matchIntent(intent, ["payment", "payments", "billing", "stripe", "webhook"])) {
|
|
21451
|
+
profiles.push(PAYMENTS_PROFILE);
|
|
21452
|
+
}
|
|
21453
|
+
return profiles.length > 0 ? profiles : [GENERIC_PROFILE];
|
|
21454
|
+
}
|
|
21455
|
+
function profileBlueprint(profile) {
|
|
21456
|
+
switch (profile) {
|
|
21457
|
+
case MCP_RULE_PROFILE:
|
|
21458
|
+
return {
|
|
21459
|
+
expectedSurfaces: ["mcp", "rules_installation", "configuration_flow", "tests_or_manual_proof"],
|
|
21460
|
+
expectedFileAreas: [
|
|
21461
|
+
"mcp/**",
|
|
21462
|
+
"mcp/agentbridge-mcp.ts",
|
|
21463
|
+
"AGENTBRIDGE.md",
|
|
21464
|
+
".cursor/rules/**",
|
|
21465
|
+
"cli/src/mcp-config.ts",
|
|
21466
|
+
"cli/src/commands/setup-mcp.ts"
|
|
21467
|
+
],
|
|
21468
|
+
completionCriteria: [
|
|
21469
|
+
"MCP configuration path triggers AgentBridge rule installation.",
|
|
21470
|
+
"Rules are created or updated in the expected Cursor rules location.",
|
|
21471
|
+
"Existing rules/config are preserved or safely updated.",
|
|
21472
|
+
"Re-running MCP configuration is idempotent and does not duplicate rules.",
|
|
21473
|
+
"Proof exists that MCP configuration causes rules to be installed."
|
|
21474
|
+
],
|
|
21475
|
+
proofNeeded: [
|
|
21476
|
+
"Run MCP setup/configuration flow in a clean repo.",
|
|
21477
|
+
"Confirm the AgentBridge Cursor rules file is created.",
|
|
21478
|
+
"Run setup/configuration again to confirm idempotency.",
|
|
21479
|
+
"Record test/manual proof output."
|
|
21480
|
+
],
|
|
21481
|
+
riskyOmissions: [
|
|
21482
|
+
"MCP server file changed but no install trigger wired to the configuration path.",
|
|
21483
|
+
"Rules are installed only in local mode or only in server mode.",
|
|
21484
|
+
"Existing Cursor rules are overwritten.",
|
|
21485
|
+
"No idempotency check.",
|
|
21486
|
+
"No proof that the auto-install behavior actually runs."
|
|
21487
|
+
],
|
|
21488
|
+
contractProfiles: [MCP_RULE_PROFILE]
|
|
21489
|
+
};
|
|
21490
|
+
case AUTH_PROFILE:
|
|
21491
|
+
return {
|
|
21492
|
+
expectedSurfaces: ["auth", "session", "tests_or_manual_proof"],
|
|
21493
|
+
expectedFileAreas: ["auth/**", "src/**/auth/**", "src/**/session/**", "middleware/**"],
|
|
21494
|
+
completionCriteria: [
|
|
21495
|
+
"Authentication/session flow handling is updated where intended.",
|
|
21496
|
+
"Authorization boundaries remain explicit and unchanged outside scope.",
|
|
21497
|
+
"Proof exists for the auth/session behavior change."
|
|
21498
|
+
],
|
|
21499
|
+
proofNeeded: ["Run auth/session flow tests or a reproducible manual proof."],
|
|
21500
|
+
riskyOmissions: [
|
|
21501
|
+
"Auth logic changed without session or middleware checks.",
|
|
21502
|
+
"No proof of login/session behavior."
|
|
21503
|
+
],
|
|
21504
|
+
contractProfiles: [AUTH_PROFILE]
|
|
21505
|
+
};
|
|
21506
|
+
case DB_PROFILE:
|
|
21507
|
+
return {
|
|
21508
|
+
expectedSurfaces: ["database", "schema_migration", "tests_or_manual_proof"],
|
|
21509
|
+
expectedFileAreas: ["prisma/**", "migrations/**", "src/**/db/**", "src/**/database/**"],
|
|
21510
|
+
completionCriteria: [
|
|
21511
|
+
"Schema/data-layer changes are applied in intended files.",
|
|
21512
|
+
"Migration or compatibility impact is accounted for.",
|
|
21513
|
+
"Proof exists for migration/query behavior."
|
|
21514
|
+
],
|
|
21515
|
+
proofNeeded: ["Run migration/database verification command and capture output."],
|
|
21516
|
+
riskyOmissions: [
|
|
21517
|
+
"Schema changed without migration/compatibility proof.",
|
|
21518
|
+
"No evidence of migration/query validation."
|
|
21519
|
+
],
|
|
21520
|
+
contractProfiles: [DB_PROFILE]
|
|
21521
|
+
};
|
|
21522
|
+
case UI_PROFILE:
|
|
21523
|
+
return {
|
|
21524
|
+
expectedSurfaces: ["ui", "copy_or_style", "tests_or_manual_proof"],
|
|
21525
|
+
expectedFileAreas: ["src/**/components/**", "src/**/pages/**", "src/**/*.css", "src/**/*.html"],
|
|
21526
|
+
completionCriteria: [
|
|
21527
|
+
"UI/copy/style surface for the contract is updated.",
|
|
21528
|
+
"Unrelated UI areas are not changed unintentionally.",
|
|
21529
|
+
"Proof exists for the visible behavior change."
|
|
21530
|
+
],
|
|
21531
|
+
proofNeeded: ["Record manual verification steps (or visual/tests) for UI outcome."],
|
|
21532
|
+
riskyOmissions: [
|
|
21533
|
+
"UI files changed without a clear visible proof.",
|
|
21534
|
+
"Broad style changes without scope evidence."
|
|
21535
|
+
],
|
|
21536
|
+
contractProfiles: [UI_PROFILE]
|
|
21537
|
+
};
|
|
21538
|
+
case API_PROFILE:
|
|
21539
|
+
return {
|
|
21540
|
+
expectedSurfaces: ["api", "endpoint_logic", "tests_or_manual_proof"],
|
|
21541
|
+
expectedFileAreas: ["src/**/routes/**", "src/**/api/**", "src/**/controllers/**"],
|
|
21542
|
+
completionCriteria: [
|
|
21543
|
+
"Target API/endpoint behavior is changed in the correct surface.",
|
|
21544
|
+
"Request/response behavior is evidenced.",
|
|
21545
|
+
"Proof exists for endpoint behavior."
|
|
21546
|
+
],
|
|
21547
|
+
proofNeeded: ["Run endpoint tests or reproducible request/response proof."],
|
|
21548
|
+
riskyOmissions: [
|
|
21549
|
+
"Endpoint files changed without request/response evidence.",
|
|
21550
|
+
"No proof for API behavior change."
|
|
21551
|
+
],
|
|
21552
|
+
contractProfiles: [API_PROFILE]
|
|
21553
|
+
};
|
|
21554
|
+
case TEST_PROFILE:
|
|
21555
|
+
return {
|
|
21556
|
+
expectedSurfaces: ["tests", "proof"],
|
|
21557
|
+
expectedFileAreas: ["**/*.test.ts", "**/*.spec.ts", "tests/**"],
|
|
21558
|
+
completionCriteria: [
|
|
21559
|
+
"Test/proof artifacts relevant to the contract are updated.",
|
|
21560
|
+
"Test execution evidence is recorded."
|
|
21561
|
+
],
|
|
21562
|
+
proofNeeded: ["Run tests and record command + result output."],
|
|
21563
|
+
riskyOmissions: ["Tests changed but no execution proof recorded."],
|
|
21564
|
+
contractProfiles: [TEST_PROFILE]
|
|
21565
|
+
};
|
|
21566
|
+
case PAYMENTS_PROFILE:
|
|
21567
|
+
return {
|
|
21568
|
+
expectedSurfaces: ["payments", "webhooks", "tests_or_manual_proof"],
|
|
21569
|
+
expectedFileAreas: ["src/**/billing/**", "src/**/payments/**", "src/**/webhooks/**"],
|
|
21570
|
+
completionCriteria: [
|
|
21571
|
+
"Payments/webhook handling logic is updated in scope.",
|
|
21572
|
+
"Critical payment side effects are evidenced.",
|
|
21573
|
+
"Proof exists for payment/webhook behavior."
|
|
21574
|
+
],
|
|
21575
|
+
proofNeeded: ["Run payment/webhook verification flow and capture output."],
|
|
21576
|
+
riskyOmissions: [
|
|
21577
|
+
"Webhook/payment logic changed without behavior proof.",
|
|
21578
|
+
"No idempotency/effect validation for financial flows."
|
|
21579
|
+
],
|
|
21580
|
+
contractProfiles: [PAYMENTS_PROFILE]
|
|
21581
|
+
};
|
|
21582
|
+
default:
|
|
21583
|
+
return {
|
|
21584
|
+
expectedSurfaces: ["implementation_surface", "tests_or_manual_proof"],
|
|
21585
|
+
expectedFileAreas: ["**"],
|
|
21586
|
+
completionCriteria: [
|
|
21587
|
+
"Files changed align with the declared contract intent.",
|
|
21588
|
+
"Proof exists for the intended behavior change."
|
|
21589
|
+
],
|
|
21590
|
+
proofNeeded: ["Run relevant tests or provide manual proof output."],
|
|
21591
|
+
riskyOmissions: ["Code changed without proof linked to the declared intent."],
|
|
21592
|
+
contractProfiles: [GENERIC_PROFILE]
|
|
21593
|
+
};
|
|
21594
|
+
}
|
|
21595
|
+
}
|
|
21596
|
+
function buildContractIntelligence(intent, createdBy) {
|
|
21597
|
+
const normalizedIntent = intent?.trim() ?? "";
|
|
21598
|
+
const profiles = detectProfiles(normalizedIntent);
|
|
21599
|
+
const combined = profiles.map((profile) => profileBlueprint(profile));
|
|
21600
|
+
const baseCompletionCriteria = unique(combined.flatMap((item) => item.completionCriteria));
|
|
21601
|
+
const parsed = parseIntent(normalizedIntent);
|
|
21602
|
+
const taskCriteria = buildTaskSpecificCriteria(parsed);
|
|
21603
|
+
const firstTask = taskCriteria[0];
|
|
21604
|
+
const lastTask = taskCriteria[1];
|
|
21605
|
+
const completionCriteria = unique([
|
|
21606
|
+
...firstTask ? [firstTask] : [],
|
|
21607
|
+
...baseCompletionCriteria.filter((c) => !c.toLowerCase().startsWith("proof")),
|
|
21608
|
+
...lastTask ? [lastTask] : [],
|
|
21609
|
+
...baseCompletionCriteria.filter((c) => c.toLowerCase().startsWith("proof"))
|
|
21610
|
+
]);
|
|
21611
|
+
return {
|
|
21612
|
+
expectedSurfaces: unique(combined.flatMap((item) => item.expectedSurfaces)),
|
|
21613
|
+
expectedFileAreas: unique(combined.flatMap((item) => item.expectedFileAreas)),
|
|
21614
|
+
completionCriteria,
|
|
21615
|
+
proofNeeded: unique(combined.flatMap((item) => item.proofNeeded)),
|
|
21616
|
+
riskyOmissions: unique(combined.flatMap((item) => item.riskyOmissions)),
|
|
21617
|
+
contractProfiles: unique(combined.flatMap((item) => item.contractProfiles)),
|
|
21618
|
+
createdBy
|
|
21619
|
+
};
|
|
21620
|
+
}
|
|
21621
|
+
function localSessionToContractIntelligence(session) {
|
|
21622
|
+
if (session.completionCriteria?.length && session.contractProfiles?.length) {
|
|
21623
|
+
return {
|
|
21624
|
+
contractProfiles: session.contractProfiles,
|
|
21625
|
+
completionCriteria: session.completionCriteria,
|
|
21626
|
+
proofNeeded: session.proofNeeded ?? [],
|
|
21627
|
+
riskyOmissions: session.riskyOmissions ?? [],
|
|
21628
|
+
expectedSurfaces: session.expectedSurfaces ?? [],
|
|
21629
|
+
expectedFileAreas: session.expectedFileAreas ?? [],
|
|
21630
|
+
createdBy: session.createdBy ?? "agent_hello"
|
|
21631
|
+
};
|
|
21632
|
+
}
|
|
21633
|
+
return buildContractIntelligence(session.intent, session.createdBy ?? "agent_hello");
|
|
21634
|
+
}
|
|
21635
|
+
function sessionNeedsContractBackfill(session) {
|
|
21636
|
+
return !session.completionCriteria?.length || !session.contractProfiles?.length;
|
|
21637
|
+
}
|
|
21638
|
+
function ensureSessionContractIntelligence(session) {
|
|
21639
|
+
if (!sessionNeedsContractBackfill(session)) {
|
|
21640
|
+
return session;
|
|
21641
|
+
}
|
|
21642
|
+
const createdBy = session.createdBy ?? (session.agentId?.trim() === "local" ? "user_start" : "agent_hello");
|
|
21643
|
+
const contract = buildContractIntelligence(session.intent?.trim(), createdBy);
|
|
21644
|
+
const updated = {
|
|
21645
|
+
...session,
|
|
21646
|
+
createdBy,
|
|
21647
|
+
contractProfiles: contract.contractProfiles,
|
|
21648
|
+
expectedSurfaces: contract.expectedSurfaces,
|
|
21649
|
+
expectedFileAreas: contract.expectedFileAreas,
|
|
21650
|
+
completionCriteria: contract.completionCriteria,
|
|
21651
|
+
proofNeeded: contract.proofNeeded,
|
|
21652
|
+
riskyOmissions: contract.riskyOmissions
|
|
21653
|
+
};
|
|
21654
|
+
writeSessionState(updated);
|
|
21655
|
+
return updated;
|
|
21656
|
+
}
|
|
21657
|
+
function buildProofRequiredCommands(contract) {
|
|
21658
|
+
if (contract.contractProfiles.includes(MCP_RULE_PROFILE)) {
|
|
21659
|
+
return [
|
|
21660
|
+
"agentbridge verify npm run setup-mcp -- --local",
|
|
21661
|
+
"agentbridge verify npm run setup-mcp -- --local (run again to confirm idempotency)"
|
|
21662
|
+
];
|
|
21663
|
+
}
|
|
21664
|
+
if (contract.contractProfiles.includes(DB_PROFILE)) {
|
|
21665
|
+
return [
|
|
21666
|
+
"agentbridge verify npx prisma migrate status",
|
|
21667
|
+
"agentbridge verify npm test"
|
|
21668
|
+
];
|
|
21669
|
+
}
|
|
21670
|
+
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)) {
|
|
21671
|
+
return ["agentbridge verify npm test"];
|
|
21672
|
+
}
|
|
21673
|
+
return ["agentbridge verify npm test"];
|
|
21674
|
+
}
|
|
21675
|
+
function buildLocalHelloPayload(session) {
|
|
21676
|
+
const contract = localSessionToContractIntelligence(session);
|
|
21677
|
+
const scopeSource = session.createdBy ?? (session.agentId?.trim() === "local" ? "user_start" : "agent_hello");
|
|
21678
|
+
return {
|
|
21679
|
+
contract: {
|
|
21680
|
+
id: session.id,
|
|
21681
|
+
intent: session.intent?.trim() ?? null,
|
|
21682
|
+
created_by: scopeSource
|
|
21683
|
+
},
|
|
21684
|
+
done_checklist: contract.completionCriteria.slice(0, 4),
|
|
21685
|
+
proof_required: buildProofRequiredCommands(contract),
|
|
21686
|
+
warnings: contract.riskyOmissions.slice(0, 2)
|
|
21687
|
+
};
|
|
21688
|
+
}
|
|
21246
21689
|
|
|
21247
21690
|
// src/git-status.ts
|
|
21248
21691
|
var import_node_child_process = require("node:child_process");
|
|
@@ -21251,7 +21694,9 @@ function normalizePath3(path) {
|
|
|
21251
21694
|
}
|
|
21252
21695
|
function isAgentbridgeLocalPath(path) {
|
|
21253
21696
|
const normalized = normalizePath3(path);
|
|
21254
|
-
|
|
21697
|
+
const lower = normalized.toLowerCase();
|
|
21698
|
+
if (lower === ".agentbridge" || lower.endsWith("/.agentbridge")) return true;
|
|
21699
|
+
return lower.includes(".agentbridge/");
|
|
21255
21700
|
}
|
|
21256
21701
|
function isRenameOrCopy(xy) {
|
|
21257
21702
|
return xy.includes("R") || xy.includes("C");
|
|
@@ -21340,11 +21785,20 @@ function openLocalSession(input) {
|
|
|
21340
21785
|
const claimedPaths = [...new Set((input.claimedPaths ?? []).map((path) => path.trim()).filter(Boolean))];
|
|
21341
21786
|
const baseline = captureLocalSessionBaseline();
|
|
21342
21787
|
const now = baseline.startedAt;
|
|
21788
|
+
const createdBy = input.createdBy ?? (input.agentId?.trim() === "local" ? "user_start" : "agent_hello");
|
|
21789
|
+
const contract = buildContractIntelligence(input.intent?.trim(), createdBy);
|
|
21343
21790
|
const state = {
|
|
21344
21791
|
id: `local_${Date.now().toString(36)}`,
|
|
21345
21792
|
agentId: input.agentId?.trim() || "local",
|
|
21346
21793
|
laneDomain: input.laneDomain,
|
|
21347
21794
|
intent: input.intent?.trim() || void 0,
|
|
21795
|
+
createdBy,
|
|
21796
|
+
contractProfiles: contract.contractProfiles,
|
|
21797
|
+
expectedSurfaces: contract.expectedSurfaces,
|
|
21798
|
+
expectedFileAreas: contract.expectedFileAreas,
|
|
21799
|
+
completionCriteria: contract.completionCriteria,
|
|
21800
|
+
proofNeeded: contract.proofNeeded,
|
|
21801
|
+
riskyOmissions: contract.riskyOmissions,
|
|
21348
21802
|
mode: input.mode,
|
|
21349
21803
|
changeRequestId: input.changeRequestId,
|
|
21350
21804
|
claimedPaths,
|
|
@@ -22135,6 +22589,84 @@ function toolJson(data) {
|
|
|
22135
22589
|
]
|
|
22136
22590
|
};
|
|
22137
22591
|
}
|
|
22592
|
+
function isRecord2(value) {
|
|
22593
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22594
|
+
}
|
|
22595
|
+
function needsRulesAutoInstall(hello) {
|
|
22596
|
+
return isRecord2(hello) && hello.rules_status === "not_installed";
|
|
22597
|
+
}
|
|
22598
|
+
function formatUnknownError(err) {
|
|
22599
|
+
if (err instanceof Error) return err.message;
|
|
22600
|
+
return String(err);
|
|
22601
|
+
}
|
|
22602
|
+
async function autoInstallRulesForProject(cfg, projectId) {
|
|
22603
|
+
const installPath = `/v1/dev/projects/${encodeURIComponent(projectId)}/rules`;
|
|
22604
|
+
const installRes = await bridgeJson(cfg, "GET", installPath);
|
|
22605
|
+
if (!installRes.ok) {
|
|
22606
|
+
return {
|
|
22607
|
+
status: "failed",
|
|
22608
|
+
step: "install_agentbridge_rules",
|
|
22609
|
+
error: formatHttpFailure(installPath, installRes.status, installRes.text, installRes.json)
|
|
22610
|
+
};
|
|
22611
|
+
}
|
|
22612
|
+
if (!isRecord2(installRes.json) || !Array.isArray(installRes.json.files)) {
|
|
22613
|
+
return {
|
|
22614
|
+
status: "failed",
|
|
22615
|
+
step: "install_agentbridge_rules",
|
|
22616
|
+
error: "Rules payload is missing a valid files[] list."
|
|
22617
|
+
};
|
|
22618
|
+
}
|
|
22619
|
+
const repoRoot = process.env.AGENTBRIDGE_REPO_ROOT?.trim() || process.cwd();
|
|
22620
|
+
const writtenFiles = [];
|
|
22621
|
+
try {
|
|
22622
|
+
for (const file of installRes.json.files) {
|
|
22623
|
+
if (!isRecord2(file) || typeof file.path !== "string" || typeof file.content !== "string") {
|
|
22624
|
+
throw new Error("Invalid rules file entry in server response.");
|
|
22625
|
+
}
|
|
22626
|
+
const absolutePath = (0, import_node_path2.resolve)(repoRoot, file.path);
|
|
22627
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path2.dirname)(absolutePath), { recursive: true });
|
|
22628
|
+
(0, import_node_fs3.writeFileSync)(absolutePath, `${file.content}
|
|
22629
|
+
`, "utf8");
|
|
22630
|
+
writtenFiles.push(file.path);
|
|
22631
|
+
}
|
|
22632
|
+
} catch (err) {
|
|
22633
|
+
return {
|
|
22634
|
+
status: "failed",
|
|
22635
|
+
step: "write_rules_files",
|
|
22636
|
+
error: formatUnknownError(err)
|
|
22637
|
+
};
|
|
22638
|
+
}
|
|
22639
|
+
const markPath = `/v1/dev/projects/${encodeURIComponent(projectId)}/rules/mark-installed`;
|
|
22640
|
+
const markRes = await bridgeJson(cfg, "POST", markPath, {});
|
|
22641
|
+
if (!markRes.ok) {
|
|
22642
|
+
return {
|
|
22643
|
+
status: "failed",
|
|
22644
|
+
step: "mark_rules_installed",
|
|
22645
|
+
error: formatHttpFailure(markPath, markRes.status, markRes.text, markRes.json)
|
|
22646
|
+
};
|
|
22647
|
+
}
|
|
22648
|
+
return {
|
|
22649
|
+
status: "installed",
|
|
22650
|
+
repo_root: repoRoot,
|
|
22651
|
+
written_files: writtenFiles
|
|
22652
|
+
};
|
|
22653
|
+
}
|
|
22654
|
+
function localHelloResult(action, session, extras) {
|
|
22655
|
+
const prepared = ensureSessionContractIntelligence(session);
|
|
22656
|
+
const scopeSource = prepared.agentId === "local" ? "user_start" : "agent_hello";
|
|
22657
|
+
const checklist = buildLocalHelloPayload(prepared);
|
|
22658
|
+
return toolJson({
|
|
22659
|
+
mode: "local",
|
|
22660
|
+
action,
|
|
22661
|
+
contract_id: prepared.id,
|
|
22662
|
+
intent: prepared.intent ?? null,
|
|
22663
|
+
scope_source: scopeSource,
|
|
22664
|
+
status: prepared.status,
|
|
22665
|
+
next_action: "Contract declared. Start implementation now; agentbridge watch will track this work contract.",
|
|
22666
|
+
...checklist,
|
|
22667
|
+
...extras ?? {}
|
|
22668
|
+
});
|
|
22669
|
+
}
|
|
22138
22670
|
function formatHttpFailure(path, status, text, json) {
|
|
22139
22671
|
if (json && typeof json === "object" && "error" in json) {
|
|
22140
22672
|
return `AgentBridge ${path} returned ${status}: ${JSON.stringify(json.error)}`;
|
|
@@ -22227,18 +22759,41 @@ async function main() {
|
|
|
22227
22759
|
async (args) => {
|
|
22228
22760
|
if (cfg.localOnly) {
|
|
22229
22761
|
const existing = readSessionState();
|
|
22762
|
+
const declaredIntent = args.intent?.trim() || args.note?.trim();
|
|
22230
22763
|
if (isActiveLocalSession(existing)) {
|
|
22231
|
-
|
|
22232
|
-
|
|
22233
|
-
|
|
22234
|
-
|
|
22235
|
-
|
|
22764
|
+
if (existing.agentId === "local") {
|
|
22765
|
+
return localHelloResult("reuse", existing, {
|
|
22766
|
+
scope_locked: true
|
|
22767
|
+
});
|
|
22768
|
+
}
|
|
22769
|
+
const currentIntent = existing.intent?.trim();
|
|
22770
|
+
if (!declaredIntent || declaredIntent === currentIntent) {
|
|
22771
|
+
return localHelloResult("reuse", existing);
|
|
22772
|
+
}
|
|
22773
|
+
const canReplace = existing.changedFiles.length === 0 && existing.crossings.length === 0 && existing.approvals.length === 0;
|
|
22774
|
+
if (!canReplace) {
|
|
22775
|
+
return toolError(
|
|
22776
|
+
`A different AgentBridge contract is already active.
|
|
22777
|
+
|
|
22778
|
+
Current contract: ${currentIntent ?? "(unknown intent)"}
|
|
22779
|
+
Close the current contract in watch, then call agent_hello again with your new intent.`
|
|
22780
|
+
);
|
|
22781
|
+
}
|
|
22782
|
+
clearSessionState();
|
|
22783
|
+
const replaced = openLocalSession({
|
|
22784
|
+
agentId: "mcp",
|
|
22785
|
+
laneDomain: null,
|
|
22786
|
+
intent: declaredIntent,
|
|
22787
|
+
domains: [],
|
|
22788
|
+
mode: "local_supervision"
|
|
22789
|
+
});
|
|
22790
|
+
return localHelloResult("replaced", replaced, {
|
|
22791
|
+
replaced_contract_id: existing.id
|
|
22236
22792
|
});
|
|
22237
22793
|
}
|
|
22238
|
-
const declaredIntent = args.intent?.trim() || args.note?.trim();
|
|
22239
22794
|
if (!declaredIntent || isVagueIntent(declaredIntent)) {
|
|
22240
22795
|
return toolError(
|
|
22241
|
-
'No active AgentBridge contract.\n\
|
|
22796
|
+
'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
22797
|
);
|
|
22243
22798
|
}
|
|
22244
22799
|
const session = openLocalSession({
|
|
@@ -22248,12 +22803,7 @@ async function main() {
|
|
|
22248
22803
|
domains: [],
|
|
22249
22804
|
mode: "local_supervision"
|
|
22250
22805
|
});
|
|
22251
|
-
return
|
|
22252
|
-
mode: "local",
|
|
22253
|
-
action: "created",
|
|
22254
|
-
contract: session,
|
|
22255
|
-
message: "Local work contract created."
|
|
22256
|
-
});
|
|
22806
|
+
return localHelloResult("created", session);
|
|
22257
22807
|
}
|
|
22258
22808
|
const resolvedProjectId = args.project_id ?? cfg.projectId;
|
|
22259
22809
|
if (!resolvedProjectId) {
|
|
@@ -22271,7 +22821,20 @@ async function main() {
|
|
|
22271
22821
|
const res = await bridgeJson(cfg, "POST", path, body);
|
|
22272
22822
|
if (!res.ok)
|
|
22273
22823
|
return toolError(formatHttpFailure(path, res.status, res.text, res.json));
|
|
22274
|
-
|
|
22824
|
+
if (!needsRulesAutoInstall(res.json)) {
|
|
22825
|
+
return toolJson(res.json);
|
|
22826
|
+
}
|
|
22827
|
+
const autoRulesInstall = await autoInstallRulesForProject(cfg, resolvedProjectId);
|
|
22828
|
+
if (isRecord2(res.json)) {
|
|
22829
|
+
return toolJson({
|
|
22830
|
+
...res.json,
|
|
22831
|
+
auto_rules_install: autoRulesInstall
|
|
22832
|
+
});
|
|
22833
|
+
}
|
|
22834
|
+
return toolJson({
|
|
22835
|
+
hello: res.json,
|
|
22836
|
+
auto_rules_install: autoRulesInstall
|
|
22837
|
+
});
|
|
22275
22838
|
}
|
|
22276
22839
|
);
|
|
22277
22840
|
server.registerTool(
|