brainclaw 0.19.10 → 0.19.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/cli.js +1 -0
- package/dist/commands/bootstrap.js +17 -1
- package/dist/commands/env.js +7 -1
- package/dist/commands/init.js +1 -0
- package/dist/commands/mcp.js +76 -3
- package/dist/commands/version.js +3 -1
- package/dist/commands/whoami.js +11 -1
- package/dist/core/bootstrap.js +416 -60
- package/dist/core/brainclaw-version.js +303 -62
- package/dist/core/schema.js +28 -0
- package/docs/cli.md +15 -1
- package/docs/integrations/mcp.md +29 -7
- package/docs/mcp-schema-changelog.md +6 -0
- package/docs/quickstart.md +22 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -129,6 +129,7 @@ After that, the agent should stay on Brainclaw's MCP path for live state:
|
|
|
129
129
|
|
|
130
130
|
```text
|
|
131
131
|
bclaw_session_start -> open session + return board/context
|
|
132
|
+
bclaw_get_execution_context -> inspect local tooling + notice Brainclaw package updates
|
|
132
133
|
bclaw_get_context -> fetch fresh prompt-ready context for a path
|
|
133
134
|
bclaw_list_plans -> inspect shared work
|
|
134
135
|
bclaw_claim -> claim scope before editing
|
|
@@ -177,6 +178,8 @@ If you want a machine-level CLI for operator workflows, debugging, or repeated l
|
|
|
177
178
|
npm install -g brainclaw
|
|
178
179
|
```
|
|
179
180
|
|
|
181
|
+
By default, Brainclaw's update checks for end-user installs follow the public npm `latest` channel. Projects that need a different track can override `brainclaw_update_source`, for example to use `prelaunch` or a local tarball channel.
|
|
182
|
+
|
|
180
183
|
If you are working from source while developing Brainclaw itself:
|
|
181
184
|
|
|
182
185
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -515,6 +515,7 @@ program
|
|
|
515
515
|
.option('--refresh', 'Force a fresh bootstrap scan instead of reusing the current profile')
|
|
516
516
|
.option('--interview', 'Render the adaptive interview prompts instead of the bootstrap summary')
|
|
517
517
|
.option('--audience <audience>', 'Target interview prompts for cli, ide_chat, or any')
|
|
518
|
+
.option('--answers-file <path>', 'Load structured bootstrap interview answers from a JSON file')
|
|
518
519
|
.option('--apply', 'Import the current bootstrap proposal into canonical memory')
|
|
519
520
|
.option('--uninstall', 'Deactivate the last bootstrap import managed by this workspace')
|
|
520
521
|
.option('-y, --yes', 'Skip confirmation prompts for apply/uninstall')
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
1
2
|
import readline from 'node:readline/promises';
|
|
2
3
|
import { stdin as input, stdout as output } from 'node:process';
|
|
3
4
|
import { memoryExists } from '../core/io.js';
|
|
4
5
|
import { applyBootstrapImport, renderBootstrapInterview, renderBootstrapSummary, runBootstrapProfile, uninstallBootstrapImport, } from '../core/bootstrap.js';
|
|
6
|
+
import { BootstrapInterviewAnswerSchema } from '../core/schema.js';
|
|
5
7
|
export async function runBootstrap(options = {}) {
|
|
6
8
|
const cwd = options.cwd ?? process.cwd();
|
|
7
9
|
if (!memoryExists(cwd)) {
|
|
@@ -14,6 +16,7 @@ export async function runBootstrap(options = {}) {
|
|
|
14
16
|
process.exit(1);
|
|
15
17
|
}
|
|
16
18
|
const audience = resolveBootstrapInterviewAudience(options.audience);
|
|
19
|
+
const interviewAnswers = loadBootstrapInterviewAnswers(options.answersFile);
|
|
17
20
|
if (options.uninstall) {
|
|
18
21
|
await confirmBootstrapAction('Remove the last bootstrap import?', options.yes);
|
|
19
22
|
const result = uninstallBootstrapImport(cwd);
|
|
@@ -21,7 +24,7 @@ export async function runBootstrap(options = {}) {
|
|
|
21
24
|
console.log('No bootstrap import receipt found.');
|
|
22
25
|
return;
|
|
23
26
|
}
|
|
24
|
-
console.log(`✔ Bootstrap uninstall completed: ${result.deactivatedCount} instruction(s) deactivated, ${result.skippedCount} artifact(s) skipped.`);
|
|
27
|
+
console.log(`✔ Bootstrap uninstall completed: ${result.deactivatedCount} instruction(s) deactivated, ${result.deletedCount} artifact(s) deleted, ${result.skippedCount} artifact(s) skipped.`);
|
|
25
28
|
return;
|
|
26
29
|
}
|
|
27
30
|
if (options.apply) {
|
|
@@ -29,6 +32,7 @@ export async function runBootstrap(options = {}) {
|
|
|
29
32
|
const result = applyBootstrapImport({
|
|
30
33
|
target: options.for,
|
|
31
34
|
refresh: options.refresh,
|
|
35
|
+
interviewAnswers,
|
|
32
36
|
cwd,
|
|
33
37
|
});
|
|
34
38
|
console.log(`✔ Bootstrap import applied: ${result.createdCount} item(s) created, ${result.skippedCount} suggestion(s) skipped.`);
|
|
@@ -40,6 +44,7 @@ export async function runBootstrap(options = {}) {
|
|
|
40
44
|
const result = runBootstrapProfile({
|
|
41
45
|
target: options.for,
|
|
42
46
|
refresh: options.refresh,
|
|
47
|
+
interviewAnswers,
|
|
43
48
|
cwd,
|
|
44
49
|
});
|
|
45
50
|
if (options.json) {
|
|
@@ -76,6 +81,17 @@ function resolveBootstrapInterviewAudience(value) {
|
|
|
76
81
|
}
|
|
77
82
|
throw new Error(`Unsupported bootstrap interview audience '${value}'. Use cli, ide_chat, or any.`);
|
|
78
83
|
}
|
|
84
|
+
function loadBootstrapInterviewAnswers(filepath) {
|
|
85
|
+
if (!filepath) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
const raw = fs.readFileSync(filepath, 'utf-8');
|
|
89
|
+
const parsed = JSON.parse(raw);
|
|
90
|
+
if (!Array.isArray(parsed)) {
|
|
91
|
+
throw new Error(`Bootstrap interview answers file must contain a JSON array: ${filepath}`);
|
|
92
|
+
}
|
|
93
|
+
return parsed.map((entry) => BootstrapInterviewAnswerSchema.parse(entry));
|
|
94
|
+
}
|
|
79
95
|
async function confirmBootstrapAction(question, yes) {
|
|
80
96
|
if (yes) {
|
|
81
97
|
return;
|
package/dist/commands/env.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { memoryExists } from '../core/io.js';
|
|
2
2
|
import { loadConfig } from '../core/config.js';
|
|
3
3
|
import { assessAgentIntegrationReadiness } from '../core/agent-integrations.js';
|
|
4
|
-
import { assessBrainclawVersion } from '../core/brainclaw-version.js';
|
|
4
|
+
import { assessBrainclawVersion, checkBrainclawInstallableUpdate, renderBrainclawInstallableUpdateNotice, } from '../core/brainclaw-version.js';
|
|
5
5
|
import { buildExecutionContext, compactExecutionContext, renderExecutionContextSummary } from '../core/execution-context.js';
|
|
6
6
|
import { buildAgentToolingContext, renderAgentToolingSummary } from '../core/agent-context.js';
|
|
7
7
|
export function runEnv(options = {}) {
|
|
@@ -14,11 +14,14 @@ export function runEnv(options = {}) {
|
|
|
14
14
|
const config = loadConfig(cwd);
|
|
15
15
|
const integrationReadiness = assessAgentIntegrationReadiness(config, cwd);
|
|
16
16
|
const brainclawVersion = assessBrainclawVersion(config);
|
|
17
|
+
const installableUpdate = checkBrainclawInstallableUpdate(config, cwd, { useDefaultNpmSource: true });
|
|
18
|
+
const installableUpdateNotice = renderBrainclawInstallableUpdateNotice(installableUpdate);
|
|
17
19
|
const agentTooling = options.agentTooling ? buildAgentToolingContext({ cwd }) : undefined;
|
|
18
20
|
if (options.json) {
|
|
19
21
|
console.log(JSON.stringify({
|
|
20
22
|
execution_context: executionContext,
|
|
21
23
|
brainclaw_version: brainclawVersion,
|
|
24
|
+
installable_update: installableUpdate,
|
|
22
25
|
declared_agent_integrations: config.agent_integrations,
|
|
23
26
|
integration_readiness: integrationReadiness,
|
|
24
27
|
...(agentTooling ? { agent_tooling: agentTooling } : {}),
|
|
@@ -33,6 +36,9 @@ export function runEnv(options = {}) {
|
|
|
33
36
|
console.log(`Upgrade benefits: ${brainclawVersion.upgrade_message}`);
|
|
34
37
|
}
|
|
35
38
|
}
|
|
39
|
+
if (installableUpdateNotice) {
|
|
40
|
+
console.log(installableUpdateNotice);
|
|
41
|
+
}
|
|
36
42
|
console.log(`Declared agent integrations: ${config.agent_integrations.declarations.length}`);
|
|
37
43
|
const missingDeclarations = integrationReadiness.filter((entry) => !entry.ready);
|
|
38
44
|
if (missingDeclarations.length > 0) {
|
package/dist/commands/init.js
CHANGED
|
@@ -243,6 +243,7 @@ export async function runInit(options = {}) {
|
|
|
243
243
|
if ((onboardingPreflight.importPlan.interview?.question_count ?? 0) > 0) {
|
|
244
244
|
console.log('');
|
|
245
245
|
console.log(`Interview: run 'brainclaw bootstrap --interview --audience cli' for terminal agents or '--audience ide_chat' for IDE chat agents.`);
|
|
246
|
+
console.log(`Apply confirmed answers: write a JSON answers file and run 'brainclaw bootstrap --answers-file <path> --apply'.`);
|
|
246
247
|
}
|
|
247
248
|
else if ((onboardingPreflight.profile.gaps?.length ?? 0) > 0) {
|
|
248
249
|
console.log('');
|
package/dist/commands/mcp.js
CHANGED
|
@@ -2,11 +2,12 @@ import readline from 'node:readline';
|
|
|
2
2
|
import { Worker } from 'node:worker_threads';
|
|
3
3
|
import { getTriggeredItems, renderTriggeredItems } from '../core/lifecycle.js';
|
|
4
4
|
import { resolveCrossProjectTarget, writeCrossProjectNote } from '../core/cross-project.js';
|
|
5
|
-
import { renderBootstrapSummary, runBootstrapProfile } from '../core/bootstrap.js';
|
|
5
|
+
import { applyBootstrapImport, renderBootstrapInterview, renderBootstrapSummary, runBootstrapProfile, uninstallBootstrapImport } from '../core/bootstrap.js';
|
|
6
6
|
import { buildAgentToolingContext, renderAgentToolingSummary } from '../core/agent-context.js';
|
|
7
7
|
import { buildCoordinationSnapshot } from '../core/coordination.js';
|
|
8
8
|
import { buildContext, renderContextMarkdown, renderContextPromptTemplate } from '../core/context.js';
|
|
9
9
|
import { buildExecutionContext, renderExecutionContextSummary } from '../core/execution-context.js';
|
|
10
|
+
import { checkBrainclawInstallableUpdate, renderBrainclawInstallableUpdateNotice } from '../core/brainclaw-version.js';
|
|
10
11
|
import { loadConfig } from '../core/config.js';
|
|
11
12
|
import { loadState, persistState } from '../core/state.js';
|
|
12
13
|
import { memoryExists } from '../core/io.js';
|
|
@@ -30,6 +31,7 @@ import { detectAiAgent } from '../core/ai-agent-detection.js';
|
|
|
30
31
|
import { checkGitPresence, scanGitRepos, parseRoots, parseRepoSelection, parseAgentSelection, runGlobalInstall, initReposAndConfigureAgents, readSetupState, ALL_KNOWN_AGENTS, } from './setup.js';
|
|
31
32
|
import { resolveTargetStore, resolveStoreChain } from '../core/store-resolution.js';
|
|
32
33
|
import { readUnseenEvents, buildNotificationSummary } from '../core/event-log.js';
|
|
34
|
+
import { BootstrapInterviewAnswerSchema } from '../core/schema.js';
|
|
33
35
|
export const SCHEMA_VERSION = '0.6.0';
|
|
34
36
|
export const MCP_PROTOCOL_VERSIONS = ['2025-11-25', '2024-11-05'];
|
|
35
37
|
export const MCP_SERVER_NOT_INITIALIZED = -32002;
|
|
@@ -67,12 +69,21 @@ export const MCP_READ_TOOLS = [
|
|
|
67
69
|
properties: {
|
|
68
70
|
target: { type: 'string', description: 'Optional path or scope to tailor the bootstrap.' },
|
|
69
71
|
refresh: { type: 'boolean', description: 'Force a fresh bootstrap scan.' },
|
|
72
|
+
audience: { type: 'string', description: 'Optional interview audience filter: cli, ide_chat, or any.' },
|
|
73
|
+
interview: { type: 'boolean', description: 'Render interview text instead of the summary text.' },
|
|
74
|
+
apply: { type: 'boolean', description: 'Apply the current import proposal into canonical memory.' },
|
|
75
|
+
uninstall: { type: 'boolean', description: 'Uninstall the last bootstrap-managed import.' },
|
|
76
|
+
interviewAnswers: {
|
|
77
|
+
type: 'array',
|
|
78
|
+
description: 'Optional structured interview answers. Each answer may include question_id, response_text, response_items, response_boolean, and explicit suggestions.',
|
|
79
|
+
items: { type: 'object' },
|
|
80
|
+
},
|
|
70
81
|
},
|
|
71
82
|
},
|
|
72
83
|
},
|
|
73
84
|
{
|
|
74
85
|
name: 'bclaw_get_execution_context',
|
|
75
|
-
description: 'Inspect the local execution environment and optionally agent tooling signals.',
|
|
86
|
+
description: 'Inspect the local execution environment, installable Brainclaw update channel, and optionally agent tooling signals.',
|
|
76
87
|
inputSchema: {
|
|
77
88
|
type: 'object',
|
|
78
89
|
properties: {
|
|
@@ -506,6 +517,18 @@ export function createToolErrorResponse(kind, message, details) {
|
|
|
506
517
|
},
|
|
507
518
|
}, true);
|
|
508
519
|
}
|
|
520
|
+
function normalizeBootstrapInterviewAnswersArg(value) {
|
|
521
|
+
if (!Array.isArray(value)) {
|
|
522
|
+
return [];
|
|
523
|
+
}
|
|
524
|
+
return value.map((entry) => BootstrapInterviewAnswerSchema.parse(entry));
|
|
525
|
+
}
|
|
526
|
+
function normalizeBootstrapInterviewAudienceArg(value) {
|
|
527
|
+
if (value === 'cli' || value === 'ide_chat' || value === 'any') {
|
|
528
|
+
return value;
|
|
529
|
+
}
|
|
530
|
+
return 'any';
|
|
531
|
+
}
|
|
509
532
|
function requireObjectParams(params, id) {
|
|
510
533
|
if (params === undefined) {
|
|
511
534
|
return {};
|
|
@@ -1040,19 +1063,64 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
1040
1063
|
};
|
|
1041
1064
|
}
|
|
1042
1065
|
if (name === 'bclaw_bootstrap') {
|
|
1066
|
+
const interviewAnswers = normalizeBootstrapInterviewAnswersArg(args.interviewAnswers);
|
|
1067
|
+
if (args.apply && args.uninstall) {
|
|
1068
|
+
throw new Error('bclaw_bootstrap does not allow apply and uninstall at the same time.');
|
|
1069
|
+
}
|
|
1070
|
+
if (args.uninstall) {
|
|
1071
|
+
const result = uninstallBootstrapImport(cwd);
|
|
1072
|
+
const text = !result.receipt
|
|
1073
|
+
? 'No bootstrap import receipt found.'
|
|
1074
|
+
: `Bootstrap uninstall completed: ${result.deactivatedCount} instruction(s) deactivated, ${result.deletedCount} artifact(s) deleted, ${result.skippedCount} artifact(s) skipped.`;
|
|
1075
|
+
return {
|
|
1076
|
+
content: [{ type: 'text', text }],
|
|
1077
|
+
structuredContent: {
|
|
1078
|
+
receipt: result.receipt,
|
|
1079
|
+
deactivated_count: result.deactivatedCount,
|
|
1080
|
+
deleted_count: result.deletedCount,
|
|
1081
|
+
skipped_count: result.skippedCount,
|
|
1082
|
+
},
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
if (args.apply) {
|
|
1086
|
+
const applied = applyBootstrapImport({
|
|
1087
|
+
target: args.target,
|
|
1088
|
+
refresh: args.refresh,
|
|
1089
|
+
interviewAnswers,
|
|
1090
|
+
cwd,
|
|
1091
|
+
});
|
|
1092
|
+
return {
|
|
1093
|
+
content: [{
|
|
1094
|
+
type: 'text',
|
|
1095
|
+
text: `Bootstrap import applied: ${applied.createdCount} item(s) created, ${applied.skippedCount} suggestion(s) skipped.`,
|
|
1096
|
+
}],
|
|
1097
|
+
structuredContent: {
|
|
1098
|
+
created_count: applied.createdCount,
|
|
1099
|
+
skipped_count: applied.skippedCount,
|
|
1100
|
+
receipt: applied.receipt,
|
|
1101
|
+
import_plan: applied.proposal,
|
|
1102
|
+
},
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1043
1105
|
const result = runBootstrapProfile({
|
|
1044
1106
|
target: args.target,
|
|
1045
1107
|
refresh: args.refresh,
|
|
1108
|
+
interviewAnswers,
|
|
1046
1109
|
cwd,
|
|
1047
1110
|
});
|
|
1111
|
+
const audience = normalizeBootstrapInterviewAudienceArg(args.audience);
|
|
1112
|
+
const text = args.interview
|
|
1113
|
+
? renderBootstrapInterview(result, audience)
|
|
1114
|
+
: renderBootstrapSummary(result);
|
|
1048
1115
|
return {
|
|
1049
|
-
content: [{ type: 'text', text
|
|
1116
|
+
content: [{ type: 'text', text }],
|
|
1050
1117
|
structuredContent: {
|
|
1051
1118
|
summary: result.profile.summary,
|
|
1052
1119
|
target: result.profile.target,
|
|
1053
1120
|
repo_fingerprint: result.profile.repo_fingerprint,
|
|
1054
1121
|
sources_scanned: result.profile.sources_scanned,
|
|
1055
1122
|
workspace_kind: result.profile.workspace_kind,
|
|
1123
|
+
onboarding_mode: result.profile.onboarding_mode,
|
|
1056
1124
|
confidence: result.profile.confidence,
|
|
1057
1125
|
native_instruction_files: result.profile.native_instruction_files,
|
|
1058
1126
|
gaps: result.profile.gaps,
|
|
@@ -1066,15 +1134,20 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
1066
1134
|
}
|
|
1067
1135
|
if (name === 'bclaw_get_execution_context') {
|
|
1068
1136
|
const executionContext = buildExecutionContext({ cwd });
|
|
1137
|
+
const config = loadConfig(cwd);
|
|
1138
|
+
const installableUpdate = checkBrainclawInstallableUpdate(config, cwd, { useDefaultNpmSource: true });
|
|
1139
|
+
const installableUpdateNotice = renderBrainclawInstallableUpdateNotice(installableUpdate);
|
|
1069
1140
|
const agentTooling = args.includeAgentTooling ? buildAgentToolingContext({ cwd }) : undefined;
|
|
1070
1141
|
const text = [
|
|
1071
1142
|
renderExecutionContextSummary(executionContext, true),
|
|
1143
|
+
...(installableUpdateNotice ? ['', installableUpdateNotice] : []),
|
|
1072
1144
|
...(agentTooling ? ['', renderAgentToolingSummary(agentTooling)] : []),
|
|
1073
1145
|
].join('\n');
|
|
1074
1146
|
return {
|
|
1075
1147
|
content: [{ type: 'text', text }],
|
|
1076
1148
|
structuredContent: {
|
|
1077
1149
|
execution_context: executionContext,
|
|
1150
|
+
installable_update: installableUpdate,
|
|
1078
1151
|
...(agentTooling ? { agent_tooling: agentTooling } : {}),
|
|
1079
1152
|
},
|
|
1080
1153
|
};
|
package/dist/commands/version.js
CHANGED
|
@@ -31,7 +31,9 @@ export function runVersion(options = {}) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
const assessment = assessBrainclawVersion(config);
|
|
34
|
-
const updateCheck = options.check
|
|
34
|
+
const updateCheck = options.check
|
|
35
|
+
? checkBrainclawInstallableUpdate(config, cwd, { useDefaultNpmSource: true })
|
|
36
|
+
: undefined;
|
|
35
37
|
const result = {
|
|
36
38
|
initialized,
|
|
37
39
|
...assessment,
|
package/dist/commands/whoami.js
CHANGED
|
@@ -4,7 +4,7 @@ import { loadConfig } from '../core/config.js';
|
|
|
4
4
|
import { resolveCurrentHostId } from '../core/host.js';
|
|
5
5
|
import { buildOperationalIdentity } from '../core/identity.js';
|
|
6
6
|
import { assessAgentIntegrationReadiness } from '../core/agent-integrations.js';
|
|
7
|
-
import { assessBrainclawVersion } from '../core/brainclaw-version.js';
|
|
7
|
+
import { assessBrainclawVersion, checkBrainclawInstallableUpdate, renderBrainclawInstallableUpdateNotice, } from '../core/brainclaw-version.js';
|
|
8
8
|
import { buildExecutionContext, compactExecutionContext } from '../core/execution-context.js';
|
|
9
9
|
import { buildAgentToolingContext } from '../core/agent-context.js';
|
|
10
10
|
export function runWhoami(options = {}) {
|
|
@@ -18,6 +18,8 @@ export function runWhoami(options = {}) {
|
|
|
18
18
|
const executionContext = compactExecutionContext(buildExecutionContext({ cwd }));
|
|
19
19
|
const integrationReadiness = assessAgentIntegrationReadiness(config, cwd);
|
|
20
20
|
const brainclawVersion = assessBrainclawVersion(config);
|
|
21
|
+
const installableUpdate = checkBrainclawInstallableUpdate(config, cwd, { useDefaultNpmSource: true });
|
|
22
|
+
const installableUpdateNotice = renderBrainclawInstallableUpdateNotice(installableUpdate);
|
|
21
23
|
const agentTooling = buildAgentToolingContext({ cwd });
|
|
22
24
|
let identity;
|
|
23
25
|
try {
|
|
@@ -45,6 +47,7 @@ export function runWhoami(options = {}) {
|
|
|
45
47
|
env_session: process.env.BRAINCLAW_SESSION_ID ?? null,
|
|
46
48
|
env_host: process.env.BRAINCLAW_HOST_ID ?? null,
|
|
47
49
|
brainclaw_version: brainclawVersion,
|
|
50
|
+
installable_update: installableUpdate,
|
|
48
51
|
declared_agent_integrations: config.agent_integrations,
|
|
49
52
|
integration_readiness: integrationReadiness,
|
|
50
53
|
execution_context: executionContext,
|
|
@@ -80,6 +83,13 @@ export function runWhoami(options = {}) {
|
|
|
80
83
|
if (result.brainclaw_version.status !== 'ok') {
|
|
81
84
|
console.log(` Version : ${result.brainclaw_version.message}`);
|
|
82
85
|
}
|
|
86
|
+
if (installableUpdateNotice) {
|
|
87
|
+
const lines = installableUpdateNotice.split('\n');
|
|
88
|
+
console.log(` Update : ${lines[0]}`);
|
|
89
|
+
for (const line of lines.slice(1)) {
|
|
90
|
+
console.log(` ${line}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
83
93
|
console.log(` Declared integrations: ${result.declared_agent_integrations.declarations.length}`);
|
|
84
94
|
const missingIntegrations = result.integration_readiness.filter((entry) => !entry.ready);
|
|
85
95
|
if (missingIntegrations.length > 0) {
|