@agentbridge1/cli 0.0.1
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/bin/agentbridge.js +11 -0
- package/dist/acceptance-block.js +21 -0
- package/dist/acceptance-preflight.js +91 -0
- package/dist/api-client.js +6 -0
- package/dist/authority-request.js +25 -0
- package/dist/briefing.js +26 -0
- package/dist/bug-registry.js +350 -0
- package/dist/build-info.json +6 -0
- package/dist/canonical-state.js +11 -0
- package/dist/claimed-paths.js +42 -0
- package/dist/cli-failure-log.js +34 -0
- package/dist/commands/accept.js +241 -0
- package/dist/commands/attention.js +85 -0
- package/dist/commands/autopilot.js +93 -0
- package/dist/commands/bug.js +106 -0
- package/dist/commands/check.js +283 -0
- package/dist/commands/connect.js +159 -0
- package/dist/commands/dist-freshness.js +105 -0
- package/dist/commands/doctor.js +300 -0
- package/dist/commands/done.js +292 -0
- package/dist/commands/handoff.js +189 -0
- package/dist/commands/handshake.js +78 -0
- package/dist/commands/health.js +154 -0
- package/dist/commands/identity.js +57 -0
- package/dist/commands/init.js +5 -0
- package/dist/commands/memory.js +400 -0
- package/dist/commands/next.js +21 -0
- package/dist/commands/precommit-check.js +17 -0
- package/dist/commands/recover.js +116 -0
- package/dist/commands/session.js +229 -0
- package/dist/commands/setup-mcp.js +56 -0
- package/dist/commands/start.js +626 -0
- package/dist/commands/status.js +486 -0
- package/dist/commands/use.js +13 -0
- package/dist/commands/verify.js +264 -0
- package/dist/commands/version.js +32 -0
- package/dist/commands/watch.js +1718 -0
- package/dist/config.js +55 -0
- package/dist/domain-resolution.js +63 -0
- package/dist/error-catalog.js +494 -0
- package/dist/errors.js +276 -0
- package/dist/file-fingerprints.js +45 -0
- package/dist/gates.js +200 -0
- package/dist/git-evidence.js +285 -0
- package/dist/git-status.js +81 -0
- package/dist/http.js +151 -0
- package/dist/index.js +622 -0
- package/dist/init.js +458 -0
- package/dist/memory-context-render.js +51 -0
- package/dist/operator-snapshot.js +99 -0
- package/dist/precommit.js +72 -0
- package/dist/preflight-changed-files.js +109 -0
- package/dist/proof-guidance.js +110 -0
- package/dist/redact-secrets.js +15 -0
- package/dist/revert-crossing.js +73 -0
- package/dist/server-sync.js +433 -0
- package/dist/session-state.js +138 -0
- package/dist/session.js +89 -0
- package/dist/supervision.js +212 -0
- package/dist/terminal-ui.js +18 -0
- package/dist/test-runner.js +62 -0
- package/dist/types.js +2 -0
- package/dist/verification-conditions.js +185 -0
- package/dist/watch-core.js +208 -0
- package/dist/watch-packet-handshake.js +71 -0
- package/dist/watcher.js +62 -0
- package/dist/work-context-resolver.js +412 -0
- package/dist/work-contract.js +110 -0
- package/package.json +44 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runHandoff = runHandoff;
|
|
4
|
+
exports.isNoActiveSessionHttpError = isNoActiveSessionHttpError;
|
|
5
|
+
const config_1 = require("../config");
|
|
6
|
+
const http_1 = require("../http");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const session_state_1 = require("../session-state");
|
|
9
|
+
const server_sync_1 = require("../server-sync");
|
|
10
|
+
const check_1 = require("./check");
|
|
11
|
+
const operator_snapshot_1 = require("../operator-snapshot");
|
|
12
|
+
const proof_guidance_1 = require("../proof-guidance");
|
|
13
|
+
const acceptance_preflight_1 = require("../acceptance-preflight");
|
|
14
|
+
const acceptance_block_1 = require("../acceptance-block");
|
|
15
|
+
const work_context_resolver_1 = require("../work-context-resolver");
|
|
16
|
+
function resolveNetworkContext() {
|
|
17
|
+
const cfg = (0, config_1.readConfig)();
|
|
18
|
+
const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId;
|
|
19
|
+
const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
|
|
20
|
+
const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ?? cfg.apiBaseUrl ?? "https://agentauth-api-production.up.railway.app";
|
|
21
|
+
if (!projectId) {
|
|
22
|
+
throw new errors_1.SafeCliError("Missing AGENTBRIDGE_PROJECT_ID. Set AGENTBRIDGE_PROJECT_ID (or run `agentbridge init --project ...`).");
|
|
23
|
+
}
|
|
24
|
+
if (!apiKey) {
|
|
25
|
+
throw new errors_1.SafeCliError("Missing AGENTBRIDGE_API_KEY. Provide --api-key, set AGENTBRIDGE_API_KEY, or save apiKey in .agentbridge/config.json.");
|
|
26
|
+
}
|
|
27
|
+
return { projectId, apiKey, apiBaseUrl };
|
|
28
|
+
}
|
|
29
|
+
function uniqueStrings(values) {
|
|
30
|
+
return [...new Set(values.map((v) => v.trim()).filter((v) => v.length > 0))];
|
|
31
|
+
}
|
|
32
|
+
function buildProofPrompt(report) {
|
|
33
|
+
if (report.decision === "stale_evidence" || report.completion.state === "stale_evidence") {
|
|
34
|
+
return (0, check_1.buildStaleProofPrompt)(report);
|
|
35
|
+
}
|
|
36
|
+
const missing = (0, proof_guidance_1.getMissingProofDetails)(report)
|
|
37
|
+
.map((detail) => `- ${detail.message}\n Why: ${detail.why}`)
|
|
38
|
+
.join("\n");
|
|
39
|
+
return [
|
|
40
|
+
"Before this work can be accepted, complete the following proof items:",
|
|
41
|
+
missing || "- (no explicit missing proof listed)",
|
|
42
|
+
"",
|
|
43
|
+
"Then run:",
|
|
44
|
+
`agentbridge check`,
|
|
45
|
+
].join("\n");
|
|
46
|
+
}
|
|
47
|
+
function renderHandoffAcceptanceReport(summary, report) {
|
|
48
|
+
const lines = [];
|
|
49
|
+
lines.push("HANDOFF ACCEPTANCE REPORT");
|
|
50
|
+
lines.push("----------------------------------------");
|
|
51
|
+
lines.push(`CR/session: ${report.change_request_id ?? "none"} / ${report.work_session_id}`);
|
|
52
|
+
lines.push(`Summary: ${summary}`);
|
|
53
|
+
lines.push(`Changed files: ${report.changed_files.length > 0 ? report.changed_files.join(", ") : "none"}`);
|
|
54
|
+
lines.push(`Evidence: ${report.verification_runs.length > 0
|
|
55
|
+
? report.verification_runs.map((run) => `[${run.status}] ${run.command}${run.stale ? " (stale)" : ""}`).join(" | ")
|
|
56
|
+
: "none recorded"}`);
|
|
57
|
+
const missingDetails = (0, proof_guidance_1.getMissingProofDetails)(report);
|
|
58
|
+
lines.push(`Missing proof: ${missingDetails.length > 0 ? missingDetails.map((detail) => detail.message).join(" | ") : "none"}`);
|
|
59
|
+
lines.push(`Risks: ${report.risks_remaining.length > 0 ? report.risks_remaining.join(" | ") : "none detected"}`);
|
|
60
|
+
lines.push(`Decision: ${report.decision}`);
|
|
61
|
+
lines.push(`Next action: ${report.next_required_action.join(" | ")}`);
|
|
62
|
+
return lines.join("\n");
|
|
63
|
+
}
|
|
64
|
+
function renderHandoffBlocked(summary, report) {
|
|
65
|
+
process.stdout.write(`${renderHandoffAcceptanceReport(summary, report)}\n`);
|
|
66
|
+
process.stdout.write(`${(0, check_1.renderAcceptanceReport)(report)}\n`);
|
|
67
|
+
process.stdout.write(`${buildProofPrompt(report)}\n`);
|
|
68
|
+
process.exitCode = 1;
|
|
69
|
+
}
|
|
70
|
+
async function runHandoff(args, options = {}) {
|
|
71
|
+
if (!args.summary || args.summary.trim().length === 0) {
|
|
72
|
+
throw new errors_1.SafeCliError({
|
|
73
|
+
code: "HANDOFF_SUMMARY_REQUIRED",
|
|
74
|
+
what: "Handoff summary is required.",
|
|
75
|
+
why: "A summary is needed so reviewers understand what was done and why.",
|
|
76
|
+
next: 'Provide a summary with --summary \"<description of what was done>\" (at least 10 characters).',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (args.summary.trim().length < 10) {
|
|
80
|
+
throw new errors_1.SafeCliError({
|
|
81
|
+
code: "HANDOFF_SUMMARY_TOO_SHORT",
|
|
82
|
+
what: "Handoff summary must be at least 10 characters.",
|
|
83
|
+
why: "Summaries shorter than 10 characters do not provide useful context for reviewers.",
|
|
84
|
+
next: 'Provide a more descriptive summary with --summary \"<description of what was done>\".',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const summary = args.summary.trim();
|
|
88
|
+
const ctx = resolveNetworkContext();
|
|
89
|
+
const { resolution, preflight, report: beforeReport } = await (0, acceptance_preflight_1.resolveAcceptanceWorkContext)(ctx);
|
|
90
|
+
if (resolution.state !== "current_session_resolved" || !beforeReport) {
|
|
91
|
+
if (options.json) {
|
|
92
|
+
const snapshot = (0, operator_snapshot_1.buildOperatorSnapshot)(resolution);
|
|
93
|
+
process.stdout.write(`${JSON.stringify({ snapshot }, null, 2)}\n`);
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
process.stdout.write(`${(0, work_context_resolver_1.renderWorkContextLines)(resolution).join("\n")}\n`);
|
|
98
|
+
process.exitCode = 1;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const binding = (0, work_context_resolver_1.requireWorkContextBinding)(resolution, "handoff");
|
|
102
|
+
const preSyncedChangedFiles = preflight.observedFiles;
|
|
103
|
+
if ((0, acceptance_block_1.shouldBlockAcceptanceAction)(beforeReport)) {
|
|
104
|
+
if (options.json) {
|
|
105
|
+
const snapshot = (0, operator_snapshot_1.buildOperatorSnapshot)(resolution);
|
|
106
|
+
process.stdout.write(`${JSON.stringify({
|
|
107
|
+
snapshot,
|
|
108
|
+
blocked: true,
|
|
109
|
+
acceptance_report: beforeReport,
|
|
110
|
+
}, null, 2)}\n`);
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
renderHandoffBlocked(summary, beforeReport);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const commandsRun = uniqueStrings(beforeReport.verification_runs.map((run) => run.command));
|
|
118
|
+
const state = (0, session_state_1.readSessionState)();
|
|
119
|
+
const domainsTouched = uniqueStrings([
|
|
120
|
+
state?.laneDomain ?? "",
|
|
121
|
+
...state?.crossings.map((crossing) => crossing.domain ?? "") ?? [],
|
|
122
|
+
]);
|
|
123
|
+
const changedFiles = uniqueStrings([
|
|
124
|
+
...preSyncedChangedFiles,
|
|
125
|
+
...beforeReport.changed_files,
|
|
126
|
+
]);
|
|
127
|
+
await (0, server_sync_1.postHandoff)(ctx, {
|
|
128
|
+
summary,
|
|
129
|
+
changedFiles: changedFiles.length > 0 ? changedFiles : ["(no changed files captured)"],
|
|
130
|
+
commandsRun: commandsRun.length > 0 ? commandsRun : ["no verification command recorded"],
|
|
131
|
+
domainsTouched: domainsTouched.length > 0 ? domainsTouched : ["general"],
|
|
132
|
+
reviewRequired: beforeReport.boundary_status !== "clean" || beforeReport.decision === "needs_review",
|
|
133
|
+
risksRemaining: args.risksRemaining ?? null,
|
|
134
|
+
workSessionId: binding.workSessionId,
|
|
135
|
+
});
|
|
136
|
+
const { report } = await (0, acceptance_preflight_1.resolveAcceptanceWorkContext)(ctx);
|
|
137
|
+
const afterReport = report ?? beforeReport;
|
|
138
|
+
if (options.json) {
|
|
139
|
+
const snapshot = (0, operator_snapshot_1.buildOperatorSnapshot)({
|
|
140
|
+
...resolution,
|
|
141
|
+
binding: {
|
|
142
|
+
workSessionId: afterReport.work_session_id,
|
|
143
|
+
changeRequestId: afterReport.change_request_id ?? null,
|
|
144
|
+
report: afterReport,
|
|
145
|
+
},
|
|
146
|
+
resolvedServerSessionId: afterReport.work_session_id,
|
|
147
|
+
resolvedChangeRequestId: afterReport.change_request_id ?? null,
|
|
148
|
+
});
|
|
149
|
+
process.stdout.write(`${JSON.stringify({
|
|
150
|
+
snapshot,
|
|
151
|
+
handoff: {
|
|
152
|
+
summary,
|
|
153
|
+
work_session_id: afterReport.work_session_id,
|
|
154
|
+
change_request_id: afterReport.change_request_id ?? null,
|
|
155
|
+
changed_files: changedFiles,
|
|
156
|
+
commands_run: commandsRun,
|
|
157
|
+
domains_touched: domainsTouched,
|
|
158
|
+
risks_remaining: args.risksRemaining ?? null,
|
|
159
|
+
decision: afterReport.decision,
|
|
160
|
+
next_required_action: afterReport.next_required_action,
|
|
161
|
+
},
|
|
162
|
+
}, null, 2)}\n`);
|
|
163
|
+
if ((0, acceptance_block_1.shouldBlockAcceptanceAction)(afterReport)) {
|
|
164
|
+
process.exitCode = 1;
|
|
165
|
+
}
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
process.stdout.write(`${renderHandoffAcceptanceReport(summary, afterReport)}\n`);
|
|
169
|
+
process.stdout.write(`${(0, check_1.renderAcceptanceReport)(afterReport)}\n`);
|
|
170
|
+
if ((0, acceptance_block_1.shouldBlockAcceptanceAction)(afterReport)) {
|
|
171
|
+
process.stdout.write(`${buildProofPrompt(afterReport)}\n`);
|
|
172
|
+
process.exitCode = 1;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (afterReport.completion.state === "ready_to_accept") {
|
|
176
|
+
process.stdout.write("Ready to accept. Run agentbridge accept.\n");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function isNoActiveSessionHttpError(err) {
|
|
180
|
+
if (!(err instanceof http_1.CliHttpError) || err.status !== 404)
|
|
181
|
+
return false;
|
|
182
|
+
try {
|
|
183
|
+
const parsed = JSON.parse(err.body);
|
|
184
|
+
return parsed.code === "active_work_session_not_found" || parsed.error === "active_work_session_not_found";
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateHandshakeCreateFields = validateHandshakeCreateFields;
|
|
4
|
+
exports.runHandshakeCreate = runHandshakeCreate;
|
|
5
|
+
exports.runHandshakeAcknowledge = runHandshakeAcknowledge;
|
|
6
|
+
exports.runHandshakeResolve = runHandshakeResolve;
|
|
7
|
+
exports.runHandshakeList = runHandshakeList;
|
|
8
|
+
const config_1 = require("../config");
|
|
9
|
+
const errors_1 = require("../errors");
|
|
10
|
+
const server_sync_1 = require("../server-sync");
|
|
11
|
+
const work_context_resolver_1 = require("../work-context-resolver");
|
|
12
|
+
const MIN_FIELD_LEN = 20;
|
|
13
|
+
function resolveNetworkContext() {
|
|
14
|
+
const cfg = (0, config_1.readConfig)();
|
|
15
|
+
const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId;
|
|
16
|
+
const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
|
|
17
|
+
const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ?? cfg.apiBaseUrl ?? "https://agentauth-api-production.up.railway.app";
|
|
18
|
+
if (!projectId) {
|
|
19
|
+
throw new errors_1.SafeCliError("Missing AGENTBRIDGE_PROJECT_ID. Set AGENTBRIDGE_PROJECT_ID (or run `agentbridge init --project ...`).");
|
|
20
|
+
}
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
throw new errors_1.SafeCliError("Missing AGENTBRIDGE_API_KEY. Provide --api-key, set AGENTBRIDGE_API_KEY, or save apiKey in .agentbridge/config.json.");
|
|
23
|
+
}
|
|
24
|
+
return { projectId, apiKey, apiBaseUrl };
|
|
25
|
+
}
|
|
26
|
+
function validateHandshakeCreateFields(action, reason) {
|
|
27
|
+
if (action.trim().length < MIN_FIELD_LEN) {
|
|
28
|
+
return `requested_action must be at least ${MIN_FIELD_LEN} characters (describe the exact change, not just the domain).`;
|
|
29
|
+
}
|
|
30
|
+
if (reason.trim().length < MIN_FIELD_LEN) {
|
|
31
|
+
return `reason must be at least ${MIN_FIELD_LEN} characters (explain why cross-domain access is needed).`;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
async function runHandshakeCreate(options) {
|
|
36
|
+
const validationError = validateHandshakeCreateFields(options.action, options.reason);
|
|
37
|
+
if (validationError) {
|
|
38
|
+
process.stderr.write(`${validationError}\n`);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const ctx = resolveNetworkContext();
|
|
43
|
+
const resolution = await (0, work_context_resolver_1.resolveWorkContext)(ctx, {
|
|
44
|
+
changeRequestId: options.changeRequestId,
|
|
45
|
+
preferredWorkSessionId: options.workSessionId,
|
|
46
|
+
});
|
|
47
|
+
if (resolution.state !== "current_session_resolved" || !resolution.binding) {
|
|
48
|
+
process.stdout.write(`${(0, work_context_resolver_1.renderWorkContextLines)(resolution).join("\n")}\n`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const binding = (0, work_context_resolver_1.requireWorkContextBinding)(resolution, "handshake create");
|
|
52
|
+
const result = await (0, server_sync_1.createAgentHandshake)(ctx, {
|
|
53
|
+
changeRequestId: binding.changeRequestId ?? options.changeRequestId ?? "",
|
|
54
|
+
workSessionId: binding.workSessionId,
|
|
55
|
+
requestedDomain: options.domain,
|
|
56
|
+
requestedAction: options.action.trim(),
|
|
57
|
+
reason: options.reason.trim(),
|
|
58
|
+
});
|
|
59
|
+
process.stdout.write([
|
|
60
|
+
result.was_existing ? "Handshake already open (reused)." : "Handshake created.",
|
|
61
|
+
`ID: ${result.id}`,
|
|
62
|
+
`Target: ${result.target_work_identity_name} (${result.target_work_identity_id})`,
|
|
63
|
+
`Domain: ${result.requested_domain}`,
|
|
64
|
+
`Action: ${result.requested_action}`,
|
|
65
|
+
`Status: ${result.status}`,
|
|
66
|
+
`Expires: ${result.expires_at}`,
|
|
67
|
+
`CR/session: ${result.change_request_id} / ${result.work_session_id}`,
|
|
68
|
+
].join("\n") + "\n");
|
|
69
|
+
}
|
|
70
|
+
async function runHandshakeAcknowledge() {
|
|
71
|
+
process.stdout.write("Handshake acknowledge is not yet available in the CLI. Use the dashboard.\n");
|
|
72
|
+
}
|
|
73
|
+
async function runHandshakeResolve() {
|
|
74
|
+
process.stdout.write("Handshake resolve is not yet available in the CLI. Use the dashboard.\n");
|
|
75
|
+
}
|
|
76
|
+
async function runHandshakeList() {
|
|
77
|
+
process.stdout.write("Handshake list is not yet available in the CLI. Use the dashboard.\n");
|
|
78
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderHealthSummaryRollup = renderHealthSummaryRollup;
|
|
4
|
+
exports.deriveHealthRollup = deriveHealthRollup;
|
|
5
|
+
exports.buildHealthChecks = buildHealthChecks;
|
|
6
|
+
exports.collectHealthSummary = collectHealthSummary;
|
|
7
|
+
exports.runHealth = runHealth;
|
|
8
|
+
const config_1 = require("../config");
|
|
9
|
+
const operator_snapshot_1 = require("../operator-snapshot");
|
|
10
|
+
const work_context_resolver_1 = require("../work-context-resolver");
|
|
11
|
+
function resolveNetworkContext() {
|
|
12
|
+
const cfg = (0, config_1.readConfig)();
|
|
13
|
+
const projectId = process.env.AGENTBRIDGE_PROJECT_ID ?? cfg.projectId;
|
|
14
|
+
const apiKey = process.env.AGENTBRIDGE_API_KEY ?? cfg.apiKey ?? "";
|
|
15
|
+
const apiBaseUrl = process.env.AGENTBRIDGE_BASE_URL ?? cfg.apiBaseUrl ?? "https://agentauth-api-production.up.railway.app";
|
|
16
|
+
if (!projectId || !apiKey)
|
|
17
|
+
return null;
|
|
18
|
+
return { projectId, apiKey, apiBaseUrl };
|
|
19
|
+
}
|
|
20
|
+
function checkLabel(ok) {
|
|
21
|
+
return ok ? "PASS" : "WARN";
|
|
22
|
+
}
|
|
23
|
+
function renderHealthSummaryRollup(rollup) {
|
|
24
|
+
const overall = rollup.overall_status === "pass" ? "PASS" : "WARN";
|
|
25
|
+
const flags = [
|
|
26
|
+
rollup.has_current_session ? "session:yes" : "session:no",
|
|
27
|
+
rollup.has_missing_proof ? "proof:missing" : "proof:ok",
|
|
28
|
+
rollup.has_protocol_warnings ? "protocol:warn" : "protocol:ok",
|
|
29
|
+
];
|
|
30
|
+
return `Summary: ${overall} | completion:${rollup.completion_state} | ${flags.join(" | ")} | next:${rollup.next_action}`;
|
|
31
|
+
}
|
|
32
|
+
function deriveHealthRollup(summary) {
|
|
33
|
+
const pass_count = summary.checks.filter((check) => check.status === "pass").length;
|
|
34
|
+
const warn_count = summary.checks.length - pass_count;
|
|
35
|
+
return {
|
|
36
|
+
overall_status: warn_count > 0 ? "warn" : "pass",
|
|
37
|
+
pass_count,
|
|
38
|
+
warn_count,
|
|
39
|
+
completion_state: summary.snapshot.completion_state,
|
|
40
|
+
next_action: summary.snapshot.next_action,
|
|
41
|
+
has_current_session: summary.snapshot.has_current_session,
|
|
42
|
+
has_other_active_sessions: summary.snapshot.other_active_sessions_count > 0,
|
|
43
|
+
has_missing_proof: summary.snapshot.evidence_missing_count > 0,
|
|
44
|
+
has_protocol_warnings: summary.snapshot.protocol_warnings_count > 0,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function buildHealthChecks(input) {
|
|
48
|
+
return [
|
|
49
|
+
{
|
|
50
|
+
id: "config-project-id",
|
|
51
|
+
status: input.configProjectId ? "pass" : "warn",
|
|
52
|
+
detail: input.configProjectId ? "project configured" : "project missing in local config",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "config-api-key",
|
|
56
|
+
status: input.configApiKey ? "pass" : "warn",
|
|
57
|
+
detail: input.configApiKey ? "api key configured" : "api key missing in local config",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "work-context",
|
|
61
|
+
status: input.workContextResolved ? "pass" : "warn",
|
|
62
|
+
detail: input.workContextResolved ? "current session resolved" : "no active server session",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "protocol-warnings",
|
|
66
|
+
status: input.protocolWarnings > 0 ? "warn" : "pass",
|
|
67
|
+
detail: input.protocolWarnings > 0 ? `${input.protocolWarnings} warning(s)` : "no protocol warnings",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "missing-proof",
|
|
71
|
+
status: input.evidenceMissing > 0 ? "warn" : "pass",
|
|
72
|
+
detail: input.evidenceMissing > 0
|
|
73
|
+
? `${input.evidenceMissing} missing proof artifact(s)`
|
|
74
|
+
: "no proof gaps detected",
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
async function collectHealthSummary(options = {}) {
|
|
79
|
+
const cfg = (0, config_1.readConfig)();
|
|
80
|
+
const ctx = resolveNetworkContext();
|
|
81
|
+
if (!ctx) {
|
|
82
|
+
const fallbackSnapshot = (0, operator_snapshot_1.buildOperatorSnapshot)({
|
|
83
|
+
state: "no_current_session",
|
|
84
|
+
contextSource: "none",
|
|
85
|
+
requestedChangeRequestId: null,
|
|
86
|
+
ambiguousSessions: [],
|
|
87
|
+
message: "No network context available.",
|
|
88
|
+
localServerSessionId: null,
|
|
89
|
+
resolvedServerSessionId: null,
|
|
90
|
+
resolvedChangeRequestId: null,
|
|
91
|
+
binding: null,
|
|
92
|
+
otherActiveSessions: [],
|
|
93
|
+
});
|
|
94
|
+
const checks = buildHealthChecks({
|
|
95
|
+
configProjectId: !!cfg.projectId,
|
|
96
|
+
configApiKey: !!cfg.apiKey,
|
|
97
|
+
workContextResolved: false,
|
|
98
|
+
protocolWarnings: 0,
|
|
99
|
+
evidenceMissing: 0,
|
|
100
|
+
});
|
|
101
|
+
checks[2] = {
|
|
102
|
+
id: "network-context",
|
|
103
|
+
status: "warn",
|
|
104
|
+
detail: "no active API context",
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
snapshot: fallbackSnapshot,
|
|
108
|
+
checks,
|
|
109
|
+
rollup: deriveHealthRollup({ snapshot: fallbackSnapshot, checks }),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const resolution = await (0, work_context_resolver_1.resolveWorkContext)(ctx, {
|
|
113
|
+
includeOtherActiveSessions: options.includeOtherActiveSessions === true,
|
|
114
|
+
});
|
|
115
|
+
const snapshot = (0, operator_snapshot_1.buildOperatorSnapshot)(resolution);
|
|
116
|
+
const checks = buildHealthChecks({
|
|
117
|
+
configProjectId: !!cfg.projectId,
|
|
118
|
+
configApiKey: !!cfg.apiKey,
|
|
119
|
+
workContextResolved: resolution.state === "current_session_resolved",
|
|
120
|
+
protocolWarnings: snapshot.protocol_warnings_count,
|
|
121
|
+
evidenceMissing: snapshot.evidence_missing_count,
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
snapshot,
|
|
125
|
+
checks,
|
|
126
|
+
rollup: deriveHealthRollup({ snapshot, checks }),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async function runHealth(options = {}) {
|
|
130
|
+
const summary = await collectHealthSummary({
|
|
131
|
+
includeOtherActiveSessions: options.json === true,
|
|
132
|
+
});
|
|
133
|
+
if (options.json) {
|
|
134
|
+
process.stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const lines = [];
|
|
138
|
+
lines.push("AgentBridge Health");
|
|
139
|
+
lines.push(renderHealthSummaryRollup(summary.rollup));
|
|
140
|
+
lines.push(...(0, operator_snapshot_1.renderOperatorSnapshotHuman)(summary.snapshot).split("\n"));
|
|
141
|
+
lines.push("");
|
|
142
|
+
lines.push("Checks:");
|
|
143
|
+
for (const check of summary.checks) {
|
|
144
|
+
lines.push(`- ${check.status === "pass" ? "PASS" : "WARN"} ${check.id}: ${check.detail}`);
|
|
145
|
+
}
|
|
146
|
+
lines.push("");
|
|
147
|
+
lines.push("Rollup:");
|
|
148
|
+
lines.push(`- ${checkLabel(summary.rollup.overall_status === "pass")} overall`);
|
|
149
|
+
lines.push(`- completion: ${summary.rollup.completion_state}`);
|
|
150
|
+
lines.push(`- pass: ${summary.rollup.pass_count}`);
|
|
151
|
+
lines.push(`- warn: ${summary.rollup.warn_count}`);
|
|
152
|
+
lines.push(`- next: ${summary.rollup.next_action}`);
|
|
153
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
154
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runIdentityList = runIdentityList;
|
|
4
|
+
const config_1 = require("../config");
|
|
5
|
+
const server_sync_1 = require("../server-sync");
|
|
6
|
+
function normalize(value) {
|
|
7
|
+
const trimmed = value?.trim();
|
|
8
|
+
return trimmed && trimmed.length > 0 ? trimmed : "unknown";
|
|
9
|
+
}
|
|
10
|
+
async function runIdentityList() {
|
|
11
|
+
const cfg = (0, config_1.readConfig)();
|
|
12
|
+
const configuredActiveAgentId = cfg.activeAgentId?.trim() || "(none)";
|
|
13
|
+
const ctx = (0, config_1.contextFromConfig)();
|
|
14
|
+
const [callerPacket, identities] = await Promise.all([
|
|
15
|
+
(0, server_sync_1.fetchCallerIdentityPacket)(ctx),
|
|
16
|
+
(0, server_sync_1.listWorkIdentities)(ctx),
|
|
17
|
+
]);
|
|
18
|
+
const callerWorkIdentityId = callerPacket?.work_identity?.id ?? null;
|
|
19
|
+
const callerIdentity = callerWorkIdentityId
|
|
20
|
+
? identities.find((identity) => identity.id === callerWorkIdentityId) ?? null
|
|
21
|
+
: null;
|
|
22
|
+
const suggestedActiveAgentId = callerIdentity?.name?.trim() ||
|
|
23
|
+
callerPacket?.work_identity?.name?.trim() ||
|
|
24
|
+
"(none)";
|
|
25
|
+
const rows = identities.map((identity) => ({
|
|
26
|
+
id: identity.id,
|
|
27
|
+
name: normalize(identity.name),
|
|
28
|
+
domainName: normalize(identity.domain?.name ?? identity.domain?.displayName ?? null),
|
|
29
|
+
isCaller: callerWorkIdentityId === identity.id,
|
|
30
|
+
matchesConfigured: configuredActiveAgentId !== "(none)" &&
|
|
31
|
+
(identity.id === configuredActiveAgentId ||
|
|
32
|
+
identity.name?.toLowerCase() === configuredActiveAgentId.toLowerCase()),
|
|
33
|
+
}));
|
|
34
|
+
const lines = [
|
|
35
|
+
"AgentBridge identities",
|
|
36
|
+
`Project: ${ctx.projectId}`,
|
|
37
|
+
`Configured active agent: ${configuredActiveAgentId}`,
|
|
38
|
+
`Caller WorkIdentity: ${callerWorkIdentityId ?? "unresolved"}`,
|
|
39
|
+
"Available project identities:",
|
|
40
|
+
];
|
|
41
|
+
if (rows.length === 0) {
|
|
42
|
+
lines.push("- (none)");
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
for (const row of rows) {
|
|
46
|
+
const tags = [];
|
|
47
|
+
if (row.isCaller)
|
|
48
|
+
tags.push("current caller");
|
|
49
|
+
if (row.matchesConfigured)
|
|
50
|
+
tags.push("configured active agent");
|
|
51
|
+
const tagSuffix = tags.length > 0 ? ` / ${tags.join(", ")}` : "";
|
|
52
|
+
lines.push(`- agent: ${row.name} / work identity: ${row.id} / domain: ${row.domainName}${tagSuffix}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
lines.push(`Suggested activeAgentId: ${suggestedActiveAgentId}`);
|
|
56
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
57
|
+
}
|