kira-glasses-bridge 2.19.0 → 2.20.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/package.json +1 -1
- package/src/agents/policy.mjs +53 -3
package/package.json
CHANGED
package/src/agents/policy.mjs
CHANGED
|
@@ -31,11 +31,60 @@ export const WEB = new Set(['WebFetch', 'WebSearch'])
|
|
|
31
31
|
/** Claude Code's name for the tools of Kira's MCP server (mcp__<server>__<tool>). */
|
|
32
32
|
export const KIRA_TOOLS = 'mcp__kira__'
|
|
33
33
|
|
|
34
|
-
/**
|
|
35
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Read-only commands: looking, listing, testing, type-checking, building. Nothing that writes, sends
|
|
36
|
+
* or installs, nothing that runs code given inline (node -e, python -c, awk), nothing that prints
|
|
37
|
+
* secrets (heroku config).
|
|
38
|
+
*/
|
|
39
|
+
/** Plain commands that only look. */
|
|
40
|
+
const LOOKERS = [
|
|
41
|
+
'ls', 'll', 'pwd', 'cat', 'head', 'tail', 'wc', 'echo', 'printf', 'which', 'type', 'env', 'printenv',
|
|
42
|
+
'date', 'whoami', 'id', 'uname', 'tree', 'find', 'fd', 'grep', 'rg', 'ag', 'cut', 'tr', 'sort', 'uniq',
|
|
43
|
+
'diff', 'comm', 'stat', 'file', 'du', 'df', 'basename', 'dirname', 'realpath', 'readlink', 'jq', 'yq',
|
|
44
|
+
'xxd', 'hexdump', 'strings', 'test', '[', 'true', 'false', 'sleep', 'md5', 'shasum', 'sha256sum',
|
|
45
|
+
'md5sum', 'column', 'nl', 'less', 'more', 'tsc', 'eslint', 'jest', 'vitest', 'pytest',
|
|
46
|
+
]
|
|
47
|
+
/** Tools with their read-only, test and build subcommands. */
|
|
48
|
+
const SUBCOMMANDS = {
|
|
49
|
+
git: [
|
|
50
|
+
'status', 'diff', 'log', 'show', 'branch', 'rev-parse', 'remote', 'ls-files', 'ls-tree', 'blame', 'describe',
|
|
51
|
+
'stash list', 'tag', 'config --get', 'config -l', 'cat-file', 'grep', 'shortlog', 'count-objects', 'reflog',
|
|
52
|
+
],
|
|
53
|
+
node: ['-v', '--version'],
|
|
54
|
+
npm: ['-v', '--version', 'ls', 'list', 'view', 'outdated', 'why', 'test', 'run test', 'run lint', 'run typecheck',
|
|
55
|
+
'run check', 'run build', 'run format:check'],
|
|
56
|
+
pnpm: ['-v', '--version', 'ls', 'list', 'why', 'outdated', 'test', 'typecheck', 'lint', 'build', 'run test',
|
|
57
|
+
'run lint', 'run typecheck', 'run check', 'run build'],
|
|
58
|
+
yarn: ['-v', '--version', 'list', 'test', 'lint', 'typecheck', 'build'],
|
|
59
|
+
npx: ['tsc', 'eslint', 'prettier --check', 'jest', 'vitest', 'playwright test'],
|
|
60
|
+
prettier: ['--check'],
|
|
61
|
+
cargo: ['check', 'test', 'build', 'fmt --check', 'clippy', 'tree', 'metadata'],
|
|
62
|
+
go: ['test', 'build', 'vet', 'version', 'list', 'env'],
|
|
63
|
+
python: ['-V', '--version', '-m pytest'],
|
|
64
|
+
python3: ['-V', '--version', '-m pytest'],
|
|
65
|
+
ruby: ['-v'],
|
|
66
|
+
make: ['test', 'check', 'lint', 'build'],
|
|
67
|
+
mvn: ['test', 'compile'],
|
|
68
|
+
gradle: ['test', 'build'],
|
|
69
|
+
swift: ['build', 'test'],
|
|
70
|
+
xcodebuild: ['-list'],
|
|
71
|
+
brew: ['list', 'info', '--version'],
|
|
72
|
+
docker: ['ps', 'images', 'version'],
|
|
73
|
+
gh: ['pr list', 'pr view', 'pr status', 'pr checks', 'issue list', 'issue view', 'run list', 'run view', 'repo view'],
|
|
74
|
+
heroku: ['logs', 'ps', 'releases', 'apps', 'info'],
|
|
75
|
+
open: ['-n --args'],
|
|
76
|
+
sed: ['-n', '-E -n', '-n -E'],
|
|
77
|
+
}
|
|
78
|
+
const escape = w => w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
79
|
+
const withSubs = Object.entries(SUBCOMMANDS).flatMap(([tool, subs]) => subs.map(sub => `${tool} ${sub}`))
|
|
80
|
+
const SAFE_PHRASES = [...LOOKERS, ...withSubs]
|
|
81
|
+
const SAFE_CMD = new RegExp(`^(?:${SAFE_PHRASES.map(escape).join('|')})(?:\\s|$)`)
|
|
36
82
|
|
|
37
83
|
/** Redirections that write somewhere other than nowhere. */
|
|
38
84
|
const WRITES = /(^|[^&\d])>(?!&)|>>|\btee\b|\bxargs\b|\beval\b|\bexec\b|`/
|
|
85
|
+
/** find and fd can run or delete what they find: then they aren't looking any more. */
|
|
86
|
+
const FINDER_ACTS =
|
|
87
|
+
/^(?:find|fd)\b.*\s(?:-exec(?:dir)?|-ok(?:dir)?|-delete|-fprint\w*|-fls|-x|--exec(?:-batch)?|-X)\b/
|
|
39
88
|
|
|
40
89
|
function pieces(command) {
|
|
41
90
|
// Strip quoted strings so separators inside them do not split; keep a placeholder.
|
|
@@ -76,7 +125,8 @@ export function shellIsSafe(command, allowRules = []) {
|
|
|
76
125
|
c = c.slice(0, m.index) + '""' + c.slice(m.index + m[0].length)
|
|
77
126
|
}
|
|
78
127
|
if (WRITES.test(c.replace(/2>&1|2>\/dev\/null|>\/dev\/null|&>\/dev\/null/g, ''))) return false
|
|
79
|
-
|
|
128
|
+
const allowedByRule = p => allowRules.some(r => r && (p === r || p.startsWith(String(r) + ' ')))
|
|
129
|
+
return pieces(c).every(p => (SAFE_CMD.test(p) && !FINDER_ACTS.test(p)) || allowedByRule(p))
|
|
80
130
|
}
|
|
81
131
|
|
|
82
132
|
/** The rule key an "always allow" answer produces. */
|