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 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 (jsonMode) {
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.1.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/diagnostic",
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.1.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