agent-governance-check 0.1.0 → 0.2.0
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/cli.js +6 -2
- package/package.json +2 -2
- package/src/patterns.js +27 -0
- package/src/reporter.js +49 -1
- package/src/scanner.js +2 -2
package/bin/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import { copyFile, mkdir, access } from 'node:fs/promises';
|
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
import { dirname, join } from 'node:path';
|
|
11
11
|
import { scan } from '../src/scanner.js';
|
|
12
|
-
import { report, reportJson } from '../src/reporter.js';
|
|
12
|
+
import { report, reportJson, reportJsonLd } from '../src/reporter.js';
|
|
13
13
|
import { questions } from '../src/questions.js';
|
|
14
14
|
|
|
15
15
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -21,6 +21,7 @@ const positional = args.filter(a => !a.startsWith('--'));
|
|
|
21
21
|
|
|
22
22
|
const targetDir = resolve(positional[0] || '.');
|
|
23
23
|
const jsonMode = flags.has('--json');
|
|
24
|
+
const jsonLdMode = flags.has('--jsonld');
|
|
24
25
|
const initMode = flags.has('--init');
|
|
25
26
|
const verbose = flags.has('--verbose');
|
|
26
27
|
const help = flags.has('--help') || flags.has('-h');
|
|
@@ -35,6 +36,7 @@ if (help) {
|
|
|
35
36
|
npx agent-governance-check ./project Scan specific path
|
|
36
37
|
npx agent-governance-check --init Add starter templates to project
|
|
37
38
|
npx agent-governance-check --json Machine-readable output
|
|
39
|
+
npx agent-governance-check --jsonld JSON-LD attestation (VC-compatible)
|
|
38
40
|
npx agent-governance-check --help Show this help
|
|
39
41
|
|
|
40
42
|
${dim('What it checks:')}
|
|
@@ -95,7 +97,9 @@ console.log(` ${dim('Scanning')} ${targetDir === resolve('.') ? '.' : targetDir
|
|
|
95
97
|
|
|
96
98
|
const results = await scan(targetDir);
|
|
97
99
|
|
|
98
|
-
if (
|
|
100
|
+
if (jsonLdMode) {
|
|
101
|
+
console.log(reportJsonLd(results));
|
|
102
|
+
} else if (jsonMode) {
|
|
99
103
|
console.log(reportJson(results));
|
|
100
104
|
} else {
|
|
101
105
|
console.log(report(results, targetDir));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-governance-check",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Five governance questions for your AI agent system. Scan your repo in thirty seconds.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
],
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"author": "Erin Stanley",
|
|
29
|
-
"homepage": "https://evoked.dev/
|
|
29
|
+
"homepage": "https://evoked.dev/registry",
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
32
|
"url": "git+https://github.com/lowkey-divine/agent-governance-check.git"
|
package/src/patterns.js
CHANGED
|
@@ -5,12 +5,18 @@ export const governancePatterns = {
|
|
|
5
5
|
files: [
|
|
6
6
|
'**/memory-schema.md',
|
|
7
7
|
'**/memory.md',
|
|
8
|
+
'**/MEMORY.md',
|
|
8
9
|
'**/agent-memory.*',
|
|
9
10
|
'**/agents/*/memory.md',
|
|
10
11
|
'**/agents/*/MEMORY.md',
|
|
12
|
+
'**/agent-memory/*/MEMORY.md',
|
|
13
|
+
'**/agent-memory/*/*/MEMORY.md',
|
|
11
14
|
'**/self-record.*',
|
|
12
15
|
'**/decision-log*',
|
|
13
16
|
'**/decision-record*',
|
|
17
|
+
'**/decision-logs/*.md',
|
|
18
|
+
'**/decisions/*.md',
|
|
19
|
+
'**/meetings/*.md',
|
|
14
20
|
],
|
|
15
21
|
contentSignals: [
|
|
16
22
|
/decision.?log/i,
|
|
@@ -19,6 +25,8 @@ export const governancePatterns = {
|
|
|
19
25
|
/standing.?position/i,
|
|
20
26
|
/memory.?schema/i,
|
|
21
27
|
/persistent.?state/i,
|
|
28
|
+
/key.?memories/i,
|
|
29
|
+
/who.?i.?am/i,
|
|
22
30
|
],
|
|
23
31
|
},
|
|
24
32
|
|
|
@@ -30,6 +38,11 @@ export const governancePatterns = {
|
|
|
30
38
|
'**/guardrails.*',
|
|
31
39
|
'**/safety-spec.*',
|
|
32
40
|
'**/boundaries.md',
|
|
41
|
+
'**/red-lines*',
|
|
42
|
+
'**/red_lines*',
|
|
43
|
+
'**/PRIME_DIRECTIVE*.md',
|
|
44
|
+
'**/prime-directive*',
|
|
45
|
+
'**/prime_directive*',
|
|
33
46
|
],
|
|
34
47
|
contentSignals: [
|
|
35
48
|
/engine.?withdrawal/i,
|
|
@@ -39,6 +52,10 @@ export const governancePatterns = {
|
|
|
39
52
|
/refusal.?categor/i,
|
|
40
53
|
/fail.?closed/i,
|
|
41
54
|
/agent.*refuse/i,
|
|
55
|
+
/will.?not/i,
|
|
56
|
+
/must.?not/i,
|
|
57
|
+
/red.?lines?/i,
|
|
58
|
+
/sovereignty.*scope.*dependency/i,
|
|
42
59
|
],
|
|
43
60
|
},
|
|
44
61
|
|
|
@@ -51,7 +68,11 @@ export const governancePatterns = {
|
|
|
51
68
|
'**/manifesto.md',
|
|
52
69
|
'**/agency_manifesto.md',
|
|
53
70
|
'**/agents/*/persona.md',
|
|
71
|
+
'**/personas/*.md',
|
|
72
|
+
'**/new-generation/*.md',
|
|
54
73
|
'**/AGENTS.md',
|
|
74
|
+
'**/persona*.md',
|
|
75
|
+
'**/identity*.md',
|
|
55
76
|
],
|
|
56
77
|
contentSignals: [
|
|
57
78
|
/agent.?charter/i,
|
|
@@ -59,16 +80,21 @@ export const governancePatterns = {
|
|
|
59
80
|
/agent.?identity/i,
|
|
60
81
|
/persona.?file/i,
|
|
61
82
|
/who.?is.?this.?agent/i,
|
|
83
|
+
/role.?definition/i,
|
|
84
|
+
/communication.?style/i,
|
|
62
85
|
],
|
|
63
86
|
},
|
|
64
87
|
|
|
65
88
|
'disagreement-protocol': {
|
|
66
89
|
files: [
|
|
67
90
|
'**/deliberation-framework.md',
|
|
91
|
+
'**/DELIBERATION_FRAMEWORK.md',
|
|
68
92
|
'**/deliberation.*',
|
|
69
93
|
'**/governance-log*',
|
|
70
94
|
'**/dissent*',
|
|
71
95
|
'**/convergent-signal*',
|
|
96
|
+
'**/CONVERGENT_SIGNAL*',
|
|
97
|
+
'**/EXISTENTIAL_CHARTER*',
|
|
72
98
|
],
|
|
73
99
|
contentSignals: [
|
|
74
100
|
/deliberation/i,
|
|
@@ -109,4 +135,5 @@ export const frameworkPatterns = [
|
|
|
109
135
|
{ name: 'Evoke', files: ['**/agents/*/persona.md', '**/agents/decision-logs/*'] },
|
|
110
136
|
{ name: 'Swarm', files: ['**/swarm.py'] },
|
|
111
137
|
{ name: 'Dify', files: ['**/dify.yaml'] },
|
|
138
|
+
{ name: 'OpenClaw', files: ['**/.openclaw/**', '**/SKILL.md', '**/skill.md'] },
|
|
112
139
|
];
|
package/src/reporter.js
CHANGED
|
@@ -110,14 +110,62 @@ export function report(scanResults, targetDir) {
|
|
|
110
110
|
}
|
|
111
111
|
lines.push(` ${dim('Free starter kit: https://github.com/lowkey-divine/agent-governance-starter-kit')}`);
|
|
112
112
|
lines.push(` ${dim('Full framework: https://evoked.dev/products/agent-governance-starter-kit')}`);
|
|
113
|
+
lines.push(` ${dim('Bot Authority: https://evoked.dev/registry')}`);
|
|
113
114
|
lines.push('');
|
|
114
115
|
|
|
115
116
|
return lines.join('\n');
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
export function reportJsonLd(scanResults) {
|
|
120
|
+
const score = { found: 0, partial: 0, missing: 0, total: 5 };
|
|
121
|
+
const governanceProperties = {};
|
|
122
|
+
const evidence = {};
|
|
123
|
+
|
|
124
|
+
for (const q of questions) {
|
|
125
|
+
const result = scanResults.results[q.id];
|
|
126
|
+
score[result.status]++;
|
|
127
|
+
|
|
128
|
+
// Map question IDs to camelCase property names
|
|
129
|
+
const propName = q.id.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
130
|
+
governanceProperties[propName] = result.status;
|
|
131
|
+
|
|
132
|
+
if (result.evidence.length > 0) {
|
|
133
|
+
const items = result.evidence.slice(0, 5).map(e => ({
|
|
134
|
+
file: e.file,
|
|
135
|
+
type: e.type,
|
|
136
|
+
...(e.type === 'content' ? { signal: e.signal } : {}),
|
|
137
|
+
}));
|
|
138
|
+
if (result.evidence.length > 5) {
|
|
139
|
+
items.push({ note: `${result.evidence.length - 5} additional files detected` });
|
|
140
|
+
}
|
|
141
|
+
evidence[propName] = items;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const output = {
|
|
146
|
+
"@context": [
|
|
147
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
148
|
+
"https://evoked.dev/schemas/governance/v1"
|
|
149
|
+
],
|
|
150
|
+
"@type": "GovernanceAttestation",
|
|
151
|
+
issuer: "self",
|
|
152
|
+
issuanceDate: new Date().toISOString(),
|
|
153
|
+
tier: 1,
|
|
154
|
+
tierLabel: "Self-Attested",
|
|
155
|
+
governanceProperties,
|
|
156
|
+
score,
|
|
157
|
+
frameworks: scanResults.frameworks.map(f => f.name),
|
|
158
|
+
evidence,
|
|
159
|
+
registryUrl: "https://evoked.dev/registry",
|
|
160
|
+
verifyUrl: "https://evoked.dev/api/verify-agent",
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return JSON.stringify(output, null, 2);
|
|
164
|
+
}
|
|
165
|
+
|
|
118
166
|
export function reportJson(scanResults) {
|
|
119
167
|
const output = {
|
|
120
|
-
version: '0.
|
|
168
|
+
version: '0.2.0',
|
|
121
169
|
frameworks: scanResults.frameworks,
|
|
122
170
|
questions: questions.map(q => ({
|
|
123
171
|
id: q.id,
|
package/src/scanner.js
CHANGED
|
@@ -36,7 +36,7 @@ function matchGlob(filePath, pattern) {
|
|
|
36
36
|
pi++;
|
|
37
37
|
fi++;
|
|
38
38
|
} else if (parts[pi].includes('*')) {
|
|
39
|
-
const regex = new RegExp('^' + parts[pi].replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
|
|
39
|
+
const regex = new RegExp('^' + parts[pi].replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
|
|
40
40
|
if (regex.test(fileParts[fi])) {
|
|
41
41
|
pi++;
|
|
42
42
|
fi++;
|
|
@@ -128,7 +128,7 @@ export async function scan(targetDir) {
|
|
|
128
128
|
// Scan code files for governance-related content
|
|
129
129
|
if (evidence.length === 0) {
|
|
130
130
|
const codeFiles = allFiles.filter(f =>
|
|
131
|
-
/\.(js|mjs|ts|py|yaml|yml|json)$/.test(f)
|
|
131
|
+
/\.(js|mjs|ts|py|yaml|yml|json|md|txt|toml)$/.test(f)
|
|
132
132
|
);
|
|
133
133
|
|
|
134
134
|
// Sample up to 50 files for content scanning
|