@shomra/agent 0.3.29 → 0.3.30

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.
Files changed (77) hide show
  1. package/package.json +1 -1
  2. package/src/agents/hook-command.mjs +1 -1
  3. package/src/artifacts/matchers.mjs +7 -0
  4. package/src/cli/flags.mjs +2 -2
  5. package/src/cli/help-sections.mjs +7 -0
  6. package/src/cli/help.mjs +1 -1
  7. package/src/commands/check.mjs +3 -11
  8. package/src/commands/gate.mjs +26 -4
  9. package/src/commands/git-hooks.mjs +2 -2
  10. package/src/commands/ledger.mjs +0 -1
  11. package/src/commands/mcp-add.mjs +2 -1
  12. package/src/commands/memory-scan.mjs +135 -47
  13. package/src/commands/pr.mjs +7 -10
  14. package/src/commands/provenance.mjs +8 -13
  15. package/src/commands/scan.mjs +7 -1
  16. package/src/commands/secrets.mjs +4 -5
  17. package/src/core/git-exec.mjs +79 -0
  18. package/src/core/yaml-lite.mjs +300 -0
  19. package/src/core/zip-lite.mjs +37 -0
  20. package/src/detect/local-redact.mjs +1 -3
  21. package/src/detect/sast/rules-config.mjs +1 -1
  22. package/src/detect/sast/scanner.mjs +1 -1
  23. package/src/detect/signals/agent-frameworks.mjs +231 -0
  24. package/src/detect/signals/agent-graph-surface.mjs +113 -0
  25. package/src/detect/signals/agentic-ci-surface.mjs +314 -0
  26. package/src/detect/signals/agentic-shim.mjs +82 -0
  27. package/src/detect/signals/artifacts.mjs +7 -35
  28. package/src/detect/signals/chat-template.mjs +211 -0
  29. package/src/detect/signals/ci-workflow.mjs +169 -0
  30. package/src/detect/signals/gate.mjs +77 -9
  31. package/src/detect/signals/guardrail-shape.mjs +564 -0
  32. package/src/detect/signals/guardrail-surface.mjs +221 -0
  33. package/src/detect/signals/injection.mjs +8 -0
  34. package/src/detect/signals/inspect-shim.mjs +7 -0
  35. package/src/detect/signals/instruction-paths.mjs +60 -0
  36. package/src/detect/signals/manifests.mjs +302 -0
  37. package/src/detect/signals/mcp-advisories.mjs +109 -0
  38. package/src/detect/signals/mcp-config.mjs +598 -0
  39. package/src/detect/signals/memory-directives.mjs +661 -0
  40. package/src/detect/signals/memory-locations.mjs +158 -0
  41. package/src/detect/signals/memory.mjs +47 -29
  42. package/src/detect/signals/model-config-rules.mjs +655 -0
  43. package/src/detect/signals/model-config.mjs +61 -0
  44. package/src/detect/signals/prose-context.mjs +6 -9
  45. package/src/detect/signals/scan.mjs +4 -4
  46. package/src/detect/signals/secret-scanner.mjs +241 -0
  47. package/src/detect/signals/secrets.mjs +1 -48
  48. package/src/detect/signals/shell.mjs +3 -3
  49. package/src/gate/advisories.mjs +16 -0
  50. package/src/gate/batch.mjs +10 -0
  51. package/src/gate/environment.mjs +8 -53
  52. package/src/guard/artifact-paths.mjs +107 -0
  53. package/src/guard/classify.mjs +165 -7
  54. package/src/guard/command-resolve.mjs +35 -5
  55. package/src/guard/memory-write.mjs +218 -0
  56. package/src/guard/prompt-guard.mjs +0 -1
  57. package/src/guard/tool-guard.mjs +52 -77
  58. package/src/inventory/agent-posture.mjs +236 -57
  59. package/src/inventory/artifacts/classify.mjs +10 -1
  60. package/src/inventory/artifacts/discover.mjs +113 -3
  61. package/src/inventory/artifacts/extensions.mjs +70 -0
  62. package/src/inventory/artifacts/hook-scripts.mjs +128 -0
  63. package/src/inventory/artifacts/limits.mjs +1 -1
  64. package/src/inventory/artifacts/plugins.mjs +105 -0
  65. package/src/inventory/artifacts/roots.mjs +40 -0
  66. package/src/inventory/discovery/ai-dependencies.mjs +39 -12
  67. package/src/inventory/discovery/all.mjs +4 -0
  68. package/src/inventory/discovery/cloud-clis.mjs +472 -0
  69. package/src/inventory/discovery/coding-agents.mjs +19 -4
  70. package/src/inventory/discovery/mcp-clients.mjs +16 -10
  71. package/src/inventory/discovery/mcp-servers.mjs +125 -35
  72. package/src/inventory/discovery/mcp-stores.mjs +207 -0
  73. package/src/inventory/env-redirect.mjs +148 -0
  74. package/src/inventory/grant-extract.mjs +463 -0
  75. package/src/inventory/project-roots.mjs +108 -0
  76. package/src/inventory/vscode-state.mjs +153 -0
  77. package/src/mcp/server-tools.mjs +1 -1
