clembot-doorman 0.2.0 โ 0.2.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/README.md +56 -3
- package/doorman/.claude-plugin/plugin.json +1 -1
- package/doorman/cli/audit.mjs +232 -0
- package/doorman/cli/doorman.mjs +59 -5
- package/doorman/cli/install.mjs +15 -1
- package/doorman/cli/schedule.mjs +128 -0
- package/doorman/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
<
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="media/hero.png" alt="Clembot Doorman - The Package Manager and Security Gate for AI Agents" width="100%">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
5
|
# Clembot Doorman
|
|
4
6
|
|
|
5
|
-
> **The Package Manager & Security Doorman for
|
|
7
|
+
> **The Package Manager & Security Doorman for AI Agents.**
|
|
6
8
|
> Inspect your build. Recommend vetted MCPs from prompt history. Block rogue tools before they reach context.
|
|
7
9
|
|
|
8
10
|
[](https://clembot-doorman.wanessalabs.com)
|
|
9
11
|
[](https://clembot-doorman.bazgateway.com)
|
|
10
|
-
[](RUNBOOK.md)
|
|
11
13
|
[](LICENSE)
|
|
12
14
|
|
|
13
15
|
---
|
|
@@ -40,6 +42,56 @@
|
|
|
40
42
|
|
|
41
43
|
---
|
|
42
44
|
|
|
45
|
+
## ๐ธ Architecture & Platform Gallery
|
|
46
|
+
|
|
47
|
+
<table>
|
|
48
|
+
<tr>
|
|
49
|
+
<td width="50%" align="center" valign="top">
|
|
50
|
+
<a href="media/gallery-03-two-phase-solution.png"><img src="media/gallery-03-two-phase-solution.png" alt="2 phase solution with Clembot Doorman" width="100%"></a><br>
|
|
51
|
+
<b>2-Phase Defense Solution with Clembot Doorman</b><br>
|
|
52
|
+
<i>$0.00 local pre-screening before $0.01 Base mainnet verification</i>
|
|
53
|
+
</td>
|
|
54
|
+
<td width="50%" align="center" valign="top">
|
|
55
|
+
<a href="media/gallery-04-tiered-architecture.png"><img src="media/gallery-04-tiered-architecture.png" alt="Tiered Clembot-doorman Architecture" width="100%"></a><br>
|
|
56
|
+
<b>Tiered Clembot-Doorman Architecture</b><br>
|
|
57
|
+
<i>Four modular layers (L0 Doctor โ L1 Needs โ L2 Offline Gate โ L3 Scorecard)</i>
|
|
58
|
+
</td>
|
|
59
|
+
</tr>
|
|
60
|
+
<tr>
|
|
61
|
+
<td width="50%" align="center" valign="top">
|
|
62
|
+
<a href="media/gallery-01-bazantic-gateway.png"><img src="media/gallery-01-bazantic-gateway.png" alt="Bazantic doorman gateway" width="100%"></a><br>
|
|
63
|
+
<b>Bazantic Doorman Gateway</b><br>
|
|
64
|
+
<i>Live edge gateway (<code>clembot-doorman.bazgateway.com</code>) with 10 managed tools</i>
|
|
65
|
+
</td>
|
|
66
|
+
<td width="50%" align="center" valign="top">
|
|
67
|
+
<a href="media/gallery-02-bazantic-recipes.png"><img src="media/gallery-02-bazantic-recipes.png" alt="Bazantic recipes" width="100%"></a><br>
|
|
68
|
+
<b>Bazantic Recipes</b><br>
|
|
69
|
+
<i>Three published production recipes delivering 87% context token reduction</i>
|
|
70
|
+
</td>
|
|
71
|
+
</tr>
|
|
72
|
+
<tr>
|
|
73
|
+
<td width="50%" align="center" valign="top">
|
|
74
|
+
<a href="media/gallery-05-powered-by-bazantic.png"><img src="media/gallery-05-powered-by-bazantic.png" alt="Powered by Bazantic" width="100%"></a><br>
|
|
75
|
+
<b>Powered by Bazantic</b><br>
|
|
76
|
+
<i>Deep technical integration: Continuity, Edge Infrastructure, and Cryptographic Allowlisting</i>
|
|
77
|
+
</td>
|
|
78
|
+
<td width="50%" align="center" valign="top">
|
|
79
|
+
<a href="media/gallery-06-doorman-demo.png"><img src="media/gallery-06-doorman-demo.png" alt="Doorman demo" width="100%"></a><br>
|
|
80
|
+
<b>Doorman Demo</b><br>
|
|
81
|
+
<i>Interactive flow testing real MCPs with toggleable Base x402 micropayments</i>
|
|
82
|
+
</td>
|
|
83
|
+
</tr>
|
|
84
|
+
<tr>
|
|
85
|
+
<td colspan="2" align="center" valign="top">
|
|
86
|
+
<a href="media/gallery-07-clembot-org-chart.png"><img src="media/gallery-07-clembot-org-chart.png" alt="Clembot org chart" width="100%"></a><br>
|
|
87
|
+
<b>Clembot Organization Chart</b><br>
|
|
88
|
+
<i>27 autonomous agents across 5 divisions: Design Director is the sole surface gated by Doorman</i>
|
|
89
|
+
</td>
|
|
90
|
+
</tr>
|
|
91
|
+
</table>
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
43
95
|
## What this is for
|
|
44
96
|
|
|
45
97
|
Doorman measures whether a candidate tool actually helps **your** agent, and gives you a report about **your** build.
|
|
@@ -77,6 +129,7 @@ The verdict is yours, produced on your machine, from numbers we never receive.
|
|
|
77
129
|
| `site/` | The live product & explainer at [clembot-doorman.wanessalabs.com](https://clembot-doorman.wanessalabs.com). |
|
|
78
130
|
| `fixtures/planted-bad-mcp/` | A deliberately hostile MCP server, deployed, so the demo denies something real instead of a line in a JSON file. |
|
|
79
131
|
|
|
132
|
+
<a id="install"></a>
|
|
80
133
|
## Quickstart & Installation
|
|
81
134
|
|
|
82
135
|
**The answer depends on your stack, so run it on yours.**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "clembot-doorman",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "A gate on what your agent is allowed to use. Blocks MCP servers that are not on your trust list, reads your prompt history to find what the build actually needs, and grades candidates before you install them.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Clemens Wan",
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `doorman audit` โ Unified security audit & tool recommendation report.
|
|
3
|
+
*
|
|
4
|
+
* Combines three layers in one fast, local sweep:
|
|
5
|
+
* 1. L0 doctor: Inspects your harness, gate wiring, and installed MCP servers.
|
|
6
|
+
* 2. L0.5 needs: Scans local prompt history to detect missing capability needs.
|
|
7
|
+
* 3. L2 watch: Cross-references unmet gaps against the public graded feed.
|
|
8
|
+
*
|
|
9
|
+
* Output: An actionable, executive-grade posture and tool recommendation report.
|
|
10
|
+
* Free, offline-first, zero runtime dependencies.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { resolve } from 'node:path';
|
|
14
|
+
import { writeFileSync } from 'node:fs';
|
|
15
|
+
import { doctor } from './doctor.mjs';
|
|
16
|
+
import { needs as readNeeds } from './needs.mjs';
|
|
17
|
+
import { watch } from './watch.mjs';
|
|
18
|
+
|
|
19
|
+
export async function auditProject(targetDir = process.cwd(), opts = {}) {
|
|
20
|
+
const absRoot = resolve(targetDir);
|
|
21
|
+
|
|
22
|
+
// 1. Run Doctor (L0: Harness, Gate, Installed servers)
|
|
23
|
+
const doc = await doctor(absRoot, opts);
|
|
24
|
+
if (!doc.ok) {
|
|
25
|
+
return { ok: false, why: doc.why };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 2. Run Needs (L0.5: Prompt history scan for capability gaps)
|
|
29
|
+
let needsResult = null;
|
|
30
|
+
try {
|
|
31
|
+
needsResult = await readNeeds({
|
|
32
|
+
root: absRoot,
|
|
33
|
+
historyDir: opts.historyDir,
|
|
34
|
+
candidateFile: opts.candidateFile,
|
|
35
|
+
api: opts.api,
|
|
36
|
+
});
|
|
37
|
+
} catch {
|
|
38
|
+
needsResult = null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 3. Run Watch (L2: Classified feed of newly graded tools & threats)
|
|
42
|
+
let watchResult = null;
|
|
43
|
+
try {
|
|
44
|
+
watchResult = await watch({
|
|
45
|
+
root: absRoot,
|
|
46
|
+
api: opts.api,
|
|
47
|
+
all: true,
|
|
48
|
+
});
|
|
49
|
+
} catch {
|
|
50
|
+
watchResult = null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Synthesize executive findings
|
|
54
|
+
const gateStatus = doc.gate?.verdict || 'unknown';
|
|
55
|
+
const isGateWired = gateStatus === 'installed and wired' || gateStatus.includes('wired');
|
|
56
|
+
const harnesses = (doc.harnesses || []).map((h) => h.harness);
|
|
57
|
+
const installedCount = (doc.servers || []).length;
|
|
58
|
+
|
|
59
|
+
const gaps = (needsResult?.matches || []).filter((m) => m.status === 'GAP' || m.status === 'UNMET');
|
|
60
|
+
const covered = (needsResult?.matches || []).filter((m) => m.status === 'COVERED');
|
|
61
|
+
|
|
62
|
+
const candidates = watchResult?.candidates || [];
|
|
63
|
+
const recommended = candidates
|
|
64
|
+
.filter((c) => (c.grade === 'A' || c.grade === 'B') && c.verdict === 'unreviewed' && !c.is_fixture && !c.self_graded)
|
|
65
|
+
.slice(0, 5);
|
|
66
|
+
|
|
67
|
+
const blockedThreats = candidates
|
|
68
|
+
.filter((c) => c.grade === 'F' || c.hard_fail || c.verdict === 'blocked')
|
|
69
|
+
.slice(0, 3);
|
|
70
|
+
|
|
71
|
+
const result = {
|
|
72
|
+
ok: true,
|
|
73
|
+
root: absRoot,
|
|
74
|
+
timestamp: new Date().toISOString(),
|
|
75
|
+
posture: {
|
|
76
|
+
gateStatus,
|
|
77
|
+
isGateWired,
|
|
78
|
+
harnesses,
|
|
79
|
+
installedCount,
|
|
80
|
+
agentsCount: doc.agents?.count ?? 0,
|
|
81
|
+
},
|
|
82
|
+
needs: {
|
|
83
|
+
totalPrompts: needsResult?.promptCount ?? 0,
|
|
84
|
+
gaps,
|
|
85
|
+
covered,
|
|
86
|
+
},
|
|
87
|
+
recommendations: recommended,
|
|
88
|
+
threats: blockedThreats,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (opts.out) {
|
|
92
|
+
const md = renderAuditMarkdown(result);
|
|
93
|
+
writeFileSync(opts.out, md, 'utf8');
|
|
94
|
+
result.outFile = opts.out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function renderAuditMarkdown(res) {
|
|
101
|
+
const lines = [];
|
|
102
|
+
lines.push('# Clembot Doorman Security & Tool Recommendation Report');
|
|
103
|
+
lines.push(`\n**Target:** \`${res.root}\``);
|
|
104
|
+
lines.push(`**Generated:** ${res.timestamp}`);
|
|
105
|
+
lines.push('');
|
|
106
|
+
|
|
107
|
+
// Posture
|
|
108
|
+
lines.push('## 1. Security & Gate Posture');
|
|
109
|
+
const gateIcon = res.posture.isGateWired ? 'PASS' : 'WARN';
|
|
110
|
+
lines.push(`- **Gate Status:** [${gateIcon}] ${res.posture.gateStatus}`);
|
|
111
|
+
lines.push(`- **Harnesses Detected:** ${res.posture.harnesses.join(', ') || 'none'}`);
|
|
112
|
+
lines.push(`- **Reachable MCP Servers:** ${res.posture.installedCount}`);
|
|
113
|
+
lines.push(`- **Subagents Configured:** ${res.posture.agentsCount}`);
|
|
114
|
+
lines.push('');
|
|
115
|
+
|
|
116
|
+
// Recommendations based on needs
|
|
117
|
+
lines.push('## 2. Capability Needs & Tool Recommendations');
|
|
118
|
+
if (res.needs.gaps.length > 0) {
|
|
119
|
+
lines.push('Your prompt history reveals the following unmet tool capabilities:');
|
|
120
|
+
for (const g of res.needs.gaps) {
|
|
121
|
+
lines.push(`- **${g.title}:** ${g.promptsCount} prompt(s) reaching for this capability.`);
|
|
122
|
+
if (g.topCandidates && g.topCandidates.length > 0) {
|
|
123
|
+
for (const c of g.topCandidates.slice(0, 2)) {
|
|
124
|
+
lines.push(` โ Recommended: **${c.name || c.url}** (${c.grade ? `Grade ${c.grade}` : 'verified'})`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
lines.push('- No active capability gaps detected in prompt history.');
|
|
130
|
+
}
|
|
131
|
+
lines.push('');
|
|
132
|
+
|
|
133
|
+
if (res.recommendations.length > 0) {
|
|
134
|
+
lines.push('### Top Verified Safe MCP Servers');
|
|
135
|
+
for (const r of res.recommendations) {
|
|
136
|
+
const score = typeof r.score === 'number' ? `${r.score.toFixed(1)}/100` : 'passing';
|
|
137
|
+
lines.push(`- **${r.server_name || r.server_url}** โ Grade **${r.grade}** (${score})`);
|
|
138
|
+
lines.push(` \`${r.server_url}\``);
|
|
139
|
+
}
|
|
140
|
+
lines.push('');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Threats
|
|
144
|
+
lines.push('## 3. Threat Intelligence');
|
|
145
|
+
if (res.threats.length > 0) {
|
|
146
|
+
lines.push('The following servers failed security inspection and are blocked at the gate:');
|
|
147
|
+
for (const t of res.threats) {
|
|
148
|
+
const reason = t.hard_fail || 'Failed safety scan / commercial steering detected';
|
|
149
|
+
lines.push(`- โ ๏ธ **${t.server_name || t.server_url}** โ Grade **${t.grade}** [BLOCKED]: ${reason}`);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
lines.push('- No active threat flags recorded on your trust list.');
|
|
153
|
+
}
|
|
154
|
+
lines.push('');
|
|
155
|
+
|
|
156
|
+
// Next Steps
|
|
157
|
+
lines.push('## 4. Recommended Actions');
|
|
158
|
+
if (!res.posture.isGateWired) {
|
|
159
|
+
lines.push('1. **Wire the security gate:** `claude plugin marketplace add clemenswan/clembot-doorman && claude plugin install clembot-doorman`');
|
|
160
|
+
}
|
|
161
|
+
lines.push('2. **Vet new candidate servers before adoption:** `/vet <url>`');
|
|
162
|
+
lines.push('3. **Allow trusted servers:** `doorman allow <server-name>`');
|
|
163
|
+
lines.push('4. **Schedule recurring audits:** `doorman schedule`');
|
|
164
|
+
|
|
165
|
+
return lines.join('\n');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function renderAudit(res) {
|
|
169
|
+
const lines = [];
|
|
170
|
+
lines.push('');
|
|
171
|
+
lines.push('================================================================');
|
|
172
|
+
lines.push(' CLEMBOT DOORMAN ยท UNIFIED AUDIT & RECOMMENDATIONS ');
|
|
173
|
+
lines.push('================================================================');
|
|
174
|
+
lines.push(`Build: ${res.root}`);
|
|
175
|
+
lines.push('');
|
|
176
|
+
|
|
177
|
+
// 1. Security Posture
|
|
178
|
+
lines.push('โโ 1. SECURITY POSTURE โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
179
|
+
const gateMark = res.posture.isGateWired ? 'โ' : '!';
|
|
180
|
+
lines.push(` [${gateMark}] Gate: ${res.posture.gateStatus}`);
|
|
181
|
+
lines.push(` [i] Harness: ${res.posture.harnesses.join(', ') || 'None declared'}`);
|
|
182
|
+
lines.push(` [i] Reachable MCP Tools: ${res.posture.installedCount} declared`);
|
|
183
|
+
lines.push('');
|
|
184
|
+
|
|
185
|
+
// 2. Capability Recommendations
|
|
186
|
+
lines.push('โโ 2. CAPABILITY GAPS & RECOMMENDED TOOLS โโโโโโโโโโโโโโโโโโโโโโ');
|
|
187
|
+
if (res.needs.gaps.length > 0) {
|
|
188
|
+
lines.push(` Detected ${res.needs.gaps.length} capability gap(s) from prompt history:`);
|
|
189
|
+
for (const g of res.needs.gaps) {
|
|
190
|
+
lines.push(` โข ${g.title} (${g.promptsCount} prompt asks)`);
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
lines.push(' No unmet capability gaps detected.');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (res.recommendations.length > 0) {
|
|
197
|
+
lines.push('');
|
|
198
|
+
lines.push(' Top Vetted Candidates from Graded Feed:');
|
|
199
|
+
for (const r of res.recommendations) {
|
|
200
|
+
const score = typeof r.score === 'number' ? `${r.score.toFixed(1)}/100` : '';
|
|
201
|
+
lines.push(` โ [Grade ${r.grade} ยท ${score}] ${r.server_name || 'Server'}`);
|
|
202
|
+
lines.push(` URL: ${r.server_url}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
lines.push('');
|
|
206
|
+
|
|
207
|
+
// 3. Blocked Threats
|
|
208
|
+
lines.push('โโ 3. THREATS BLOCKED AT THE GATE โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
209
|
+
if (res.threats.length > 0) {
|
|
210
|
+
for (const t of res.threats) {
|
|
211
|
+
lines.push(` โ [Grade ${t.grade}] ${t.server_name || t.server_url}`);
|
|
212
|
+
if (t.hard_fail) lines.push(` Reason: ${t.hard_fail}`);
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
lines.push(' No active security alerts on installed servers.');
|
|
216
|
+
}
|
|
217
|
+
lines.push('');
|
|
218
|
+
|
|
219
|
+
// 4. Quick Actions
|
|
220
|
+
lines.push('โโ 4. QUICK ACTIONS โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
221
|
+
if (!res.posture.isGateWired) {
|
|
222
|
+
lines.push(' โข Wire Gate: claude plugin install clembot-doorman');
|
|
223
|
+
}
|
|
224
|
+
lines.push(' โข Vet Tool: /vet <candidate_url>');
|
|
225
|
+
lines.push(' โข Trust Tool: doorman allow <server_name>');
|
|
226
|
+
lines.push(' โข Schedule: doorman schedule');
|
|
227
|
+
if (res.outFile) {
|
|
228
|
+
lines.push(` โข Report: Saved to ${res.outFile}`);
|
|
229
|
+
}
|
|
230
|
+
lines.push('');
|
|
231
|
+
return lines.join('\n');
|
|
232
|
+
}
|
package/doorman/cli/doorman.mjs
CHANGED
|
@@ -31,16 +31,48 @@ import { needs as readNeeds, render as renderNeedsCli } from './needs.mjs';
|
|
|
31
31
|
import { install, renderInstall } from './install.mjs';
|
|
32
32
|
import { allow, renderAllow, SCOPES } from './allow.mjs';
|
|
33
33
|
import { refreshNotify, consumeDigest, DEFAULT_DIGEST } from './notify.mjs';
|
|
34
|
+
import { auditProject, renderAudit } from './audit.mjs';
|
|
35
|
+
import { schedule as scheduleReport, renderSchedule } from './schedule.mjs';
|
|
34
36
|
import { join } from 'node:path';
|
|
35
37
|
|
|
36
38
|
// Pinned to every other declaration by version.test.mjs. There are FOUR of
|
|
37
39
|
// them (root package.json, doorman/package.json, plugin.json, this) and this
|
|
38
40
|
// one silently reported 0.1.0 out of a 0.2.0 tarball.
|
|
39
|
-
const VERSION = '0.2.
|
|
41
|
+
const VERSION = '0.2.1';
|
|
42
|
+
|
|
43
|
+
const QUICKSTART = `
|
|
44
|
+
doorman ${VERSION} โ Security gate & tool package manager for AI agents
|
|
45
|
+
|
|
46
|
+
QUICKSTART (3 SIMPLE STEPS):
|
|
47
|
+
1. doorman audit Run full build check & get vetted MCP recommendations
|
|
48
|
+
2. /vet <url> Audit an untrusted candidate MCP server before adoption
|
|
49
|
+
3. doorman schedule Configure automated weekly/daily audit reports
|
|
50
|
+
|
|
51
|
+
COMMON COMMANDS:
|
|
52
|
+
doorman audit [path] Unified scan: doctor + prompt needs + recommended tools
|
|
53
|
+
doorman schedule Configure recurring automated reports (cron, GitHub Actions)
|
|
54
|
+
doorman doctor [path] L0 build & gate inspection (free, offline, <5ms)
|
|
55
|
+
doorman needs [path] L0.5 scan prompt history for missing capabilities
|
|
56
|
+
doorman watch [path] Check public feed for newly graded tools
|
|
57
|
+
doorman allow <server> Trust an MCP server by name on your local allowlist
|
|
58
|
+
doorman install [path] Install the gate & hooks into this project
|
|
59
|
+
|
|
60
|
+
Run \`doorman --help\` for full manual and advanced benchmark flags.
|
|
61
|
+
`;
|
|
40
62
|
|
|
41
63
|
const HELP = `
|
|
42
64
|
doorman ${VERSION} โ measure a candidate, do not just read it
|
|
43
65
|
|
|
66
|
+
doorman audit [path] [--out FILE] [--json]
|
|
67
|
+
Unified security audit & capability recommendations. Runs doctor,
|
|
68
|
+
prompt-history needs, and watch in one fast command. Produces an
|
|
69
|
+
executive report with security posture, capability gaps, and top
|
|
70
|
+
verified tools.
|
|
71
|
+
|
|
72
|
+
doorman schedule [path] [--github]
|
|
73
|
+
Set up automated recurring audit reports via GitHub Actions, system
|
|
74
|
+
cron, or session-notify hooks.
|
|
75
|
+
|
|
44
76
|
doorman doctor [path]
|
|
45
77
|
L0. What is in YOUR build: which harness, which MCP servers your agents can
|
|
46
78
|
reach, how many subagents hold MCP tools, and whether the gate is installed
|
|
@@ -125,7 +157,7 @@ Options
|
|
|
125
157
|
*/
|
|
126
158
|
const BOOLEAN_FLAGS = new Set([
|
|
127
159
|
'json', 'dry-run', 'all', 'estimate', 'help', 'version', 'allow-network',
|
|
128
|
-
'static-only', 'no-feed',
|
|
160
|
+
'static-only', 'no-feed', 'github', 'cron', 'weekly',
|
|
129
161
|
]);
|
|
130
162
|
|
|
131
163
|
function parseArgs(argv) {
|
|
@@ -149,12 +181,34 @@ const log = (m) => console.error(`${new Date().toISOString().slice(11, 19)} ${m}
|
|
|
149
181
|
async function main() {
|
|
150
182
|
const args = parseArgs(process.argv.slice(2));
|
|
151
183
|
if (args.version) { console.log(VERSION); return; }
|
|
152
|
-
if (args.help
|
|
184
|
+
if (args.help) { console.log(HELP); return; }
|
|
185
|
+
if (args._.length === 0) { console.log(QUICKSTART); return; }
|
|
153
186
|
|
|
154
|
-
|
|
187
|
+
const [cmd, link] = args._;
|
|
155
188
|
|
|
189
|
+
if (cmd === 'audit' || cmd === 'scan' || cmd === 'recommend') {
|
|
190
|
+
const target = args._[1] || process.cwd();
|
|
191
|
+
const r = await auditProject(target, {
|
|
192
|
+
out: typeof args.out === 'string' ? args.out : null,
|
|
193
|
+
api: typeof args.api === 'string' ? args.api : undefined,
|
|
194
|
+
historyDir: typeof args.history === 'string' ? args.history : undefined,
|
|
195
|
+
});
|
|
196
|
+
if (!r.ok) { console.error(`audit: ${r.why}`); process.exitCode = 1; return; }
|
|
197
|
+
if (args.json) { console.log(JSON.stringify(r, null, 2)); return; }
|
|
198
|
+
console.log(renderAudit(r));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
156
201
|
|
|
157
|
-
|
|
202
|
+
if (cmd === 'schedule') {
|
|
203
|
+
const target = args._[1] || process.cwd();
|
|
204
|
+
const r = await scheduleReport(target, {
|
|
205
|
+
github: Boolean(args.github),
|
|
206
|
+
});
|
|
207
|
+
if (!r.ok) { console.error(`schedule: ${r.why}`); process.exitCode = 1; return; }
|
|
208
|
+
if (args.json) { console.log(JSON.stringify(r, null, 2)); return; }
|
|
209
|
+
console.log(renderSchedule(r));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
158
212
|
|
|
159
213
|
if (cmd === 'doctor') {
|
|
160
214
|
const d = await doctor(args._[1] || process.cwd());
|
package/doorman/cli/install.mjs
CHANGED
|
@@ -183,6 +183,20 @@ export function renderInstall(res) {
|
|
|
183
183
|
L.push('');
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
L.push('
|
|
186
|
+
L.push('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
187
|
+
L.push(' INSTALLATION COMPLETE ยท GETTING STARTED GUIDANCE');
|
|
188
|
+
L.push('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
189
|
+
L.push(' 1. Run unified health & tool check:');
|
|
190
|
+
L.push(' doorman audit');
|
|
191
|
+
L.push('');
|
|
192
|
+
L.push(' 2. In Claude Code, manage your gate interactively:');
|
|
193
|
+
L.push(' /doorman');
|
|
194
|
+
L.push('');
|
|
195
|
+
L.push(' 3. Audit any candidate tool before adoption:');
|
|
196
|
+
L.push(' /vet <mcp_server_url>');
|
|
197
|
+
L.push('');
|
|
198
|
+
L.push(' 4. Set up recurring automated audit digests:');
|
|
199
|
+
L.push(' doorman schedule');
|
|
200
|
+
L.push('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
187
201
|
return L.join('\n');
|
|
188
202
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `doorman schedule` โ Configure automated, recurring tool audits & recommendation reports.
|
|
3
|
+
*
|
|
4
|
+
* Supports three automation modes:
|
|
5
|
+
* 1. Built-in SessionStart Hook (runs silently in background on session open)
|
|
6
|
+
* 2. GitHub Actions Workflow (--github: creates .github/workflows/doorman-audit.yml)
|
|
7
|
+
* 3. Agent / Cron Scheduling (prints crontab entry & /schedule agent prompt)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { resolve, join } from 'node:path';
|
|
11
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
export const GITHUB_WORKFLOW_YAML = `name: Doorman Tool Audit & Security Report
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
schedule:
|
|
17
|
+
# Run every Monday at 09:00 UTC
|
|
18
|
+
- cron: '0 9 * * 1'
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
audit:
|
|
23
|
+
name: Run Clembot Doorman Audit
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout repository
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Setup Node.js
|
|
30
|
+
uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: 20
|
|
33
|
+
|
|
34
|
+
- name: Install Clembot Doorman
|
|
35
|
+
run: npm i -g clembot-doorman
|
|
36
|
+
|
|
37
|
+
- name: Run Unified Audit
|
|
38
|
+
run: |
|
|
39
|
+
mkdir -p .doorman
|
|
40
|
+
doorman audit --out .doorman/audit-report.md
|
|
41
|
+
|
|
42
|
+
- name: Upload Audit Artifact
|
|
43
|
+
uses: actions/upload-artifact@v4
|
|
44
|
+
with:
|
|
45
|
+
name: doorman-audit-report
|
|
46
|
+
path: .doorman/audit-report.md
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
export async function schedule(targetDir = process.cwd(), opts = {}) {
|
|
50
|
+
const absRoot = resolve(targetDir);
|
|
51
|
+
|
|
52
|
+
if (opts.github) {
|
|
53
|
+
const wfDir = join(absRoot, '.github', 'workflows');
|
|
54
|
+
mkdirSync(wfDir, { recursive: true });
|
|
55
|
+
const wfPath = join(wfDir, 'doorman-audit.yml');
|
|
56
|
+
writeFileSync(wfPath, GITHUB_WORKFLOW_YAML, 'utf8');
|
|
57
|
+
return {
|
|
58
|
+
ok: true,
|
|
59
|
+
mode: 'github',
|
|
60
|
+
path: wfPath,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check hook status
|
|
65
|
+
const sessionHook = join(absRoot, '.claude', 'hooks', 'session-notify.sh');
|
|
66
|
+
const hasHook = existsSync(sessionHook);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
ok: true,
|
|
70
|
+
mode: 'guide',
|
|
71
|
+
root: absRoot,
|
|
72
|
+
hasHook,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function renderSchedule(res) {
|
|
77
|
+
const lines = [];
|
|
78
|
+
lines.push('');
|
|
79
|
+
lines.push('================================================================');
|
|
80
|
+
lines.push(' CLEMBOT DOORMAN ยท AUTOMATED AUDIT SCHEDULING ');
|
|
81
|
+
lines.push('================================================================');
|
|
82
|
+
lines.push('');
|
|
83
|
+
|
|
84
|
+
if (res.mode === 'github') {
|
|
85
|
+
lines.push(` โ Created GitHub Actions workflow at:`);
|
|
86
|
+
lines.push(` ${res.path}`);
|
|
87
|
+
lines.push('');
|
|
88
|
+
lines.push(' This workflow runs `doorman audit` every Monday at 09:00 UTC');
|
|
89
|
+
lines.push(' and uploads the markdown report as an artifact.');
|
|
90
|
+
lines.push('');
|
|
91
|
+
return lines.join('\n');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
lines.push('Choose how you want to schedule your tool audit & recommendations:');
|
|
95
|
+
lines.push('');
|
|
96
|
+
|
|
97
|
+
// 1. SessionStart Hook
|
|
98
|
+
lines.push('โโ 1. BUILT-IN SESSION HOOK (ZERO CONFIG) โโโโโโโโโโโโโโโโโโโโโโโ');
|
|
99
|
+
if (res.hasHook) {
|
|
100
|
+
lines.push(' [ACTIVE] .claude/hooks/session-notify.sh is installed.');
|
|
101
|
+
lines.push(' Claude Code automatically checks for new graded MCP tools at the');
|
|
102
|
+
lines.push(' start of every session and notifies you if fresh tools are available.');
|
|
103
|
+
} else {
|
|
104
|
+
lines.push(' Install the plugin to enable silent background session checks:');
|
|
105
|
+
lines.push(' claude plugin marketplace add clemenswan/clembot-doorman && claude plugin install clembot-doorman');
|
|
106
|
+
}
|
|
107
|
+
lines.push('');
|
|
108
|
+
|
|
109
|
+
// 2. AI Agent Loop / Slash Command
|
|
110
|
+
lines.push('โโ 2. AI AGENT RECURRING SCHEDULING โโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
111
|
+
lines.push(' In Antigravity or pair-programming chat, invoke the /schedule command:');
|
|
112
|
+
lines.push(' /schedule CronExpression="0 9 * * 1", Prompt="Run doorman audit and report recommended MCP tools"');
|
|
113
|
+
lines.push('');
|
|
114
|
+
|
|
115
|
+
// 3. GitHub Actions
|
|
116
|
+
lines.push('โโ 3. CI/CD GITHUB ACTIONS (RECOMMENDED FOR TEAMS) โโโโโโโโโโโโโโ');
|
|
117
|
+
lines.push(' Generate a weekly automated audit workflow with:');
|
|
118
|
+
lines.push(' doorman schedule --github');
|
|
119
|
+
lines.push('');
|
|
120
|
+
|
|
121
|
+
// 4. System Cron
|
|
122
|
+
lines.push('โโ 4. SYSTEM CRON / TASK SCHEDULER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
123
|
+
lines.push(' Add to your crontab (crontab -e) to generate weekly markdown reports:');
|
|
124
|
+
lines.push(` 0 9 * * 1 cd "${res.root}" && npx clembot-doorman audit --out .doorman/audit.md`);
|
|
125
|
+
lines.push('');
|
|
126
|
+
|
|
127
|
+
return lines.join('\n');
|
|
128
|
+
}
|
package/doorman/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clembot-doorman",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "The Package Manager & Security Doorman for Claude Code: inspect your build, recommend vetted MCPs from prompt history, and block rogue tools before context.",
|
|
5
5
|
"homepage": "https://clembot-doorman.wanessalabs.com",
|
|
6
6
|
"type": "module",
|