@fml-inc/panopticon 0.1.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/.claude-plugin/plugin.json +10 -0
- package/LICENSE +5 -0
- package/README.md +363 -0
- package/bin/hook-handler +3 -0
- package/bin/mcp-server +3 -0
- package/bin/panopticon +3 -0
- package/bin/proxy +3 -0
- package/bin/server +3 -0
- package/dist/api/client.d.ts +67 -0
- package/dist/api/client.js +48 -0
- package/dist/api/client.js.map +1 -0
- package/dist/chunk-3BUJ7URA.js +387 -0
- package/dist/chunk-3BUJ7URA.js.map +1 -0
- package/dist/chunk-3TZAKV3M.js +158 -0
- package/dist/chunk-3TZAKV3M.js.map +1 -0
- package/dist/chunk-4SM2H22C.js +169 -0
- package/dist/chunk-4SM2H22C.js.map +1 -0
- package/dist/chunk-7Q3BJMLG.js +62 -0
- package/dist/chunk-7Q3BJMLG.js.map +1 -0
- package/dist/chunk-BVOE7A2Z.js +412 -0
- package/dist/chunk-BVOE7A2Z.js.map +1 -0
- package/dist/chunk-CF4GPWLI.js +170 -0
- package/dist/chunk-CF4GPWLI.js.map +1 -0
- package/dist/chunk-DZ5HJFB4.js +467 -0
- package/dist/chunk-DZ5HJFB4.js.map +1 -0
- package/dist/chunk-HQCY722C.js +428 -0
- package/dist/chunk-HQCY722C.js.map +1 -0
- package/dist/chunk-HRCEIYKU.js +134 -0
- package/dist/chunk-HRCEIYKU.js.map +1 -0
- package/dist/chunk-K7YUPLES.js +76 -0
- package/dist/chunk-K7YUPLES.js.map +1 -0
- package/dist/chunk-L7G27XWF.js +130 -0
- package/dist/chunk-L7G27XWF.js.map +1 -0
- package/dist/chunk-LWXF7YRG.js +626 -0
- package/dist/chunk-LWXF7YRG.js.map +1 -0
- package/dist/chunk-NXH7AONS.js +1120 -0
- package/dist/chunk-NXH7AONS.js.map +1 -0
- package/dist/chunk-QK5442ZP.js +55 -0
- package/dist/chunk-QK5442ZP.js.map +1 -0
- package/dist/chunk-QVK6VGCV.js +1703 -0
- package/dist/chunk-QVK6VGCV.js.map +1 -0
- package/dist/chunk-RX2RXHBH.js +1699 -0
- package/dist/chunk-RX2RXHBH.js.map +1 -0
- package/dist/chunk-SEXU2WYG.js +788 -0
- package/dist/chunk-SEXU2WYG.js.map +1 -0
- package/dist/chunk-SUGSQ4YI.js +264 -0
- package/dist/chunk-SUGSQ4YI.js.map +1 -0
- package/dist/chunk-TGXFVAID.js +138 -0
- package/dist/chunk-TGXFVAID.js.map +1 -0
- package/dist/chunk-WLBNFVIG.js +447 -0
- package/dist/chunk-WLBNFVIG.js.map +1 -0
- package/dist/chunk-XLTCUH5A.js +1072 -0
- package/dist/chunk-XLTCUH5A.js.map +1 -0
- package/dist/chunk-YVRWVDIA.js +146 -0
- package/dist/chunk-YVRWVDIA.js.map +1 -0
- package/dist/chunk-ZEC4LRKS.js +176 -0
- package/dist/chunk-ZEC4LRKS.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1084 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-NwoZC-GM.d.ts +20 -0
- package/dist/db.d.ts +46 -0
- package/dist/db.js +15 -0
- package/dist/db.js.map +1 -0
- package/dist/doctor.d.ts +37 -0
- package/dist/doctor.js +14 -0
- package/dist/doctor.js.map +1 -0
- package/dist/hooks/handler.d.ts +23 -0
- package/dist/hooks/handler.js +295 -0
- package/dist/hooks/handler.js.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +243 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/otlp/server.d.ts +7 -0
- package/dist/otlp/server.js +17 -0
- package/dist/otlp/server.js.map +1 -0
- package/dist/permissions.d.ts +33 -0
- package/dist/permissions.js +14 -0
- package/dist/permissions.js.map +1 -0
- package/dist/pricing.d.ts +29 -0
- package/dist/pricing.js +13 -0
- package/dist/pricing.js.map +1 -0
- package/dist/proxy/server.d.ts +10 -0
- package/dist/proxy/server.js +20 -0
- package/dist/proxy/server.js.map +1 -0
- package/dist/prune.d.ts +18 -0
- package/dist/prune.js +13 -0
- package/dist/prune.js.map +1 -0
- package/dist/query.d.ts +56 -0
- package/dist/query.js +27 -0
- package/dist/query.js.map +1 -0
- package/dist/reparse-636YZCE3.js +14 -0
- package/dist/reparse-636YZCE3.js.map +1 -0
- package/dist/repo.d.ts +17 -0
- package/dist/repo.js +9 -0
- package/dist/repo.js.map +1 -0
- package/dist/scanner.d.ts +73 -0
- package/dist/scanner.js +15 -0
- package/dist/scanner.js.map +1 -0
- package/dist/sdk.d.ts +82 -0
- package/dist/sdk.js +208 -0
- package/dist/sdk.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +25 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +35 -0
- package/dist/setup.js +19 -0
- package/dist/setup.js.map +1 -0
- package/dist/sync/index.d.ts +29 -0
- package/dist/sync/index.js +32 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/targets.d.ts +279 -0
- package/dist/targets.js +20 -0
- package/dist/targets.js.map +1 -0
- package/dist/types-D-MYCBol.d.ts +128 -0
- package/dist/types.d.ts +164 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/hooks/hooks.json +274 -0
- package/package.json +124 -0
- package/skills/panopticon-optimize/SKILL.md +222 -0
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"SessionEnd": [
|
|
14
|
+
{
|
|
15
|
+
"hooks": [
|
|
16
|
+
{
|
|
17
|
+
"type": "command",
|
|
18
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"Setup": [
|
|
24
|
+
{
|
|
25
|
+
"hooks": [
|
|
26
|
+
{
|
|
27
|
+
"type": "command",
|
|
28
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"UserPromptSubmit": [
|
|
34
|
+
{
|
|
35
|
+
"hooks": [
|
|
36
|
+
{
|
|
37
|
+
"type": "command",
|
|
38
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"PreToolUse": [
|
|
44
|
+
{
|
|
45
|
+
"hooks": [
|
|
46
|
+
{
|
|
47
|
+
"type": "command",
|
|
48
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"PostToolUse": [
|
|
54
|
+
{
|
|
55
|
+
"hooks": [
|
|
56
|
+
{
|
|
57
|
+
"type": "command",
|
|
58
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"PostToolUseFailure": [
|
|
64
|
+
{
|
|
65
|
+
"hooks": [
|
|
66
|
+
{
|
|
67
|
+
"type": "command",
|
|
68
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"PermissionRequest": [
|
|
74
|
+
{
|
|
75
|
+
"hooks": [
|
|
76
|
+
{
|
|
77
|
+
"type": "command",
|
|
78
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"PermissionDenied": [
|
|
84
|
+
{
|
|
85
|
+
"hooks": [
|
|
86
|
+
{
|
|
87
|
+
"type": "command",
|
|
88
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"Stop": [
|
|
94
|
+
{
|
|
95
|
+
"hooks": [
|
|
96
|
+
{
|
|
97
|
+
"type": "command",
|
|
98
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"StopFailure": [
|
|
104
|
+
{
|
|
105
|
+
"hooks": [
|
|
106
|
+
{
|
|
107
|
+
"type": "command",
|
|
108
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"SubagentStart": [
|
|
114
|
+
{
|
|
115
|
+
"hooks": [
|
|
116
|
+
{
|
|
117
|
+
"type": "command",
|
|
118
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"SubagentStop": [
|
|
124
|
+
{
|
|
125
|
+
"hooks": [
|
|
126
|
+
{
|
|
127
|
+
"type": "command",
|
|
128
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"PreCompact": [
|
|
134
|
+
{
|
|
135
|
+
"hooks": [
|
|
136
|
+
{
|
|
137
|
+
"type": "command",
|
|
138
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
"PostCompact": [
|
|
144
|
+
{
|
|
145
|
+
"hooks": [
|
|
146
|
+
{
|
|
147
|
+
"type": "command",
|
|
148
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
"Notification": [
|
|
154
|
+
{
|
|
155
|
+
"hooks": [
|
|
156
|
+
{
|
|
157
|
+
"type": "command",
|
|
158
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"TeammateIdle": [
|
|
164
|
+
{
|
|
165
|
+
"hooks": [
|
|
166
|
+
{
|
|
167
|
+
"type": "command",
|
|
168
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"TaskCreated": [
|
|
174
|
+
{
|
|
175
|
+
"hooks": [
|
|
176
|
+
{
|
|
177
|
+
"type": "command",
|
|
178
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
"TaskCompleted": [
|
|
184
|
+
{
|
|
185
|
+
"hooks": [
|
|
186
|
+
{
|
|
187
|
+
"type": "command",
|
|
188
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
"Elicitation": [
|
|
194
|
+
{
|
|
195
|
+
"hooks": [
|
|
196
|
+
{
|
|
197
|
+
"type": "command",
|
|
198
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
"ElicitationResult": [
|
|
204
|
+
{
|
|
205
|
+
"hooks": [
|
|
206
|
+
{
|
|
207
|
+
"type": "command",
|
|
208
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
],
|
|
213
|
+
"ConfigChange": [
|
|
214
|
+
{
|
|
215
|
+
"hooks": [
|
|
216
|
+
{
|
|
217
|
+
"type": "command",
|
|
218
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
],
|
|
223
|
+
"InstructionsLoaded": [
|
|
224
|
+
{
|
|
225
|
+
"hooks": [
|
|
226
|
+
{
|
|
227
|
+
"type": "command",
|
|
228
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
229
|
+
}
|
|
230
|
+
]
|
|
231
|
+
}
|
|
232
|
+
],
|
|
233
|
+
"CwdChanged": [
|
|
234
|
+
{
|
|
235
|
+
"hooks": [
|
|
236
|
+
{
|
|
237
|
+
"type": "command",
|
|
238
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
"FileChanged": [
|
|
244
|
+
{
|
|
245
|
+
"hooks": [
|
|
246
|
+
{
|
|
247
|
+
"type": "command",
|
|
248
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
"WorktreeCreate": [
|
|
254
|
+
{
|
|
255
|
+
"hooks": [
|
|
256
|
+
{
|
|
257
|
+
"type": "command",
|
|
258
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
],
|
|
263
|
+
"WorktreeRemove": [
|
|
264
|
+
{
|
|
265
|
+
"hooks": [
|
|
266
|
+
{
|
|
267
|
+
"type": "command",
|
|
268
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/bin/hook-handler claude"
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fml-inc/panopticon",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Observability for Claude Code — captures OTel signals and hook events, queryable via MCP",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22.0.0"
|
|
8
|
+
},
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"registry": "https://registry.npmjs.org",
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/fml-inc/panopticon.git"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin/",
|
|
19
|
+
"dist/",
|
|
20
|
+
"hooks/",
|
|
21
|
+
"skills/",
|
|
22
|
+
".claude-plugin/"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"panopticon": "./bin/panopticon"
|
|
26
|
+
},
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./sdk": {
|
|
33
|
+
"types": "./dist/sdk.d.ts",
|
|
34
|
+
"import": "./dist/sdk.js"
|
|
35
|
+
},
|
|
36
|
+
"./db": {
|
|
37
|
+
"types": "./dist/db.d.ts",
|
|
38
|
+
"import": "./dist/db.js"
|
|
39
|
+
},
|
|
40
|
+
"./types": {
|
|
41
|
+
"types": "./dist/types.d.ts",
|
|
42
|
+
"import": "./dist/types.js"
|
|
43
|
+
},
|
|
44
|
+
"./query": {
|
|
45
|
+
"types": "./dist/query.d.ts",
|
|
46
|
+
"import": "./dist/query.js"
|
|
47
|
+
},
|
|
48
|
+
"./server": {
|
|
49
|
+
"types": "./dist/server.d.ts",
|
|
50
|
+
"import": "./dist/server.js"
|
|
51
|
+
},
|
|
52
|
+
"./setup": {
|
|
53
|
+
"types": "./dist/setup.d.ts",
|
|
54
|
+
"import": "./dist/setup.js"
|
|
55
|
+
},
|
|
56
|
+
"./prune": {
|
|
57
|
+
"types": "./dist/prune.d.ts",
|
|
58
|
+
"import": "./dist/prune.js"
|
|
59
|
+
},
|
|
60
|
+
"./pricing": {
|
|
61
|
+
"types": "./dist/pricing.d.ts",
|
|
62
|
+
"import": "./dist/pricing.js"
|
|
63
|
+
},
|
|
64
|
+
"./permissions": {
|
|
65
|
+
"types": "./dist/permissions.d.ts",
|
|
66
|
+
"import": "./dist/permissions.js"
|
|
67
|
+
},
|
|
68
|
+
"./doctor": {
|
|
69
|
+
"types": "./dist/doctor.d.ts",
|
|
70
|
+
"import": "./dist/doctor.js"
|
|
71
|
+
},
|
|
72
|
+
"./repo": {
|
|
73
|
+
"types": "./dist/repo.d.ts",
|
|
74
|
+
"import": "./dist/repo.js"
|
|
75
|
+
},
|
|
76
|
+
"./scanner": {
|
|
77
|
+
"types": "./dist/scanner.d.ts",
|
|
78
|
+
"import": "./dist/scanner.js"
|
|
79
|
+
},
|
|
80
|
+
"./api": {
|
|
81
|
+
"types": "./dist/api/client.d.ts",
|
|
82
|
+
"import": "./dist/api/client.js"
|
|
83
|
+
},
|
|
84
|
+
"./sync": {
|
|
85
|
+
"types": "./dist/sync/index.d.ts",
|
|
86
|
+
"import": "./dist/sync/index.js"
|
|
87
|
+
},
|
|
88
|
+
"./targets": {
|
|
89
|
+
"types": "./dist/targets.d.ts",
|
|
90
|
+
"import": "./dist/targets.js"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"dependencies": {
|
|
94
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
95
|
+
"@sentry/core": "^10.46.0",
|
|
96
|
+
"better-sqlite3": "^11.0.0",
|
|
97
|
+
"commander": "^14.0.3",
|
|
98
|
+
"protobufjs": "^7.0.0",
|
|
99
|
+
"smol-toml": "^1.3.0",
|
|
100
|
+
"tslog": "^4.10.2",
|
|
101
|
+
"zod": "^4.3.6"
|
|
102
|
+
},
|
|
103
|
+
"devDependencies": {
|
|
104
|
+
"@biomejs/biome": "^2.4.4",
|
|
105
|
+
"@types/better-sqlite3": "^7.0.0",
|
|
106
|
+
"@types/node": "^22.0.0",
|
|
107
|
+
"lefthook": "^2.1.1",
|
|
108
|
+
"tsup": "^8.0.0",
|
|
109
|
+
"typescript": "^5",
|
|
110
|
+
"vitest": "^4.1.0"
|
|
111
|
+
},
|
|
112
|
+
"scripts": {
|
|
113
|
+
"build": "tsup",
|
|
114
|
+
"dev": "tsup --watch",
|
|
115
|
+
"check": "biome check src/",
|
|
116
|
+
"check:fix": "biome check --write src/",
|
|
117
|
+
"format": "biome format --write src/",
|
|
118
|
+
"test": "vitest run --exclude '.claude/**'",
|
|
119
|
+
"test:watch": "vitest --exclude '.claude/**'",
|
|
120
|
+
"typecheck": "tsc --noEmit",
|
|
121
|
+
"pack:local": "pnpm build && pnpm pack",
|
|
122
|
+
"postinstall": "node ./bin/panopticon install && claude plugin update panopticon@local-plugins 2>/dev/null || true"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: panopticon-optimize
|
|
3
|
+
description: "Analyze tool usage from panopticon, categorize by risk level, and generate optimized permission rules. Remembers approved categories across runs."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Panopticon Optimize
|
|
7
|
+
|
|
8
|
+
Analyze all tool usage captured by panopticon for the current repository, categorize each pattern by risk level, auto-allow safe patterns, and prompt for approval of higher-risk categories. Category approvals persist across runs.
|
|
9
|
+
|
|
10
|
+
## Architecture
|
|
11
|
+
|
|
12
|
+
All permissions are enforced via panopticon's `PreToolUse` hook — panopticon does **not** write to `settings.local.json`.
|
|
13
|
+
|
|
14
|
+
- **Bash commands** → chain-aware enforcement: the hook splits chains (`&&`, `;`, `|`) and checks each component independently against approved base commands
|
|
15
|
+
- **Non-Bash tools** → exact name match against the allowed tools list
|
|
16
|
+
|
|
17
|
+
Both are stored in `~/.local/share/panopticon/permissions/allowed.json`. The hook returns `"permissionDecision": "allow"` only when the tool or all chain components match. Unmatched tools fall through to Claude Code's normal prompting.
|
|
18
|
+
|
|
19
|
+
## MCP Tools
|
|
20
|
+
|
|
21
|
+
- **`panopticon_permissions_show`** — Load existing approvals + current allowed tools/commands. Call this first (no arguments needed).
|
|
22
|
+
- **`panopticon_permissions_apply`** — Write allowed.json (Bash commands + tool names), save approvals, and create backup. Call this at the end.
|
|
23
|
+
|
|
24
|
+
All analysis and querying uses the standard `panopticon_query` tool.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Step 1 — Load State
|
|
29
|
+
|
|
30
|
+
Call `panopticon_permissions_show` (no arguments). It returns:
|
|
31
|
+
- `approvals` — previously approved/denied categories and custom overrides
|
|
32
|
+
- `allowed` — current `{ bash_commands, tools }` list
|
|
33
|
+
- File paths for reference
|
|
34
|
+
|
|
35
|
+
`"safe"` is always pre-approved and cannot be removed.
|
|
36
|
+
|
|
37
|
+
## Step 2 — Identify Current Repository
|
|
38
|
+
|
|
39
|
+
Run `git remote get-url origin` and extract `org/repo` (strip `.git` suffix and host prefix). Used for backup metadata only — **not** for scoping queries, since the whitelist is global.
|
|
40
|
+
|
|
41
|
+
## Step 3 — Query Panopticon
|
|
42
|
+
|
|
43
|
+
The allowed list is global (not per-repo), so queries must aggregate across **all** repositories.
|
|
44
|
+
|
|
45
|
+
Run via `panopticon_query`:
|
|
46
|
+
|
|
47
|
+
**Query A — Non-Bash tools:**
|
|
48
|
+
```sql
|
|
49
|
+
SELECT tool_name, COUNT(*) as cnt
|
|
50
|
+
FROM hook_events
|
|
51
|
+
WHERE event_type = 'PreToolUse'
|
|
52
|
+
AND tool_name != 'Bash'
|
|
53
|
+
GROUP BY tool_name ORDER BY cnt DESC
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Query B — All Bash commands (full command strings):**
|
|
57
|
+
```sql
|
|
58
|
+
SELECT
|
|
59
|
+
json_extract(json_extract(decompress(payload), '$.tool_input'), '$.command') as cmd,
|
|
60
|
+
COUNT(*) as cnt
|
|
61
|
+
FROM hook_events
|
|
62
|
+
WHERE event_type = 'PreToolUse' AND tool_name = 'Bash'
|
|
63
|
+
GROUP BY cmd ORDER BY cnt DESC
|
|
64
|
+
LIMIT 500
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Step 4 — Classify
|
|
68
|
+
|
|
69
|
+
For each observed Bash command:
|
|
70
|
+
1. Split on chain operators (`&&`, `;`, `|`) to extract individual commands
|
|
71
|
+
2. For each individual command, extract the **base command** — the first token, or first two tokens for `git`/`gh`/`npx`/`pnpm` subcommands (e.g., `git status`, `npx tsup`)
|
|
72
|
+
3. Classify each base command into a risk category (see below)
|
|
73
|
+
4. Collect all unique base commands across all observed usage
|
|
74
|
+
|
|
75
|
+
### Base command extraction
|
|
76
|
+
|
|
77
|
+
The hook uses the same algorithm, so patterns must match:
|
|
78
|
+
- Simple commands: first token → `ls`, `cat`, `rm`
|
|
79
|
+
- Compound CLI tools: first two tokens → `git status`, `npx tsup`, `pnpm install`, `gh pr`, `xargs grep`
|
|
80
|
+
- Transparent wrappers (compound): `env`, `nice`, `timeout`, `watch` — skip flags/positional args, extract delegated command → `timeout 30 rm` → `timeout rm`, `env NODE_ENV=prod node` → `env node`
|
|
81
|
+
- `find -exec` / `-execdir`: returns **both** `find` and the delegated command → `find . -exec rm {} \;` → `["find", "rm"]` — both must be allowed
|
|
82
|
+
- Shell re-entry: `bash -c` / `sh -c` → base command is `bash`/`sh` (classify as high_destructive)
|
|
83
|
+
- Env var prefixes stripped: `FOO=bar git push` → `git push`
|
|
84
|
+
- Redirections stripped: `ls 2>&1` → `ls`
|
|
85
|
+
|
|
86
|
+
### Risk categories
|
|
87
|
+
|
|
88
|
+
#### Category: `safe` — Read-only, zero side effects
|
|
89
|
+
**Always auto-approved.**
|
|
90
|
+
|
|
91
|
+
Non-Bash tools: `Read`, `Grep`, `Glob`, `ToolSearch`, `Agent`, `EnterPlanMode`, `ExitPlanMode`, `TaskOutput`, `TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet`, and any `mcp__plugin_panopticon_*` tool.
|
|
92
|
+
|
|
93
|
+
Bash base commands:
|
|
94
|
+
- **Read-only fs**: `find`, `ls`, `cat`, `head`, `tail`, `wc`, `pwd`, `echo`, `diff`, `readlink`, `file`, `which`, `type`, `env`, `printenv`, `basename`, `dirname`, `cd`, `mkdir`, `stat`, `du`, `realpath`
|
|
95
|
+
- **Read-only search/text**: `grep`, `rg`, `sort`, `uniq`, `tr`, `cut`, `jq`
|
|
96
|
+
- **Read-only system**: `date`, `uname`, `printf`, `true`, `false`, `test`
|
|
97
|
+
- **Read-only git**: `git status`, `git diff`, `git log`, `git show`, `git blame`, `git branch`, `git ls-tree`, `git merge-base`, `git fetch`, `git remote`, `git rev-parse`, `git describe`, `git tag`
|
|
98
|
+
|
|
99
|
+
#### Category: `low_check` — Lint & type-check (read-only analysis)
|
|
100
|
+
|
|
101
|
+
Base commands: `pnpm type-check`, `pnpm lint`, `npx eslint`, `npx tsc`
|
|
102
|
+
|
|
103
|
+
#### Category: `medium_build` — Local build artifacts only
|
|
104
|
+
|
|
105
|
+
Base commands: `npx tsup`, `npx prettier`, `pnpm exec`
|
|
106
|
+
|
|
107
|
+
#### Category: `medium_deps` — Dependency & formatting changes
|
|
108
|
+
|
|
109
|
+
Base commands: `pnpm format`, `pnpm install`, `pnpm rebuild`
|
|
110
|
+
|
|
111
|
+
#### Category: `medium_git_write` — Local git mutations
|
|
112
|
+
|
|
113
|
+
Base commands: `git add`, `git checkout`, `git stash`, `git commit`, `git rebase`, `git cherry-pick`, `git pull`, `git worktree`, `git merge`
|
|
114
|
+
|
|
115
|
+
#### Category: `high_git_remote` — Remote git & GitHub operations
|
|
116
|
+
|
|
117
|
+
Base commands: `git push`, `gh pr`, `gh run`, `gh api`
|
|
118
|
+
|
|
119
|
+
#### Category: `medium_fs_write` — Non-destructive file operations
|
|
120
|
+
|
|
121
|
+
Base commands: `cp`, `mv`, `touch`, `rmdir`
|
|
122
|
+
|
|
123
|
+
Note: `rmdir` only removes empty directories (fails on non-empty). Less risky than `rm`.
|
|
124
|
+
|
|
125
|
+
Compound commands (`xargs`, `env`, `nice`, `timeout`, `watch`) inherit the delegated command's category. `xargs grep` → safe (grep is safe), `timeout rm` → high_destructive (rm is destructive), `env node` → high_destructive (node is destructive). Classify `{wrapper} {subcmd}` into whatever category `{subcmd}` belongs to.
|
|
126
|
+
|
|
127
|
+
For `find -exec`/`-execdir`, both `find` (safe) and the delegated command must be allowed. If the delegated command is `rm`, the whole command falls into the highest-risk category of its components (high_destructive).
|
|
128
|
+
|
|
129
|
+
#### Category: `high_destructive` — Destructive or arbitrary execution
|
|
130
|
+
|
|
131
|
+
Base commands: `rm`, `pkill`, `kill`, `node`, `python3`, `python`, `sed`, `bash`, `sh`
|
|
132
|
+
|
|
133
|
+
**Default: deny.**
|
|
134
|
+
|
|
135
|
+
#### Category: `high_infra` — Infrastructure & deployment
|
|
136
|
+
|
|
137
|
+
Base commands: `npx convex`, `npx dotenvx`, `docker`, `fly`, `pnpm build`, `pnpm run`, `pnpm dev`, `curl`
|
|
138
|
+
|
|
139
|
+
**Default: deny.**
|
|
140
|
+
|
|
141
|
+
#### Category: `web` — Web access
|
|
142
|
+
|
|
143
|
+
`WebSearch`, `WebFetch`. For WebFetch, extract observed domains and generate domain-restricted patterns.
|
|
144
|
+
|
|
145
|
+
#### Category: `mcp_external` — Non-panopticon MCP/plugin tools
|
|
146
|
+
|
|
147
|
+
Any `mcp__plugin_fml_*`, `mcp__claude_ai_*`, `mcp__discjockey__*`, etc. Present per-plugin.
|
|
148
|
+
|
|
149
|
+
## Step 5 — Generate Permission Patterns
|
|
150
|
+
|
|
151
|
+
For each approved category, generate permission patterns based on observed usage.
|
|
152
|
+
|
|
153
|
+
### Non-Bash tools
|
|
154
|
+
|
|
155
|
+
Use the tool name directly (e.g., `WebSearch`, `mcp__plugin_panopticon_panopticon__panopticon_query`).
|
|
156
|
+
|
|
157
|
+
### Bash commands
|
|
158
|
+
|
|
159
|
+
For each unique base command observed in panopticon data that falls within an approved category, generate `Bash({base_command} *)`. The `panopticon_permissions_apply` tool splits these into the `bash_commands` list in `allowed.json`.
|
|
160
|
+
|
|
161
|
+
### Only generate for observed commands
|
|
162
|
+
|
|
163
|
+
Don't generate patterns for commands never seen in panopticon data. The patterns should reflect actual usage, not hypothetical commands.
|
|
164
|
+
|
|
165
|
+
## Step 6 — Present to User
|
|
166
|
+
|
|
167
|
+
**Summary table first:**
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
Category Risk Patterns Calls Status
|
|
171
|
+
──────────────────────────────────────────────────────────
|
|
172
|
+
safe none 14 1,247 always approved
|
|
173
|
+
low_check low 4 50 previously approved
|
|
174
|
+
medium_build medium 3 9 ? pending
|
|
175
|
+
medium_deps medium 3 15 x previously denied
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Then for each pending category**, show:
|
|
179
|
+
1. Category name, risk level, one-line description
|
|
180
|
+
2. Observed base commands and call counts
|
|
181
|
+
3. Permission patterns that would be generated
|
|
182
|
+
4. Ask: **"Approve `{category}`? (y = approve / n = deny / s = skip)"**
|
|
183
|
+
|
|
184
|
+
- **y**: Add to `approved_categories`
|
|
185
|
+
- **n**: Add to `denied_categories` (won't ask again)
|
|
186
|
+
- **s**: Skip (will ask next run)
|
|
187
|
+
|
|
188
|
+
For `denied_categories`, show as denied with option to re-evaluate.
|
|
189
|
+
|
|
190
|
+
## Step 7 — Apply
|
|
191
|
+
|
|
192
|
+
Call `panopticon_permissions_apply` with:
|
|
193
|
+
- `repository` (optional) — org/repo slug, included in backup metadata
|
|
194
|
+
- `approved_categories` — all approved (including previously approved from state)
|
|
195
|
+
- `denied_categories` — all denied (including previously denied from state)
|
|
196
|
+
- `custom_overrides` — any per-pattern overrides
|
|
197
|
+
- `permissions` — the full permission patterns list (Bash and non-Bash mixed — the tool splits them)
|
|
198
|
+
- `categories` — full category breakdown (for backup)
|
|
199
|
+
|
|
200
|
+
The tool handles atomically:
|
|
201
|
+
1. Writing `allowed.json` with Bash base commands + tool names (for hook enforcement)
|
|
202
|
+
2. Saving approvals state
|
|
203
|
+
3. Creating timestamped backup
|
|
204
|
+
|
|
205
|
+
## Step 8 — Summary
|
|
206
|
+
|
|
207
|
+
Print:
|
|
208
|
+
```
|
|
209
|
+
Panopticon Optimize — Complete
|
|
210
|
+
═══════════════════════════════
|
|
211
|
+
Repository: org/repo
|
|
212
|
+
Analyzed: N tool calls across M sessions
|
|
213
|
+
|
|
214
|
+
allowed.json (hook enforcement):
|
|
215
|
+
X Bash base commands with chain-aware matching
|
|
216
|
+
Y non-Bash tools with exact name matching
|
|
217
|
+
|
|
218
|
+
Backup saved to ~/.local/share/panopticon/permissions/backups/...
|
|
219
|
+
|
|
220
|
+
Run /panopticon-optimize again to update as new patterns appear.
|
|
221
|
+
To reset all decisions: rm ~/.local/share/panopticon/permissions/approvals.json
|
|
222
|
+
```
|