@@ -0,0 +1,153 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { createRequire } from 'node:module';
5
+
6
+ const require = createRequire(import.meta.url);
7
+ const MAX_VALUE_BYTES = 8 * 1024 * 1024;
8
+ const MAX_ROWS = 20;
9
+
10
+ let sqlite;
11
+
12
+ function loadSqlite() {
13
+ if (sqlite !== undefined) return sqlite;
14
+ const original = process.emitWarning;
15
+ process.emitWarning = function (warning, ...rest) {
16
+ if (/sqlite/i.test(String(warning?.message ?? warning))) return;
17
+ return original.call(process, warning, ...rest);
18
+ };
19
+ try {
20
+ sqlite = require('node:sqlite');
21
+ } catch {
22
+ sqlite = null;
23
+ } finally {
24
+ process.emitWarning = original;
25
+ }
26
+ return sqlite;
27
+ }
28
+
29
+ export function stateDbAvailable() {
30
+ return !!loadSqlite()?.DatabaseSync;
31
+ }
32
+
33
+ function openCopy(file) {
34
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'shomra-state-'));
35
+ const copy = path.join(dir, 'state.vscdb');
36
+ fs.copyFileSync(file, copy);
37
+ for (const suffix of ['-wal', '-shm']) {
38
+ if (fs.existsSync(file + suffix)) fs.copyFileSync(file + suffix, copy + suffix);
39
+ }
40
+ return { copy, cleanup: () => fs.rmSync(dir, { recursive: true, force: true }) };
41
+ }
42
+
43
+ function queryRows(db, keys) {
44
+ const rows = [];
45
+ const exact = db.prepare('SELECT key, value FROM ItemTable WHERE lower(key) = lower(?)');
46
+ const like = db.prepare('SELECT key, value FROM ItemTable WHERE lower(key) LIKE lower(?) LIMIT ?');
47
+ for (const k of keys) {
48
+ if (k.includes('%')) rows.push(...like.all(k, MAX_ROWS));
49
+ else {
50
+ const row = exact.get(k);
51
+ if (row) rows.push(row);
52
+ }
53
+ if (rows.length >= MAX_ROWS) break;
54
+ }
55
+ return rows.slice(0, MAX_ROWS);
56
+ }
57
+
58
+ function decode(value) {
59
+ if (value == null) return null;
60
+ const text = typeof value === 'string' ? value : Buffer.from(value).toString('utf8');
61
+ if (text.length > MAX_VALUE_BYTES) return { oversized: true };
62
+ try {
63
+ return { json: JSON.parse(text) };
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ export function readStateKeys(file, keys) {
70
+ if (!fs.existsSync(file)) return { state: 'absent' };
71
+ const lib = loadSqlite();
72
+ if (!lib?.DatabaseSync) return { state: 'unreadable', reason: 'sqlite-unavailable' };
73
+
74
+ let db = null;
75
+ let cleanup = null;
76
+ try {
77
+ try {
78
+ db = new lib.DatabaseSync(file, { readOnly: true });
79
+ db.prepare('SELECT 1 FROM ItemTable LIMIT 1').get();
80
+ } catch {
81
+ db?.close?.();
82
+ const c = openCopy(file);
83
+ cleanup = c.cleanup;
84
+ db = new lib.DatabaseSync(c.copy, { readOnly: true });
85
+ }
86
+ const rows = queryRows(db, keys);
87
+ if (!rows.length) return { state: 'absent' };
88
+ const values = [];
89
+ for (const row of rows) {
90
+ const d = decode(row.value);
91
+ if (d?.oversized) return { state: 'unreadable', reason: 'oversized' };
92
+ if (d?.json !== undefined) values.push({ key: row.key, json: d.json });
93
+ }
94
+ return values.length ? { state: 'read', values } : { state: 'unreadable', reason: 'parse-failed' };
95
+ } catch (err) {
96
+ return { state: 'unreadable', reason: /locked|busy/i.test(String(err?.message)) ? 'locked' : 'db-read-failed' };
97
+ } finally {
98
+ try { db?.close?.(); } catch {}
99
+ cleanup?.();
100
+ }
101
+ }
102
+
103
+ const isObj = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
104
+
105
+ export const CURSOR_APP_USER_KEY = 'src.vs.platform.reactivestorage.browser.reactiveStorageServiceImpl.persistentStorage.applicationUser';
106
+
107
+ export function interpretCursor(json) {
108
+ const cs = isObj(json?.composerState) ? json.composerState : null;
109
+ if (!cs) return {};
110
+ const doc = {};
111
+ const allowlist = Array.isArray(cs.yoloCommandAllowlist) ? cs.yoloCommandAllowlist.filter((c) => typeof c === 'string') : [];
112
+ if (cs.useYoloMode === true) {
113
+ if (cs.yoloEnableRunEverything === true || !allowlist.length) doc.yoloEnableRunEverything = true;
114
+ else doc.yoloCommandAllowlist = allowlist;
115
+ if (cs.yoloMcpToolsDisabled === false) doc.mcpAllowlist = ['*:*'];
116
+ if (cs.yoloOutsideWorkspaceDisabled === false) doc.fileSystem = { write: ['../**'] };
117
+ }
118
+ if (Array.isArray(cs.webFetchDomainAllowlist) && cs.webFetchDomainAllowlist.length) {
119
+ doc.network = { outbound: cs.webFetchDomainAllowlist.filter((d) => typeof d === 'string') };
120
+ }
121
+ return doc;
122
+ }
123
+
124
+ const CLINE_KEYS = ['autoApprovalSettings', 'yoloModeToggled', 'allowedCommands', 'mode'];
125
+
126
+ export function interpretCline(json) {
127
+ if (!isObj(json)) return {};
128
+ const out = Object.fromEntries(CLINE_KEYS.filter((k) => k in json).map((k) => [k, json[k]]));
129
+ const aas = json.autoApprovalSettings;
130
+ if (isObj(aas) && aas.enabled !== false && aas.actions?.useMcp === true) out.mcpAllowlist = ['*:*'];
131
+ return out;
132
+ }
133
+
134
+ export function interpretRoo(json) {
135
+ if (!isObj(json) || json.autoApprovalEnabled === false) return {};
136
+ return Object.fromEntries(
137
+ Object.entries(json).filter(([k]) => /^(?:autoApprovalEnabled|alwaysAllow\w*|allowedCommands|alwaysApproveResubmit)$/.test(k)),
138
+ );
139
+ }
140
+
141
+ export function interpretWindsurf(json) {
142
+ if (!isObj(json)) return {};
143
+ return Object.fromEntries(
144
+ Object.entries(json).filter(([k]) => /autoexecut|cascade.*(?:allow|auto)|turbo|yolo|autorun/i.test(k)),
145
+ );
146
+ }
147
+
148
+ export const INTERPRETERS = {
149
+ cursor: interpretCursor,
150
+ cline: interpretCline,
151
+ roo: interpretRoo,
152
+ windsurf: interpretWindsurf,
153
+ };
@@ -45,7 +45,7 @@ export const MCP_TOOLS = [
45
45
  properties: {
46
46
  content: { type: 'string', description: 'The full proposed file content.' },
47
47
  path: { type: 'string', description: 'The path you intend to write it to (drives which checks apply).' },
48
- kind: { type: 'string', description: 'Optional artifact kind: mcp, skill, command, subagent, hook, rules, agent-card, memory.' },
48
+ kind: { type: 'string', description: 'Optional artifact kind: mcp, skill, command, subagent, hook, rules, agent-card, memory, plugin, tool-manifest, extension, workflow (a CI definition that runs an agent), guardrail (a guardrail / content-filter config), framework (CrewAI / ADK / AutoGen / Langflow / Flowise / Dify file).' },
49
49
  },
50
50
  required: ['content', 'path'],
51
51
  },