@polderlabs/bizar 6.2.2 → 6.2.4
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/cli/bin.mjs +51 -1
- package/cli/commands/cline-cmd.mjs +289 -0
- package/cli/commands/rca.mjs +198 -0
- package/cli/commands/rca.test.mjs +99 -0
- package/cli/commands/setup-provider.mjs +249 -75
- package/cli/commands/setup-provider.test.mjs +198 -98
- package/cli/commands/validate.mjs +92 -0
- package/cli/commands/validate.test.mjs +37 -0
- package/config/agents/_shared/AGENT_BASELINE.md +40 -1
- package/config/agents/_shared/CLINE_TOOLS.md +398 -0
- package/config/agents/agent-browser.md +1 -1
- package/config/agents/baldr.md +1 -1
- package/config/agents/forseti.md +1 -1
- package/config/agents/frigg.md +1 -1
- package/config/agents/heimdall.md +1 -1
- package/config/agents/hermod.md +1 -1
- package/config/agents/mimir.md +1 -1
- package/config/agents/odin.md +1 -1
- package/config/agents/quick.md +1 -1
- package/config/agents/semble-search.md +1 -1
- package/config/agents/thor.md +1 -1
- package/config/agents/tyr.md +1 -1
- package/config/agents/vidarr.md +1 -1
- package/config/agents/vor.md +1 -1
- package/package.json +2 -2
- package/plugins/bizar/package.json +17 -6
- package/plugins/bizar/src/clineruntime.ts +19 -4
- package/plugins/bizar/src/options.ts +14 -7
- package/plugins/bizar/tests/clineruntime-config.test.ts +69 -7
- package/plugins/bizar/tests/options.test.ts +6 -6
- package/scripts/bh-full-e2e.mjs +79 -4
- package/scripts/check-agents.mjs +73 -0
|
@@ -73,7 +73,7 @@ describe("ClineRuntime.startSession — execution plumbing", () => {
|
|
|
73
73
|
};
|
|
74
74
|
const runtime = new ClineRuntime({
|
|
75
75
|
logger: stubLogger(),
|
|
76
|
-
defaultMaxConsecutiveMistakes:
|
|
76
|
+
defaultMaxConsecutiveMistakes: 10,
|
|
77
77
|
defaultOnConsecutiveMistakeLimitReached: recovery,
|
|
78
78
|
});
|
|
79
79
|
(runtime as unknown as { core: unknown }).core = makeFakeCore();
|
|
@@ -84,16 +84,57 @@ describe("ClineRuntime.startSession — execution plumbing", () => {
|
|
|
84
84
|
prompt: "go",
|
|
85
85
|
});
|
|
86
86
|
const cfg = capturedConfig[0]!.config;
|
|
87
|
-
expect(cfg.execution).toEqual({ maxConsecutiveMistakes:
|
|
87
|
+
expect(cfg.execution).toEqual({ maxConsecutiveMistakes: 10 });
|
|
88
88
|
expect(typeof cfg.onConsecutiveMistakeLimitReached).toBe("function");
|
|
89
89
|
// Invoke the wire-through function and confirm it IS the recovery closure.
|
|
90
90
|
const fn = cfg.onConsecutiveMistakeLimitReached as (ctx: ConsecutiveMistakeLimitContext) => unknown;
|
|
91
|
-
fn({ iteration: 1, consecutiveMistakes: 3, maxConsecutiveMistakes:
|
|
91
|
+
fn({ iteration: 1, consecutiveMistakes: 3, maxConsecutiveMistakes: 10, reason: "invalid_tool_call" });
|
|
92
92
|
expect(recoveryCalls.length).toBe(1);
|
|
93
93
|
expect(recoveryCalls[0]!.reason).toBe("invalid_tool_call");
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
test("
|
|
96
|
+
test("v6.2.4 — plugin default is a FLOOR; CLI default of 3 is bumped to plugin default", async () => {
|
|
97
|
+
// This is the v6.2.0 → v6.2.4 regression test. Previously the
|
|
98
|
+
// caller's maxConsecutiveMistakes (e.g. the Cline CLI's --retries
|
|
99
|
+
// default of 3) would silently override the plugin's higher
|
|
100
|
+
// default. Now we use Math.max so the plugin's 10 wins.
|
|
101
|
+
const runtime = new ClineRuntime({
|
|
102
|
+
logger: stubLogger(),
|
|
103
|
+
defaultMaxConsecutiveMistakes: 10,
|
|
104
|
+
});
|
|
105
|
+
(runtime as unknown as { core: unknown }).core = makeFakeCore();
|
|
106
|
+
await runtime.startSession({
|
|
107
|
+
providerId: "anthropic",
|
|
108
|
+
modelId: "claude-sonnet-4-6",
|
|
109
|
+
workspaceRoot: "/tmp",
|
|
110
|
+
prompt: "go",
|
|
111
|
+
execution: { maxConsecutiveMistakes: 3, reminderAfterIterations: 8 },
|
|
112
|
+
});
|
|
113
|
+
const cfg = capturedConfig[0]!.config;
|
|
114
|
+
expect(cfg.execution?.maxConsecutiveMistakes).toBe(10,
|
|
115
|
+
"plugin default must win over CLI default of 3 (was a v6.0 regression)");
|
|
116
|
+
expect(cfg.execution?.reminderAfterIterations).toBe(8, "other caller fields pass through");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("caller-supplied HIGHER execution.maxConsecutiveMistakes still wins", async () => {
|
|
120
|
+
const runtime = new ClineRuntime({
|
|
121
|
+
logger: stubLogger(),
|
|
122
|
+
defaultMaxConsecutiveMistakes: 10,
|
|
123
|
+
});
|
|
124
|
+
(runtime as unknown as { core: unknown }).core = makeFakeCore();
|
|
125
|
+
await runtime.startSession({
|
|
126
|
+
providerId: "anthropic",
|
|
127
|
+
modelId: "claude-sonnet-4-6",
|
|
128
|
+
workspaceRoot: "/tmp",
|
|
129
|
+
prompt: "go",
|
|
130
|
+
execution: { maxConsecutiveMistakes: 20, reminderAfterIterations: 8 },
|
|
131
|
+
});
|
|
132
|
+
const cfg = capturedConfig[0]!.config;
|
|
133
|
+
expect(cfg.execution?.maxConsecutiveMistakes).toBe(20,
|
|
134
|
+
"user can still raise the limit with --retries 20");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("caller-supplied execution.maxConsecutiveMistakes wins over default (legacy behavior)", async () => {
|
|
97
138
|
const runtime = new ClineRuntime({
|
|
98
139
|
logger: stubLogger(),
|
|
99
140
|
defaultMaxConsecutiveMistakes: 4,
|
|
@@ -180,7 +221,7 @@ describe("ClineRuntime.startSession — agent teams plumbing (v6.2.0)", () => {
|
|
|
180
221
|
expect(cfg.enableAgentTeams).toBe(true);
|
|
181
222
|
});
|
|
182
223
|
|
|
183
|
-
test("enableTools is true, enableSpawnAgent is
|
|
224
|
+
test("enableTools is true, enableSpawnAgent is true (subagents + task tool)", async () => {
|
|
184
225
|
const runtime = new ClineRuntime({ logger: stubLogger() });
|
|
185
226
|
(runtime as unknown as { core: unknown }).core = makeFakeCore();
|
|
186
227
|
await runtime.startSession({
|
|
@@ -191,7 +232,8 @@ describe("ClineRuntime.startSession — agent teams plumbing (v6.2.0)", () => {
|
|
|
191
232
|
});
|
|
192
233
|
const cfg = capturedConfig[0]!.config;
|
|
193
234
|
expect(cfg.enableTools).toBe(true);
|
|
194
|
-
expect(cfg.enableSpawnAgent).toBe(
|
|
235
|
+
expect(cfg.enableSpawnAgent).toBe(true,
|
|
236
|
+
"enableSpawnAgent must be true so Odin can use the `task` tool and `use_subagents`");
|
|
195
237
|
});
|
|
196
238
|
|
|
197
239
|
test("all three boolean flags survive even when caller passes no opts", async () => {
|
|
@@ -206,7 +248,27 @@ describe("ClineRuntime.startSession — agent teams plumbing (v6.2.0)", () => {
|
|
|
206
248
|
const cfg = capturedConfig[0]!.config;
|
|
207
249
|
expect(cfg.enableAgentTeams).toBe(true);
|
|
208
250
|
expect(cfg.enableTools).toBe(true);
|
|
209
|
-
expect(cfg.enableSpawnAgent).toBe(
|
|
251
|
+
expect(cfg.enableSpawnAgent).toBe(true,
|
|
252
|
+
"v6.2.3 — subagents + task tool must be available even without caller opts");
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe("ClineRuntime.startSession — subagents plumbing (v6.2.3)", () => {
|
|
257
|
+
test("enableSpawnAgent regression: must NEVER be false (v6.2.3 fix)", async () => {
|
|
258
|
+
// v6.2.3 flipped enableSpawnAgent from false → true. Before this
|
|
259
|
+
// change, Odin could not use the `task` tool or `use_subagents`,
|
|
260
|
+
// which silently broke subagent delegation. This test pins the fix.
|
|
261
|
+
const runtime = new ClineRuntime({ logger: stubLogger() });
|
|
262
|
+
(runtime as unknown as { core: unknown }).core = makeFakeCore();
|
|
263
|
+
await runtime.startSession({
|
|
264
|
+
providerId: "anthropic",
|
|
265
|
+
modelId: "claude-sonnet-4-6",
|
|
266
|
+
workspaceRoot: "/tmp",
|
|
267
|
+
prompt: "go",
|
|
268
|
+
});
|
|
269
|
+
const cfg = capturedConfig[0]!.config;
|
|
270
|
+
expect(cfg.enableSpawnAgent).not.toBe(false);
|
|
271
|
+
expect(cfg.enableSpawnAgent).toBe(true);
|
|
210
272
|
});
|
|
211
273
|
});
|
|
212
274
|
|
|
@@ -278,16 +278,16 @@ describe("readEnvFlags", () => {
|
|
|
278
278
|
// ── clineruntimeMaxConsecutiveMistakes ───────────────────────────────────────
|
|
279
279
|
|
|
280
280
|
describe("clineruntimeMaxConsecutiveMistakes (v0.3.1)", () => {
|
|
281
|
-
test("default is
|
|
281
|
+
test("default is 10 when neither raw nor env is provided (v6.2.4)", () => {
|
|
282
282
|
delete process.env.BIZAR_MAX_CONSECUTIVE_MISTAKES;
|
|
283
283
|
const { options } = normalizeOptions({});
|
|
284
|
-
expect(options.clineruntimeMaxConsecutiveMistakes).toBe(
|
|
284
|
+
expect(options.clineruntimeMaxConsecutiveMistakes).toBe(10);
|
|
285
285
|
});
|
|
286
286
|
|
|
287
287
|
test("raw value is honored when in range", () => {
|
|
288
288
|
delete process.env.BIZAR_MAX_CONSECUTIVE_MISTAKES;
|
|
289
|
-
const { options, notes } = normalizeOptions({ clineruntimeMaxConsecutiveMistakes:
|
|
290
|
-
expect(options.clineruntimeMaxConsecutiveMistakes).toBe(
|
|
289
|
+
const { options, notes } = normalizeOptions({ clineruntimeMaxConsecutiveMistakes: 15 });
|
|
290
|
+
expect(options.clineruntimeMaxConsecutiveMistakes).toBe(15);
|
|
291
291
|
expect(notes.some((n) => n.includes("clineruntimeMaxConsecutiveMistakes"))).toBe(false);
|
|
292
292
|
});
|
|
293
293
|
|
|
@@ -321,9 +321,9 @@ describe("clineruntimeMaxConsecutiveMistakes (v0.3.1)", () => {
|
|
|
321
321
|
delete process.env.BIZAR_MAX_CONSECUTIVE_MISTAKES;
|
|
322
322
|
});
|
|
323
323
|
|
|
324
|
-
test("non-numeric raw falls back to default", () => {
|
|
324
|
+
test("non-numeric raw falls back to default (10)", () => {
|
|
325
325
|
delete process.env.BIZAR_MAX_CONSECUTIVE_MISTAKES;
|
|
326
326
|
const { options } = normalizeOptions({ clineruntimeMaxConsecutiveMistakes: "not-a-number" });
|
|
327
|
-
expect(options.clineruntimeMaxConsecutiveMistakes).toBe(
|
|
327
|
+
expect(options.clineruntimeMaxConsecutiveMistakes).toBe(10);
|
|
328
328
|
});
|
|
329
329
|
});
|
package/scripts/bh-full-e2e.mjs
CHANGED
|
@@ -125,7 +125,7 @@ if (!existsSync(PLUGIN_PATH)) {
|
|
|
125
125
|
}
|
|
126
126
|
record('plugin entry resolves', true, PLUGIN_PATH);
|
|
127
127
|
|
|
128
|
-
// ── 1. Verify enableAgentTeams in source (
|
|
128
|
+
// ── 1. Verify enableAgentTeams + enableSpawnAgent in source (v6.2.0 / v6.2.3) ───────
|
|
129
129
|
try {
|
|
130
130
|
const { readFileSync } = await import('node:fs');
|
|
131
131
|
const srcPath = join(REPO_ROOT, 'plugins', 'bizar', 'src', 'clineruntime.ts');
|
|
@@ -133,10 +133,17 @@ try {
|
|
|
133
133
|
record('clineruntime.ts source present', false, `${srcPath} missing`);
|
|
134
134
|
} else {
|
|
135
135
|
const text = readFileSync(srcPath, 'utf8');
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
const teamsOk = /enableAgentTeams:\s*true/.test(text);
|
|
137
|
+
const spawnOk = /enableSpawnAgent:\s*true/.test(text);
|
|
138
|
+
if (teamsOk && spawnOk) {
|
|
139
|
+
record('enableAgentTeams + enableSpawnAgent: true in clineruntime.ts', true,
|
|
140
|
+
'/team and /subagent (use_subagents + task tool) both work');
|
|
138
141
|
} else {
|
|
139
|
-
|
|
142
|
+
const missing = [];
|
|
143
|
+
if (!teamsOk) missing.push('enableAgentTeams');
|
|
144
|
+
if (!spawnOk) missing.push('enableSpawnAgent');
|
|
145
|
+
record('enableAgentTeams + enableSpawnAgent: true in clineruntime.ts', false,
|
|
146
|
+
`REGRESSION: missing ${missing.join(', ')} — /team and subagents will not function`);
|
|
140
147
|
}
|
|
141
148
|
}
|
|
142
149
|
} catch (err) {
|
|
@@ -336,6 +343,28 @@ try {
|
|
|
336
343
|
record('plugin hooks dir scannable', false, err.message);
|
|
337
344
|
}
|
|
338
345
|
|
|
346
|
+
// ── 9.5. Verify all 14 agents reference the shared docs (v6.2.4) ─────
|
|
347
|
+
// Catches drift: an agent that doesn't reference AGENT_BASELINE.md or
|
|
348
|
+
// CLINE_TOOLS.md won't get the always-on rules at runtime.
|
|
349
|
+
try {
|
|
350
|
+
const { spawnSync } = await import('node:child_process');
|
|
351
|
+
const r = spawnSync('node', ['scripts/check-agents.mjs'], {
|
|
352
|
+
encoding: 'utf8',
|
|
353
|
+
cwd: REPO_ROOT,
|
|
354
|
+
timeout: 10000,
|
|
355
|
+
});
|
|
356
|
+
if (r.status === 0) {
|
|
357
|
+
// Extract the count from the output
|
|
358
|
+
const m = /All (\d+) agents/.exec(r.stdout || '');
|
|
359
|
+
const n = m ? m[1] : '?';
|
|
360
|
+
record('all 14 agents reference AGENT_BASELINE + CLINE_TOOLS', true, `${n} agents OK`);
|
|
361
|
+
} else {
|
|
362
|
+
record('all 14 agents reference AGENT_BASELINE + CLINE_TOOLS', false, (r.stdout || r.stderr || '').trim().split('\n').slice(-3).join(' | '));
|
|
363
|
+
}
|
|
364
|
+
} catch (err) {
|
|
365
|
+
record('all 14 agents reference AGENT_BASELINE + CLINE_TOOLS', false, err.message);
|
|
366
|
+
}
|
|
367
|
+
|
|
339
368
|
// ── 10. Verify cline CLI is on PATH and recent enough ──────────
|
|
340
369
|
try {
|
|
341
370
|
const { spawnSync } = await import('node:child_process');
|
|
@@ -378,6 +407,52 @@ try {
|
|
|
378
407
|
record('bizar validate command present', false, err.message);
|
|
379
408
|
}
|
|
380
409
|
|
|
410
|
+
// ── 12.6. Verify Cline CLI integration (v6.2.3) ─────────────────
|
|
411
|
+
// v6.2.3 — pass-through wrappers for Cline CLI commands + sample.
|
|
412
|
+
try {
|
|
413
|
+
const { existsSync } = await import('node:fs');
|
|
414
|
+
const clineCmd = join(REPO_ROOT, 'cli', 'commands', 'cline-cmd.mjs');
|
|
415
|
+
const rcaCmd = join(REPO_ROOT, 'cli', 'commands', 'rca.mjs');
|
|
416
|
+
const rcaTest = join(REPO_ROOT, 'cli', 'commands', 'rca.test.mjs');
|
|
417
|
+
const setupProviderCmd = join(REPO_ROOT, 'cli', 'commands', 'setup-provider.mjs');
|
|
418
|
+
const setupProviderTest = join(REPO_ROOT, 'cli', 'commands', 'setup-provider.test.mjs');
|
|
419
|
+
if (existsSync(clineCmd)) {
|
|
420
|
+
const text = (await import('node:fs')).readFileSync(clineCmd, 'utf8');
|
|
421
|
+
const hasConfig = /runClineConfig\b/.test(text);
|
|
422
|
+
const hasHistory = /runClineHistory\b/.test(text);
|
|
423
|
+
const hasHub = /runClineHub\b/.test(text);
|
|
424
|
+
const hasHook = /runClineHook\b/.test(text);
|
|
425
|
+
const hasTeam = /runClineTeam\b/.test(text);
|
|
426
|
+
const hasSubagent = /runClineSubagent\b/.test(text);
|
|
427
|
+
if (hasConfig && hasHistory && hasHub && hasHook && hasTeam && hasSubagent) {
|
|
428
|
+
record('bizar cline-cmd wrappers present', true, 'config, history, hub, hook, team, subagent');
|
|
429
|
+
} else {
|
|
430
|
+
const missing = [];
|
|
431
|
+
if (!hasConfig) missing.push('config');
|
|
432
|
+
if (!hasHistory) missing.push('history');
|
|
433
|
+
if (!hasHub) missing.push('hub');
|
|
434
|
+
if (!hasHook) missing.push('hook');
|
|
435
|
+
if (!hasTeam) missing.push('team');
|
|
436
|
+
if (!hasSubagent) missing.push('subagent');
|
|
437
|
+
record('bizar cline-cmd wrappers present', false, `missing: ${missing.join(', ')}`);
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
record('bizar cline-cmd wrappers present', false, 'cli/commands/cline-cmd.mjs missing');
|
|
441
|
+
}
|
|
442
|
+
if (existsSync(rcaCmd) && existsSync(rcaTest)) {
|
|
443
|
+
record('bizar rca (GitHub Issue RCA sample) present', true, 'cli/commands/rca.{mjs,test.mjs}');
|
|
444
|
+
} else {
|
|
445
|
+
record('bizar rca (GitHub Issue RCA sample) present', false, 'cli/commands/rca.* missing');
|
|
446
|
+
}
|
|
447
|
+
if (existsSync(setupProviderCmd) && existsSync(setupProviderTest)) {
|
|
448
|
+
record('bizar setup-provider + auto-migrate present', true, 'cli/commands/setup-provider.{mjs,test.mjs}');
|
|
449
|
+
} else {
|
|
450
|
+
record('bizar setup-provider + auto-migrate present', false, 'cli/commands/setup-provider.* missing');
|
|
451
|
+
}
|
|
452
|
+
} catch (err) {
|
|
453
|
+
record('bizar cline-cmd integration present', false, err.message);
|
|
454
|
+
}
|
|
455
|
+
|
|
381
456
|
// ── 13. Verify package.json version is consistent ──────────────
|
|
382
457
|
try {
|
|
383
458
|
const { readFileSync } = await import('node:fs');
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scripts/check-agents.mjs
|
|
3
|
+
*
|
|
4
|
+
* v6.2.4 — Verifies every agent file references the right shared docs.
|
|
5
|
+
*
|
|
6
|
+
* Fails (exit 1) if any of the 14 Bizar agents is missing the
|
|
7
|
+
* AGENT_BASELINE or CLINE_TOOLS reference. This catches drift early —
|
|
8
|
+
* an agent that doesn't reference the baseline doesn't get the
|
|
9
|
+
* always-on rules at runtime.
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const ROOT = join(__filename, '..', '..');
|
|
17
|
+
|
|
18
|
+
const AGENT_FILES = [
|
|
19
|
+
'agent-browser.md',
|
|
20
|
+
'baldr.md',
|
|
21
|
+
'forseti.md',
|
|
22
|
+
'frigg.md',
|
|
23
|
+
'heimdall.md',
|
|
24
|
+
'hermod.md',
|
|
25
|
+
'mimir.md',
|
|
26
|
+
'odin.md',
|
|
27
|
+
'quick.md',
|
|
28
|
+
'semble-search.md',
|
|
29
|
+
'thor.md',
|
|
30
|
+
'tyr.md',
|
|
31
|
+
'vidarr.md',
|
|
32
|
+
'vor.md',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
let failed = 0;
|
|
36
|
+
const rows = [];
|
|
37
|
+
|
|
38
|
+
for (const file of AGENT_FILES) {
|
|
39
|
+
const path = join(ROOT, 'config', 'agents', file);
|
|
40
|
+
let text = '';
|
|
41
|
+
try {
|
|
42
|
+
text = readFileSync(path, 'utf8');
|
|
43
|
+
} catch (err) {
|
|
44
|
+
rows.push([file, 'MISSING FILE', '']);
|
|
45
|
+
failed++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const hasBaseline = /AGENT_BASELINE|agent-baseline/i.test(text);
|
|
49
|
+
const hasClineTools = /CLINE_TOOLS/i.test(text);
|
|
50
|
+
if (!hasBaseline && !hasClineTools) {
|
|
51
|
+
rows.push([file, 'NO REFERENCE', 'needs AGENT_BASELINE or CLINE_TOOLS in description']);
|
|
52
|
+
failed++;
|
|
53
|
+
} else {
|
|
54
|
+
const refs = [
|
|
55
|
+
hasBaseline ? 'AGENT_BASELINE' : null,
|
|
56
|
+
hasClineTools ? 'CLINE_TOOLS' : null,
|
|
57
|
+
].filter(Boolean).join('+');
|
|
58
|
+
rows.push([file, 'OK', refs]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log('\n Agent → Shared-Docs reference check (v6.2.4)\n');
|
|
63
|
+
console.log(' ' + 'agent'.padEnd(24) + 'status'.padEnd(14) + 'references');
|
|
64
|
+
console.log(' ' + '-'.repeat(60));
|
|
65
|
+
for (const [file, status, refs] of rows) {
|
|
66
|
+
console.log(' ' + file.padEnd(24) + status.padEnd(14) + refs);
|
|
67
|
+
}
|
|
68
|
+
console.log('');
|
|
69
|
+
if (failed > 0) {
|
|
70
|
+
console.log(` ✗ ${failed} agent(s) missing the AGENT_BASELINE/CLINE_TOOLS reference.\n`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
console.log(` ✓ All ${AGENT_FILES.length} agents reference the shared docs.\n`);
|