@agentbridge1/cli 0.0.6 → 0.0.8
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/connect.js +58 -119
- package/dist/commands/doctor.js +185 -58
- package/dist/commands/install-rules.js +64 -0
- package/dist/commands/recover.js +13 -2
- package/dist/commands/room.js +82 -0
- package/dist/commands/setup-mcp.js +54 -44
- package/dist/commands/start.js +85 -22
- package/dist/commands/watch.js +661 -92
- package/dist/config.js +31 -1
- package/dist/contract-verdict.js +186 -0
- package/dist/error-catalog.js +30 -1
- package/dist/git-status.js +6 -2
- package/dist/index.js +43 -5
- package/dist/init.js +10 -0
- package/dist/intent-validation.js +37 -0
- package/dist/local-proof.js +12 -4
- package/dist/mcp/agentbridge-mcp.js +602 -23
- package/dist/mcp/agentbridge-mcp.js.map +4 -4
- package/dist/mcp-config.js +64 -0
- package/dist/rules-sync.js +138 -0
- package/dist/supervision.js +191 -48
- package/dist/test-runner.js +201 -15
- package/package.json +1 -1
package/dist/config.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_API_BASE_URL = exports.CONFIG_PATH = exports.CONFIG_DIR = void 0;
|
|
3
|
+
exports.ROOM_CONNECTION_KEYS = exports.DEFAULT_API_BASE_URL = exports.CONFIG_PATH = exports.CONFIG_DIR = void 0;
|
|
4
4
|
exports.readConfig = readConfig;
|
|
5
5
|
exports.writeConfig = writeConfig;
|
|
6
6
|
exports.updateConfig = updateConfig;
|
|
7
|
+
exports.clearRoomConnection = clearRoomConnection;
|
|
7
8
|
exports.contextFromConfig = contextFromConfig;
|
|
8
9
|
const node_fs_1 = require("node:fs");
|
|
9
10
|
const node_path_1 = require("node:path");
|
|
@@ -30,6 +31,35 @@ function updateConfig(partial) {
|
|
|
30
31
|
writeConfig(next);
|
|
31
32
|
return next;
|
|
32
33
|
}
|
|
34
|
+
/** Config keys that bind this repo to a cloud room / execution surface. */
|
|
35
|
+
exports.ROOM_CONNECTION_KEYS = [
|
|
36
|
+
"projectId",
|
|
37
|
+
"apiKey",
|
|
38
|
+
"activeAgentId",
|
|
39
|
+
"executionSurfaceId",
|
|
40
|
+
"activeChangeRequestId",
|
|
41
|
+
"lastAcceptedSessionId",
|
|
42
|
+
"lastAcceptedAt",
|
|
43
|
+
];
|
|
44
|
+
function clearRoomConnection() {
|
|
45
|
+
const current = readConfig();
|
|
46
|
+
const clearedKeys = [];
|
|
47
|
+
const next = { ...current };
|
|
48
|
+
for (const key of exports.ROOM_CONNECTION_KEYS) {
|
|
49
|
+
if (next[key] !== undefined) {
|
|
50
|
+
clearedKeys.push(key);
|
|
51
|
+
delete next[key];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (clearedKeys.length > 0) {
|
|
55
|
+
writeConfig(next);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
clearedKeys,
|
|
59
|
+
previousProjectId: current.projectId,
|
|
60
|
+
hadApiKey: Boolean(current.apiKey),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
33
63
|
function contextFromConfig() {
|
|
34
64
|
const cfg = readConfig();
|
|
35
65
|
const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ??
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectOutOfScopeFiles = detectOutOfScopeFiles;
|
|
4
|
+
exports.renderContractVerdict = renderContractVerdict;
|
|
5
|
+
const domain_resolution_1 = require("./domain-resolution");
|
|
6
|
+
const local_proof_1 = require("./local-proof");
|
|
7
|
+
const INTENT_STOP_WORDS = new Set([
|
|
8
|
+
"a",
|
|
9
|
+
"an",
|
|
10
|
+
"the",
|
|
11
|
+
"on",
|
|
12
|
+
"in",
|
|
13
|
+
"to",
|
|
14
|
+
"for",
|
|
15
|
+
"and",
|
|
16
|
+
"or",
|
|
17
|
+
"of",
|
|
18
|
+
"fix",
|
|
19
|
+
"add",
|
|
20
|
+
"update",
|
|
21
|
+
"change",
|
|
22
|
+
"make",
|
|
23
|
+
"with",
|
|
24
|
+
"from",
|
|
25
|
+
"into",
|
|
26
|
+
"by",
|
|
27
|
+
"at",
|
|
28
|
+
"is",
|
|
29
|
+
"are",
|
|
30
|
+
"be",
|
|
31
|
+
"do",
|
|
32
|
+
"does",
|
|
33
|
+
"did",
|
|
34
|
+
"was",
|
|
35
|
+
"were",
|
|
36
|
+
"it",
|
|
37
|
+
"its",
|
|
38
|
+
"this",
|
|
39
|
+
"that",
|
|
40
|
+
"endpoint",
|
|
41
|
+
"bug",
|
|
42
|
+
"issue",
|
|
43
|
+
"error",
|
|
44
|
+
]);
|
|
45
|
+
function normalizePath(path) {
|
|
46
|
+
return path.trim().replaceAll("\\", "/");
|
|
47
|
+
}
|
|
48
|
+
function intentKeywords(intent) {
|
|
49
|
+
return intent
|
|
50
|
+
.toLowerCase()
|
|
51
|
+
.split(/[^a-z0-9]+/)
|
|
52
|
+
.map((word) => word.trim())
|
|
53
|
+
.filter((word) => word.length >= 3 && !INTENT_STOP_WORDS.has(word));
|
|
54
|
+
}
|
|
55
|
+
function fileMatchesIntentKeywords(file, keywords) {
|
|
56
|
+
if (keywords.length === 0)
|
|
57
|
+
return true;
|
|
58
|
+
const lower = normalizePath(file).toLowerCase();
|
|
59
|
+
return keywords.some((keyword) => lower.includes(keyword));
|
|
60
|
+
}
|
|
61
|
+
function fileMatchesClaimedPaths(file, claimedPaths) {
|
|
62
|
+
if (claimedPaths.length === 0)
|
|
63
|
+
return true;
|
|
64
|
+
const normalized = normalizePath(file);
|
|
65
|
+
return claimedPaths.some((pattern) => {
|
|
66
|
+
const trimmed = normalizePath(pattern);
|
|
67
|
+
if (!trimmed)
|
|
68
|
+
return false;
|
|
69
|
+
if (trimmed.endsWith("/**")) {
|
|
70
|
+
const prefix = trimmed.slice(0, -3);
|
|
71
|
+
return normalized === prefix || normalized.startsWith(`${prefix}/`);
|
|
72
|
+
}
|
|
73
|
+
if (trimmed.endsWith("/*")) {
|
|
74
|
+
const prefix = trimmed.slice(0, -2);
|
|
75
|
+
const slash = normalized.lastIndexOf("/");
|
|
76
|
+
const dir = slash >= 0 ? normalized.slice(0, slash) : "";
|
|
77
|
+
return dir === prefix;
|
|
78
|
+
}
|
|
79
|
+
return normalized === trimmed || normalized.startsWith(`${trimmed}/`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function detectOutOfScopeFiles(changedFiles, session, domains) {
|
|
83
|
+
const meaningful = changedFiles
|
|
84
|
+
.map(normalizePath)
|
|
85
|
+
.filter((file) => file.length > 0 && !(0, local_proof_1.isProofNoiseFile)(file));
|
|
86
|
+
if (meaningful.length === 0)
|
|
87
|
+
return [];
|
|
88
|
+
const claimedPaths = session?.claimedPaths ?? [];
|
|
89
|
+
if (claimedPaths.length > 0) {
|
|
90
|
+
return meaningful.filter((file) => !fileMatchesClaimedPaths(file, claimedPaths));
|
|
91
|
+
}
|
|
92
|
+
const intent = session?.intent?.trim() ?? "";
|
|
93
|
+
if (!intent)
|
|
94
|
+
return [];
|
|
95
|
+
const keywords = intentKeywords(intent);
|
|
96
|
+
if (keywords.length === 0)
|
|
97
|
+
return [];
|
|
98
|
+
const outOfScope = [];
|
|
99
|
+
for (const file of meaningful) {
|
|
100
|
+
if (fileMatchesIntentKeywords(file, keywords))
|
|
101
|
+
continue;
|
|
102
|
+
if (domains.length > 0) {
|
|
103
|
+
const domain = (0, domain_resolution_1.resolveDomainForFile)(file, domains).domain;
|
|
104
|
+
if (domain && keywords.some((keyword) => domain.toLowerCase().includes(keyword))) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
outOfScope.push(file);
|
|
109
|
+
}
|
|
110
|
+
return outOfScope;
|
|
111
|
+
}
|
|
112
|
+
function renderContractVerdict(session, changedFiles, proofRun, domains = []) {
|
|
113
|
+
const intent = session?.intent?.trim() || "(no intent declared)";
|
|
114
|
+
const meaningfulFiles = changedFiles
|
|
115
|
+
.map(normalizePath)
|
|
116
|
+
.filter((file) => file.length > 0 && !(0, local_proof_1.isProofNoiseFile)(file));
|
|
117
|
+
const outOfScope = detectOutOfScopeFiles(meaningfulFiles, session, domains);
|
|
118
|
+
const missing = [];
|
|
119
|
+
if (!session?.intent?.trim()) {
|
|
120
|
+
missing.push("No contract intent was recorded.");
|
|
121
|
+
}
|
|
122
|
+
if (meaningfulFiles.length === 0) {
|
|
123
|
+
missing.push("No files changed since the contract baseline.");
|
|
124
|
+
}
|
|
125
|
+
if (!proofRun) {
|
|
126
|
+
missing.push("No proof/test run was recorded.");
|
|
127
|
+
}
|
|
128
|
+
else if (proofRun.status === "failed") {
|
|
129
|
+
missing.push(`Proof failed: ${proofRun.command} (exit ${proofRun.exitCode}).`);
|
|
130
|
+
}
|
|
131
|
+
let nextStep = "Contract looks complete. Commit when ready.";
|
|
132
|
+
if (missing.length > 0 && outOfScope.length > 0) {
|
|
133
|
+
nextStep =
|
|
134
|
+
"Review out-of-scope files, run the relevant tests, then decide whether to accept or revert the extra changes.";
|
|
135
|
+
}
|
|
136
|
+
else if (missing.some((item) => item.includes("proof"))) {
|
|
137
|
+
nextStep = "Run the relevant test command so AgentBridge can record proof for this contract.";
|
|
138
|
+
}
|
|
139
|
+
else if (outOfScope.length > 0) {
|
|
140
|
+
nextStep =
|
|
141
|
+
"Ask the agent to justify the out-of-scope files, or revert them before accepting the work.";
|
|
142
|
+
}
|
|
143
|
+
else if (meaningfulFiles.length === 0) {
|
|
144
|
+
nextStep = "No work was recorded. Start a new contract when you are ready to implement.";
|
|
145
|
+
}
|
|
146
|
+
const lines = [
|
|
147
|
+
"AgentBridge Contract Verdict",
|
|
148
|
+
"─────────────────────────────────────────",
|
|
149
|
+
"",
|
|
150
|
+
"Here's what the contract was:",
|
|
151
|
+
` ${intent}`,
|
|
152
|
+
"",
|
|
153
|
+
"Here's what the agent changed:",
|
|
154
|
+
];
|
|
155
|
+
if (meaningfulFiles.length === 0) {
|
|
156
|
+
lines.push(" No files changed.");
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
for (const file of meaningfulFiles) {
|
|
160
|
+
lines.push(` - ${file}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
lines.push("", "Here's what appears missing:");
|
|
164
|
+
if (missing.length === 0) {
|
|
165
|
+
lines.push(" Nothing obvious from this contract check.");
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
for (const item of missing) {
|
|
169
|
+
lines.push(` - ${item}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
lines.push("", "Here's where the work drifted out of scope:");
|
|
173
|
+
if (outOfScope.length === 0) {
|
|
174
|
+
lines.push(" No out-of-scope files detected.");
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
for (const file of outOfScope) {
|
|
178
|
+
const reason = session?.intent?.trim()
|
|
179
|
+
? `${file} was changed, but the contract was about ${session.intent.trim()}.`
|
|
180
|
+
: `${file} was changed outside the declared contract.`;
|
|
181
|
+
lines.push(` - ${reason}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
lines.push("", "Here's the next step:", ` ${nextStep}`, "");
|
|
185
|
+
return lines.join("\n");
|
|
186
|
+
}
|
package/dist/error-catalog.js
CHANGED
|
@@ -20,7 +20,7 @@ const CATALOG = {
|
|
|
20
20
|
title: "Authentication failed.",
|
|
21
21
|
what: "The API key was missing, invalid, or rejected by the server.",
|
|
22
22
|
why: "AgentBridge cannot reach project APIs without valid credentials.",
|
|
23
|
-
next: "
|
|
23
|
+
next: "Run `agentbridge room exit`, set a fresh AGENTBRIDGE_API_KEY, then `agentbridge connect`.",
|
|
24
24
|
},
|
|
25
25
|
PROJECT_ACCESS_NOT_FOUND: {
|
|
26
26
|
code: "PROJECT_ACCESS_NOT_FOUND",
|
|
@@ -30,6 +30,19 @@ const CATALOG = {
|
|
|
30
30
|
why: "Commands target the wrong room or environment.",
|
|
31
31
|
next: "Verify AGENTBRIDGE_PROJECT_ID and rerun `agentbridge init --project <id>`.",
|
|
32
32
|
},
|
|
33
|
+
CONNECT_EXECUTION_SURFACE_MISSING: {
|
|
34
|
+
code: "CONNECT_EXECUTION_SURFACE_MISSING",
|
|
35
|
+
category: "IDENTITY_ERROR",
|
|
36
|
+
title: "Connection incomplete.",
|
|
37
|
+
what: "Project access was verified, but this key is not bound to an AgentConnection execution surface.",
|
|
38
|
+
why: "Connect requires a room connection key that resolves to work_identity on /hello.",
|
|
39
|
+
next: [
|
|
40
|
+
"In the AgentBridge dashboard, open this room and rotate the API key (or create a new room).",
|
|
41
|
+
"Update AGENTBRIDGE_API_KEY or .agentbridge/config.json with the new key.",
|
|
42
|
+
"Run: agentbridge connect --project <project-id> --api-key <new-key>",
|
|
43
|
+
"Connect does not create or rotate keys automatically.",
|
|
44
|
+
].join("\n"),
|
|
45
|
+
},
|
|
33
46
|
IDENTITY_ACTIVE_AGENT_STALE: {
|
|
34
47
|
code: "IDENTITY_ACTIVE_AGENT_STALE",
|
|
35
48
|
category: "IDENTITY_ERROR",
|
|
@@ -229,6 +242,22 @@ const CATALOG = {
|
|
|
229
242
|
why: "Scoped work must target a recovered domain lane.",
|
|
230
243
|
next: 'Pass `--domain "<domain>"` with start, or run `agentbridge init`.',
|
|
231
244
|
},
|
|
245
|
+
START_LANE_CLAIM_CONFIRM_REQUIRED: {
|
|
246
|
+
code: "START_LANE_CLAIM_CONFIRM_REQUIRED",
|
|
247
|
+
category: "START_ERROR",
|
|
248
|
+
title: "Lane claim needs explicit confirmation.",
|
|
249
|
+
what: "Start inferred a domain with medium confidence.",
|
|
250
|
+
why: "Production-safe lane claim requires explicit confirmation when scope-to-domain mapping is ambiguous.",
|
|
251
|
+
next: 'Rerun with `--confirm-domain` or pass an explicit `--domain "<domain>"`.',
|
|
252
|
+
},
|
|
253
|
+
START_LANE_CLAIM_LOW_CONFIDENCE: {
|
|
254
|
+
code: "START_LANE_CLAIM_LOW_CONFIDENCE",
|
|
255
|
+
category: "START_ERROR",
|
|
256
|
+
title: "Lane claim confidence too low.",
|
|
257
|
+
what: "AgentBridge could not confidently bind this work to a single domain lane.",
|
|
258
|
+
why: "A wrong lane claim undermines scope enforcement and ownership attribution.",
|
|
259
|
+
next: 'Pass explicit `--domain "<domain>"` and tighter `--scope "<path>"`, then rerun start.',
|
|
260
|
+
},
|
|
232
261
|
START_OWNER_UNRESOLVED: {
|
|
233
262
|
code: "START_OWNER_UNRESOLVED",
|
|
234
263
|
category: "START_ERROR",
|
package/dist/git-status.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.repoDirtySnapshotFromGitStatus = repoDirtySnapshotFromGitStatus;
|
|
|
7
7
|
exports.getBranchName = getBranchName;
|
|
8
8
|
exports.getDirtyWorkingTreeFiles = getDirtyWorkingTreeFiles;
|
|
9
9
|
const node_child_process_1 = require("node:child_process");
|
|
10
|
+
const local_proof_1 = require("./local-proof");
|
|
10
11
|
function normalizePath(path) {
|
|
11
12
|
return path.trim().replaceAll("\\", "/");
|
|
12
13
|
}
|
|
@@ -41,13 +42,16 @@ function parseGitStatusPorcelainZ(raw) {
|
|
|
41
42
|
}
|
|
42
43
|
return entries;
|
|
43
44
|
}
|
|
45
|
+
function isSupervisionRelevantPath(path) {
|
|
46
|
+
return !isAgentbridgeLocalPath(path) && !(0, local_proof_1.isProofNoiseFile)(path);
|
|
47
|
+
}
|
|
44
48
|
function collectChangedFilesFromStatusEntries(entries) {
|
|
45
49
|
const files = new Set();
|
|
46
50
|
for (const entry of entries) {
|
|
47
|
-
if (entry.path &&
|
|
51
|
+
if (entry.path && isSupervisionRelevantPath(entry.path)) {
|
|
48
52
|
files.add(entry.path);
|
|
49
53
|
}
|
|
50
|
-
if (entry.originalPath &&
|
|
54
|
+
if (entry.originalPath && isSupervisionRelevantPath(entry.originalPath)) {
|
|
51
55
|
files.add(entry.originalPath);
|
|
52
56
|
}
|
|
53
57
|
}
|
package/dist/index.js
CHANGED
|
@@ -25,11 +25,13 @@ const memory_1 = require("./commands/memory");
|
|
|
25
25
|
const session_1 = require("./commands/session");
|
|
26
26
|
const handshake_1 = require("./commands/handshake");
|
|
27
27
|
const connect_1 = require("./commands/connect");
|
|
28
|
+
const room_1 = require("./commands/room");
|
|
28
29
|
const setup_mcp_1 = require("./commands/setup-mcp");
|
|
29
30
|
const bug_1 = require("./commands/bug");
|
|
30
31
|
const autopilot_1 = require("./commands/autopilot");
|
|
31
32
|
const attention_1 = require("./commands/attention");
|
|
32
33
|
const recover_1 = require("./commands/recover");
|
|
34
|
+
const install_rules_1 = require("./commands/install-rules");
|
|
33
35
|
const proof_guidance_1 = require("./commands/proof-guidance");
|
|
34
36
|
const node_path_1 = require("node:path");
|
|
35
37
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -41,6 +43,10 @@ const COMMAND_HELP = {
|
|
|
41
43
|
connect: " agentbridge connect [--project <id>] [--api-key <key>] [--api-base-url <url>] [--agent <id>]\n" +
|
|
42
44
|
" Save credentials and verify connection to your AgentBridge project.\n" +
|
|
43
45
|
" Credentials can also come from AGENTBRIDGE_PROJECT_ID / AGENTBRIDGE_API_KEY env vars.\n",
|
|
46
|
+
room: " agentbridge room exit [--keep-session] [--json]\n" +
|
|
47
|
+
" Clear saved room credentials from .agentbridge/config.json (no server call).\n" +
|
|
48
|
+
" Use when API keys are rejected or you need to connect to a different project.\n" +
|
|
49
|
+
" Preserves domain recovery data from init/recover.\n",
|
|
44
50
|
recover: " agentbridge recover [--force]\n" +
|
|
45
51
|
" Recover project context so AI agents do not start blind.\n" +
|
|
46
52
|
" Shows project name, domains, and known context.\n",
|
|
@@ -49,11 +55,11 @@ const COMMAND_HELP = {
|
|
|
49
55
|
" Run `agentbridge connect` first to save credentials.\n",
|
|
50
56
|
use: " agentbridge use <agent-id>\n" +
|
|
51
57
|
" Set the active agent identity used by `watch` and `start`.\n",
|
|
52
|
-
start: " agentbridge start [\"intent\"] [--details] [--yes]\n" +
|
|
58
|
+
start: " agentbridge start [\"intent\"] [--details] [--yes] [--confirm-domain]\n" +
|
|
53
59
|
" Open or close a task checkpoint (not the live watcher).\n" +
|
|
54
60
|
" For live supervision beside Cursor, run `agentbridge watch`.\n" +
|
|
55
61
|
" Record proof: `agentbridge verify -- <test command>`.\n",
|
|
56
|
-
watch: " agentbridge watch [--allow-dirty] [--once] [--daemon] [--details] [--task \"<summary>\"] [--scope \"<path>\"]\n" +
|
|
62
|
+
watch: " agentbridge watch [--allow-dirty] [--once] [--daemon] [--details] [--confirm-domain] [--task \"<summary>\"] [--scope \"<path>\"]\n" +
|
|
57
63
|
" Primary live supervision command — run beside Cursor while the agent codes.\n" +
|
|
58
64
|
" Shows MCP-declared intent and disk changes; warns on scope drift.\n" +
|
|
59
65
|
" No --task or --scope required for normal use.\n" +
|
|
@@ -62,8 +68,9 @@ const COMMAND_HELP = {
|
|
|
62
68
|
" --once Run one supervision pass and exit.\n" +
|
|
63
69
|
" --daemon Non-interactive mode: skip prompts, auto-deny domain crossings.\n" +
|
|
64
70
|
" --change-request / --execution-surface Advanced session binding.\n",
|
|
65
|
-
"setup-mcp": " agentbridge setup-mcp [--editor cursor|windsurf|vscode]\n" +
|
|
66
|
-
"
|
|
71
|
+
"setup-mcp": " agentbridge setup-mcp [--local] [--editor cursor|windsurf|vscode]\n" +
|
|
72
|
+
" --local Write local-first MCP config (no API keys) to .cursor/mcp.json\n" +
|
|
73
|
+
" Print or write the MCP server configuration for your editor.\n",
|
|
67
74
|
mcp: " agentbridge mcp\n" +
|
|
68
75
|
" Start the AgentBridge MCP stdio server.\n",
|
|
69
76
|
status: " agentbridge status [--repair] [--json]\n Show current work session status.\n",
|
|
@@ -89,6 +96,9 @@ const COMMAND_HELP = {
|
|
|
89
96
|
" Manage domain memory packets.\n",
|
|
90
97
|
version: " agentbridge version\n Print CLI version.\n",
|
|
91
98
|
doctor: " agentbridge doctor\n Run config and connectivity diagnostics.\n",
|
|
99
|
+
"install-rules": " agentbridge install-rules [--project <id>] [--api-key <key>] [--api-base-url <url>]\n" +
|
|
100
|
+
" Fetch server protocol rules for the connected project, write AGENTBRIDGE.md and\n" +
|
|
101
|
+
" .cursor/rules/agentbridge.mdc, and mark rules installed on the server.\n",
|
|
92
102
|
"precommit-check": " agentbridge precommit-check\n Git pre-commit hook: block commits that violate domain boundaries.\n",
|
|
93
103
|
bug: " agentbridge bug report --title \"<text>\" --severity P0|P1|P2|P3 --category <CATEGORY> \\\n" +
|
|
94
104
|
" [--found-in dogfood,production,...] --observed \"<text>\" --expected \"<text>\" \\\n" +
|
|
@@ -118,6 +128,8 @@ function usage(command, opts) {
|
|
|
118
128
|
"Setup:",
|
|
119
129
|
" agentbridge doctor Check connection and repo readiness",
|
|
120
130
|
" agentbridge connect Save credentials (cloud projects)",
|
|
131
|
+
" agentbridge room exit Clear stale room credentials (no server call)",
|
|
132
|
+
" agentbridge install-rules Install server protocol rules in this repo",
|
|
121
133
|
"",
|
|
122
134
|
"Advanced commands:",
|
|
123
135
|
" start --task ... --scope ... Strict scoped session (both flags required)",
|
|
@@ -263,12 +275,36 @@ async function main() {
|
|
|
263
275
|
});
|
|
264
276
|
return;
|
|
265
277
|
}
|
|
278
|
+
if (command === "room") {
|
|
279
|
+
const sub = positional[0] ?? "";
|
|
280
|
+
if (sub === "exit") {
|
|
281
|
+
(0, room_1.runRoomExit)({
|
|
282
|
+
keepSession: flags["--keep-session"] === "true",
|
|
283
|
+
json: flags["--json"] === "true",
|
|
284
|
+
});
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
process.stderr.write("Usage: agentbridge room exit [--keep-session] [--json]\n");
|
|
288
|
+
process.exit(3);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (command === "install-rules") {
|
|
292
|
+
await (0, install_rules_1.runInstallRules)({
|
|
293
|
+
projectId,
|
|
294
|
+
apiKey,
|
|
295
|
+
apiBaseUrl,
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
266
299
|
if (command === "recover") {
|
|
267
300
|
await (0, recover_1.runRecover)({ force: Boolean(flags["--force"]) });
|
|
268
301
|
return;
|
|
269
302
|
}
|
|
270
303
|
if (command === "setup-mcp") {
|
|
271
|
-
await (0, setup_mcp_1.runSetupMcp)({
|
|
304
|
+
await (0, setup_mcp_1.runSetupMcp)({
|
|
305
|
+
editor: flags["--editor"],
|
|
306
|
+
local: flags["--local"] === "true",
|
|
307
|
+
});
|
|
272
308
|
return;
|
|
273
309
|
}
|
|
274
310
|
if (command === "mcp") {
|
|
@@ -340,6 +376,7 @@ async function main() {
|
|
|
340
376
|
daemon: flags["--daemon"] === "true",
|
|
341
377
|
once: flags["--once"] === "true",
|
|
342
378
|
details: flags["--details"] === "true",
|
|
379
|
+
confirmDomain: flags["--confirm-domain"] === "true",
|
|
343
380
|
});
|
|
344
381
|
return;
|
|
345
382
|
}
|
|
@@ -359,6 +396,7 @@ async function main() {
|
|
|
359
396
|
resume: flags["--resume"] === "true",
|
|
360
397
|
details: flags["--details"] === "true",
|
|
361
398
|
confirmClose: flags["--yes"] === "true",
|
|
399
|
+
confirmDomain: flags["--confirm-domain"] === "true",
|
|
362
400
|
});
|
|
363
401
|
return;
|
|
364
402
|
}
|
package/dist/init.js
CHANGED
|
@@ -597,6 +597,16 @@ async function runBootstrapRecovery(ctx, opts = {}) {
|
|
|
597
597
|
const existingBootstrap = refsToBootstrapDomains(opts.reconcilePlan.existingActive);
|
|
598
598
|
bootstrapPayload.domains = (0, recovery_reconcile_1.mergeBootstrapDomainEntries)(opts.reconcilePlan, candidateBootstrap, existingBootstrap);
|
|
599
599
|
}
|
|
600
|
+
if (process.env.AGENTBRIDGE_DEBUG_HTTP === "1") {
|
|
601
|
+
const payloadDomains = Array.isArray(bootstrapPayload.domains)
|
|
602
|
+
? bootstrapPayload.domains
|
|
603
|
+
: [];
|
|
604
|
+
const mappedPathCount = payloadDomains.reduce((count, domain) => {
|
|
605
|
+
const paths = domain.files && domain.files.length > 0 ? domain.files : domain.pathPatterns;
|
|
606
|
+
return count + (Array.isArray(paths) ? paths.length : 0);
|
|
607
|
+
}, 0);
|
|
608
|
+
process.stderr.write(`[agentbridge:recover] bootstrap POST project=${ctx.projectId} domains=${payloadDomains.length} mapped_paths=${mappedPathCount} product_summary_len=${String(bootstrapPayload.product_summary ?? "").length}\n`);
|
|
609
|
+
}
|
|
600
610
|
await (0, http_1.postJson)(ctx, `/v1/dev/projects/${encodeURIComponent(ctx.projectId)}/bootstrap`, bootstrapPayload);
|
|
601
611
|
const payloadDomains = Array.isArray(bootstrapPayload.domains)
|
|
602
612
|
? bootstrapPayload.domains
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isVagueIntent = isVagueIntent;
|
|
4
|
+
exports.validateIntent = validateIntent;
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const VAGUE_PHRASES = [
|
|
7
|
+
"working on project",
|
|
8
|
+
"making changes",
|
|
9
|
+
"updating files",
|
|
10
|
+
"fix stuff",
|
|
11
|
+
"general work",
|
|
12
|
+
];
|
|
13
|
+
function isVagueIntent(intent) {
|
|
14
|
+
const lower = intent.trim().toLowerCase();
|
|
15
|
+
if (!lower)
|
|
16
|
+
return true;
|
|
17
|
+
if (lower.split(/\s+/).length < 4)
|
|
18
|
+
return true;
|
|
19
|
+
return VAGUE_PHRASES.some((phrase) => lower.includes(phrase));
|
|
20
|
+
}
|
|
21
|
+
function validateIntent(intent) {
|
|
22
|
+
const trimmed = intent.trim();
|
|
23
|
+
if (!trimmed) {
|
|
24
|
+
throw (0, errors_1.catalogCliError)("START_SUMMARY_REQUIRED", {
|
|
25
|
+
what: "A work contract intent is required.",
|
|
26
|
+
next: 'Run: agentbridge start "Fix auth 401 on /rooms endpoint"',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (isVagueIntent(trimmed)) {
|
|
30
|
+
throw (0, errors_1.catalogCliError)("START_SUMMARY_REQUIRED", {
|
|
31
|
+
what: "Intent is too vague for a work contract.",
|
|
32
|
+
why: "AgentBridge needs a specific goal to compare against file changes.",
|
|
33
|
+
next: 'Use a concrete intent, e.g. agentbridge start "Fix auth 401 on /rooms endpoint"',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return trimmed;
|
|
37
|
+
}
|
package/dist/local-proof.js
CHANGED
|
@@ -11,10 +11,18 @@ function normalizePath(path) {
|
|
|
11
11
|
return path.trim().replaceAll("\\", "/");
|
|
12
12
|
}
|
|
13
13
|
function isProofNoiseFile(file) {
|
|
14
|
-
const normalized = normalizePath(file)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
const normalized = normalizePath(file);
|
|
15
|
+
const lower = normalized.toLowerCase();
|
|
16
|
+
if (lower === "agentbridge.md" ||
|
|
17
|
+
lower === ".cursor" ||
|
|
18
|
+
lower.startsWith(".cursor/")) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
// Vite ephemeral config bundles (e.g. vite.config.ts.timestamp-1781442511868-*.mjs)
|
|
22
|
+
if (/\.timestamp-\d+-[a-z0-9]+\.mjs$/i.test(normalized)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
18
26
|
}
|
|
19
27
|
function normalizeProofMatchingFileSet(files) {
|
|
20
28
|
return [...new Set(files.map(normalizePath).filter((file) => file.length > 0 && !isProofNoiseFile(file)))].sort();
|