@ccoalm/ccl-skills 0.18.1 → 0.18.3
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/README.md +2 -0
- package/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-policy.md +50 -0
- package/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-start.md +30 -40
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-delegation-owner.sh +9 -122
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-edit-isolation.sh +43 -9
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-merge-authorization.sh +95 -2
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/hooks.json +42 -1
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/host-input.py +560 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/merge-authorization-prompt.sh +103 -26
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/owner-dispatch-guard.sh +17 -8
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/proposed-next-stop.sh +14 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/session-start.sh +31 -2
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-context-compact.sh +10 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-extraction-gate-stop.sh +17 -4
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-loading.py +277 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/task-entry.sh +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_delegation_owner.sh +61 -55
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_merge_authorization.sh +140 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_host_input.py +630 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_merge_authorization_prompt.sh +56 -3
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_proposed_next.py +292 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_session_start.sh +85 -3
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_skill_loading.py +278 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_task_entry.py +103 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/ccl-skills.ts +36 -6
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/README.md +23 -15
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.sh +41 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +5 -5
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +12 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +26 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/pre-final-continuation-gate.md +9 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/extraction_review_gate.sh +2 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_skill_catalog.sh +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_extraction_review_gate.sh +59 -5
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/references/hook-authorization.md +13 -0
- package/dist/assets/release.json +95 -30
- package/dist/codex-hooks.d.ts +15 -0
- package/dist/codex-hooks.js +186 -0
- package/dist/opencode-adapter.js +8 -3
- package/dist/operations.js +13 -9
- package/package.json +1 -1
package/dist/assets/release.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"npmPackage": "@ccoalm/ccl-skills",
|
|
4
|
-
"version": "0.18.
|
|
5
|
-
"sourceCommit": "
|
|
4
|
+
"version": "0.18.3",
|
|
5
|
+
"sourceCommit": "29c5c6b6d0e35572de2c269ef75b3680d0b9da35",
|
|
6
6
|
"sourceState": "clean",
|
|
7
7
|
"files": [
|
|
8
8
|
{
|
|
@@ -40,9 +40,14 @@
|
|
|
40
40
|
"sha256": "5a06ab4ac6a633be7ebb542de579a1d2153f6cf5bbe1551702a5e3d923642181",
|
|
41
41
|
"mode": 420
|
|
42
42
|
},
|
|
43
|
+
{
|
|
44
|
+
"path": "marketplace/plugins/ccl-skills/agent-context/session-policy.md",
|
|
45
|
+
"sha256": "a54a3a1bde6a3e0691995865250d2b021eeb22ccebfa5f99a31b9447325eda55",
|
|
46
|
+
"mode": 420
|
|
47
|
+
},
|
|
43
48
|
{
|
|
44
49
|
"path": "marketplace/plugins/ccl-skills/agent-context/session-start.md",
|
|
45
|
-
"sha256": "
|
|
50
|
+
"sha256": "ea0109f642fb331250e64bc28691439250575751165334f2b0175a9e3c286175",
|
|
46
51
|
"mode": 420
|
|
47
52
|
},
|
|
48
53
|
{
|
|
@@ -57,32 +62,37 @@
|
|
|
57
62
|
},
|
|
58
63
|
{
|
|
59
64
|
"path": "marketplace/plugins/ccl-skills/hooks/guard-delegation-owner.sh",
|
|
60
|
-
"sha256": "
|
|
65
|
+
"sha256": "8f5350f4a7a57edc5e9f57fb08ab211955007902e79979b6f7cc24e56e5a3695",
|
|
61
66
|
"mode": 493
|
|
62
67
|
},
|
|
63
68
|
{
|
|
64
69
|
"path": "marketplace/plugins/ccl-skills/hooks/guard-edit-isolation.sh",
|
|
65
|
-
"sha256": "
|
|
70
|
+
"sha256": "5ef7a68518bc72d1640a395db1d7c12112e24e59e6fb5b9a6dae212ba7a34272",
|
|
66
71
|
"mode": 493
|
|
67
72
|
},
|
|
68
73
|
{
|
|
69
74
|
"path": "marketplace/plugins/ccl-skills/hooks/guard-merge-authorization.sh",
|
|
70
|
-
"sha256": "
|
|
75
|
+
"sha256": "d12e8c81122babe65d12cca2576b0e2b73b40f4e82090ef31de26bbc893a1cba",
|
|
71
76
|
"mode": 493
|
|
72
77
|
},
|
|
73
78
|
{
|
|
74
79
|
"path": "marketplace/plugins/ccl-skills/hooks/hooks.json",
|
|
75
|
-
"sha256": "
|
|
80
|
+
"sha256": "cf0749d6ed798494e622a27968207bfe3c5a465396aa261ffda6a492bc4294e2",
|
|
81
|
+
"mode": 420
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"path": "marketplace/plugins/ccl-skills/hooks/host-input.py",
|
|
85
|
+
"sha256": "546abe258e25d8103f42259a58b61142418d6c4fd1696f79cfef0fe3876a90c6",
|
|
76
86
|
"mode": 420
|
|
77
87
|
},
|
|
78
88
|
{
|
|
79
89
|
"path": "marketplace/plugins/ccl-skills/hooks/merge-authorization-prompt.sh",
|
|
80
|
-
"sha256": "
|
|
90
|
+
"sha256": "aba3a7fc3e6411da710dcc027f965f9042bc8ef72d74fccce0f56b527711f0a8",
|
|
81
91
|
"mode": 493
|
|
82
92
|
},
|
|
83
93
|
{
|
|
84
94
|
"path": "marketplace/plugins/ccl-skills/hooks/owner-dispatch-guard.sh",
|
|
85
|
-
"sha256": "
|
|
95
|
+
"sha256": "5d9ff755de829663f69e2f7dcf4351af9767f540a6c193458fd562eec0ee2d44",
|
|
86
96
|
"mode": 493
|
|
87
97
|
},
|
|
88
98
|
{
|
|
@@ -90,6 +100,11 @@
|
|
|
90
100
|
"sha256": "f36d6fe6c8b7c43f43301a2a3cf0f6756d4ca2e942ed8495ccd5940f2ce519bc",
|
|
91
101
|
"mode": 493
|
|
92
102
|
},
|
|
103
|
+
{
|
|
104
|
+
"path": "marketplace/plugins/ccl-skills/hooks/proposed-next-stop.sh",
|
|
105
|
+
"sha256": "150d6a6a2b87dec330b8affaba5497ecf40483304d52c503d8ebfe6a5e51f2f8",
|
|
106
|
+
"mode": 493
|
|
107
|
+
},
|
|
93
108
|
{
|
|
94
109
|
"path": "marketplace/plugins/ccl-skills/hooks/remind-post-merge-cleanup.sh",
|
|
95
110
|
"sha256": "c912bd8bbb9afe15b4ed3ac546175ecb9185752087a818d1426ffecd68ffb623",
|
|
@@ -117,12 +132,22 @@
|
|
|
117
132
|
},
|
|
118
133
|
{
|
|
119
134
|
"path": "marketplace/plugins/ccl-skills/hooks/session-start.sh",
|
|
120
|
-
"sha256": "
|
|
135
|
+
"sha256": "fb5bb29239130df92146b3afb38384d15e0f32c0463f7c7e903683aa085d2dd6",
|
|
136
|
+
"mode": 493
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"path": "marketplace/plugins/ccl-skills/hooks/skill-context-compact.sh",
|
|
140
|
+
"sha256": "1bf21e91517d4b56a9cbe1e98bfc8f09201ee07a5f9d32441b55875df03113a8",
|
|
121
141
|
"mode": 493
|
|
122
142
|
},
|
|
123
143
|
{
|
|
124
144
|
"path": "marketplace/plugins/ccl-skills/hooks/skill-extraction-gate-stop.sh",
|
|
125
|
-
"sha256": "
|
|
145
|
+
"sha256": "b4e5c96cd44d3dd9fdae3d6acd7ac7dc629b1ef52d85c6d42934bc84868fa8bd",
|
|
146
|
+
"mode": 493
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"path": "marketplace/plugins/ccl-skills/hooks/skill-loading.py",
|
|
150
|
+
"sha256": "f59162a353d905ef419a0075a2cf20063e7cd757799d4da7b9f7210e3ecd0272",
|
|
126
151
|
"mode": 493
|
|
127
152
|
},
|
|
128
153
|
{
|
|
@@ -130,9 +155,14 @@
|
|
|
130
155
|
"sha256": "04965611f74a73030917d501efd9b205cabc52082af05e6fc9dc5be3703a8adf",
|
|
131
156
|
"mode": 493
|
|
132
157
|
},
|
|
158
|
+
{
|
|
159
|
+
"path": "marketplace/plugins/ccl-skills/hooks/task-entry.sh",
|
|
160
|
+
"sha256": "f75f318e1e1fc9ff2c2f89b3a2dec563e95d3c0a817155d8c4e78bb936ba54f9",
|
|
161
|
+
"mode": 493
|
|
162
|
+
},
|
|
133
163
|
{
|
|
134
164
|
"path": "marketplace/plugins/ccl-skills/hooks/test_guard_delegation_owner.sh",
|
|
135
|
-
"sha256": "
|
|
165
|
+
"sha256": "0a93622a22c9b0a2dc543f77e9bc4eca892608def1cf1be2392d3dda0837bf0d",
|
|
136
166
|
"mode": 420
|
|
137
167
|
},
|
|
138
168
|
{
|
|
@@ -142,14 +172,24 @@
|
|
|
142
172
|
},
|
|
143
173
|
{
|
|
144
174
|
"path": "marketplace/plugins/ccl-skills/hooks/test_guard_merge_authorization.sh",
|
|
145
|
-
"sha256": "
|
|
175
|
+
"sha256": "46aa31fb242e9096545d00554cb17eaf9bd4fef68fa4e49ee581148b638e3a08",
|
|
146
176
|
"mode": 493
|
|
147
177
|
},
|
|
178
|
+
{
|
|
179
|
+
"path": "marketplace/plugins/ccl-skills/hooks/test_host_input.py",
|
|
180
|
+
"sha256": "459cc71337e1d2ddcd125652fe1cb7ed04bda2c65d0d60dcae1d145b1c78dd48",
|
|
181
|
+
"mode": 420
|
|
182
|
+
},
|
|
148
183
|
{
|
|
149
184
|
"path": "marketplace/plugins/ccl-skills/hooks/test_merge_authorization_prompt.sh",
|
|
150
|
-
"sha256": "
|
|
185
|
+
"sha256": "acb48c3fd690bd0c7353d2071e1cdd81b28a414d10452a579bf3bb044da1462d",
|
|
151
186
|
"mode": 420
|
|
152
187
|
},
|
|
188
|
+
{
|
|
189
|
+
"path": "marketplace/plugins/ccl-skills/hooks/test_proposed_next.py",
|
|
190
|
+
"sha256": "936ffb3c57162cb712b51ee7dc33a775b96ef5d7d5807424f326c62a644b8638",
|
|
191
|
+
"mode": 493
|
|
192
|
+
},
|
|
153
193
|
{
|
|
154
194
|
"path": "marketplace/plugins/ccl-skills/hooks/test_remind_post_merge_cleanup.sh",
|
|
155
195
|
"sha256": "f57ede7e26be676f3759d97e5707c4f9390623701103f2cfc4465a9d1669abf3",
|
|
@@ -172,9 +212,19 @@
|
|
|
172
212
|
},
|
|
173
213
|
{
|
|
174
214
|
"path": "marketplace/plugins/ccl-skills/hooks/test_session_start.sh",
|
|
175
|
-
"sha256": "
|
|
215
|
+
"sha256": "e79bf4046ddb527a19c6599be9ede656dfe280583002706645cebfcc4ec6856b",
|
|
176
216
|
"mode": 420
|
|
177
217
|
},
|
|
218
|
+
{
|
|
219
|
+
"path": "marketplace/plugins/ccl-skills/hooks/test_skill_loading.py",
|
|
220
|
+
"sha256": "78ca5d46dc116328a8eb0552011313dafdf20c472b0bd981937ec4f9f897f462",
|
|
221
|
+
"mode": 493
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"path": "marketplace/plugins/ccl-skills/hooks/test_task_entry.py",
|
|
225
|
+
"sha256": "2d7e487f12fce3a090d089a45d9296334c7213126b0925012783f2ccc29afcad",
|
|
226
|
+
"mode": 493
|
|
227
|
+
},
|
|
178
228
|
{
|
|
179
229
|
"path": "marketplace/plugins/ccl-skills/packages/opencode-plugin/AGENTS.md",
|
|
180
230
|
"sha256": "6b0a214f91bf2abe637d2bbd430b815caf2ab4c20cd25e33a80e70f21bc02b3a",
|
|
@@ -182,7 +232,7 @@
|
|
|
182
232
|
},
|
|
183
233
|
{
|
|
184
234
|
"path": "marketplace/plugins/ccl-skills/packages/opencode-plugin/ccl-skills.ts",
|
|
185
|
-
"sha256": "
|
|
235
|
+
"sha256": "059c7309a9697eb7d5e94f83363bee9bd5cd0f1be70b12b2ae099e1f59500cb7",
|
|
186
236
|
"mode": 420
|
|
187
237
|
},
|
|
188
238
|
{
|
|
@@ -217,12 +267,12 @@
|
|
|
217
267
|
},
|
|
218
268
|
{
|
|
219
269
|
"path": "marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.sh",
|
|
220
|
-
"sha256": "
|
|
270
|
+
"sha256": "af57aaecf6bcb1c396d3f1072a5dc4a260807555d45755e824b082cbfd43baea",
|
|
221
271
|
"mode": 493
|
|
222
272
|
},
|
|
223
273
|
{
|
|
224
274
|
"path": "marketplace/plugins/ccl-skills/scripts/owner-dispatch/README.md",
|
|
225
|
-
"sha256": "
|
|
275
|
+
"sha256": "00c5f07f97a24901ec97bb311cf077f5cb1d49b228449603d9f9291f36bd93af",
|
|
226
276
|
"mode": 420
|
|
227
277
|
},
|
|
228
278
|
{
|
|
@@ -307,7 +357,7 @@
|
|
|
307
357
|
},
|
|
308
358
|
{
|
|
309
359
|
"path": "marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md",
|
|
310
|
-
"sha256": "
|
|
360
|
+
"sha256": "cd54a910c1394f73af5d4eb65039c7a76617af1fd434cdc4b7b498157b41a104",
|
|
311
361
|
"mode": 420
|
|
312
362
|
},
|
|
313
363
|
{
|
|
@@ -402,7 +452,7 @@
|
|
|
402
452
|
},
|
|
403
453
|
{
|
|
404
454
|
"path": "marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py",
|
|
405
|
-
"sha256": "
|
|
455
|
+
"sha256": "3227b42ca37a81e557bf92d726cd84fa209d7ea6ee2947e60915b5484c45272b",
|
|
406
456
|
"mode": 493
|
|
407
457
|
},
|
|
408
458
|
{
|
|
@@ -527,7 +577,7 @@
|
|
|
527
577
|
},
|
|
528
578
|
{
|
|
529
579
|
"path": "marketplace/plugins/ccl-skills/skills/code-review/SKILL.md",
|
|
530
|
-
"sha256": "
|
|
580
|
+
"sha256": "a87647f9ff86840d247eb5ed3b7406422fbef7f3c2da21237a331f8cb5e83781",
|
|
531
581
|
"mode": 420
|
|
532
582
|
},
|
|
533
583
|
{
|
|
@@ -1427,7 +1477,7 @@
|
|
|
1427
1477
|
},
|
|
1428
1478
|
{
|
|
1429
1479
|
"path": "marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/pre-final-continuation-gate.md",
|
|
1430
|
-
"sha256": "
|
|
1480
|
+
"sha256": "498c56d47f9ced718173e2b537c03a767d01499b2556a8aa59893c2f39428630",
|
|
1431
1481
|
"mode": 420
|
|
1432
1482
|
},
|
|
1433
1483
|
{
|
|
@@ -2157,7 +2207,7 @@
|
|
|
2157
2207
|
},
|
|
2158
2208
|
{
|
|
2159
2209
|
"path": "marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md",
|
|
2160
|
-
"sha256": "
|
|
2210
|
+
"sha256": "a7e0ec62d3670e802ca2ede7d73f796393f657d080a40a34df97c35458490bbc",
|
|
2161
2211
|
"mode": 420
|
|
2162
2212
|
},
|
|
2163
2213
|
{
|
|
@@ -2262,7 +2312,7 @@
|
|
|
2262
2312
|
},
|
|
2263
2313
|
{
|
|
2264
2314
|
"path": "marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/extraction_review_gate.sh",
|
|
2265
|
-
"sha256": "
|
|
2315
|
+
"sha256": "247d6b9ca7996942e68a225661b43e80c1c8cb4c2d4e1042d1d201a830ba9a51",
|
|
2266
2316
|
"mode": 493
|
|
2267
2317
|
},
|
|
2268
2318
|
{
|
|
@@ -2372,7 +2422,7 @@
|
|
|
2372
2422
|
},
|
|
2373
2423
|
{
|
|
2374
2424
|
"path": "marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_skill_catalog.sh",
|
|
2375
|
-
"sha256": "
|
|
2425
|
+
"sha256": "3c133a45044e2cc665e5e6113ad084f52f385ca82a51ddfaccaa7125d7990d2b",
|
|
2376
2426
|
"mode": 493
|
|
2377
2427
|
},
|
|
2378
2428
|
{
|
|
@@ -2447,7 +2497,7 @@
|
|
|
2447
2497
|
},
|
|
2448
2498
|
{
|
|
2449
2499
|
"path": "marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_extraction_review_gate.sh",
|
|
2450
|
-
"sha256": "
|
|
2500
|
+
"sha256": "0f474ac1861a1fdd8bf36c2c955c69f127b77ed1e5bd460b35d3d73290c1d15f",
|
|
2451
2501
|
"mode": 493
|
|
2452
2502
|
},
|
|
2453
2503
|
{
|
|
@@ -3255,6 +3305,11 @@
|
|
|
3255
3305
|
"sha256": "63ebeb661eeb644497e57a2412f4fb7bc08bb9b19fc568ecb2b6f45f4ecfb070",
|
|
3256
3306
|
"mode": 420
|
|
3257
3307
|
},
|
|
3308
|
+
{
|
|
3309
|
+
"path": "marketplace/plugins/ccl-skills/skills/worktree-isolation/references/hook-authorization.md",
|
|
3310
|
+
"sha256": "989be64bb1d59bdf92c72c4bed407381c25b906e2b436ba8ab601e5590600ce8",
|
|
3311
|
+
"mode": 420
|
|
3312
|
+
},
|
|
3258
3313
|
{
|
|
3259
3314
|
"path": "marketplace/plugins/ccl-skills/skills/worktree-isolation/references/shared-branch-rebase.md",
|
|
3260
3315
|
"sha256": "99423dfd5acb461385de9f21f65eca802f975355a81590bec0617f401088abe8",
|
|
@@ -3287,7 +3342,7 @@
|
|
|
3287
3342
|
},
|
|
3288
3343
|
{
|
|
3289
3344
|
"path": "marketplace/plugins/ccl-skills/skills/worktree-isolation/SKILL.md",
|
|
3290
|
-
"sha256": "
|
|
3345
|
+
"sha256": "a9671ca9a82aa4f2171b9f2fc129bf1d5125317e062dc29e262d75824217e22c",
|
|
3291
3346
|
"mode": 420
|
|
3292
3347
|
}
|
|
3293
3348
|
],
|
|
@@ -3322,6 +3377,16 @@
|
|
|
3322
3377
|
"sha256": "5b5ab7f39b7faa81ea209b3e479295da64f2a834969ee5ac8d76354a182c2822",
|
|
3323
3378
|
"mode": 493
|
|
3324
3379
|
},
|
|
3380
|
+
{
|
|
3381
|
+
"path": "codex-hooks.d.ts",
|
|
3382
|
+
"sha256": "c87b1afaffe146fcce3d1e8a948e67db91e7b671fd1f944b879ef4b5114a56ee",
|
|
3383
|
+
"mode": 420
|
|
3384
|
+
},
|
|
3385
|
+
{
|
|
3386
|
+
"path": "codex-hooks.js",
|
|
3387
|
+
"sha256": "cd2a131514391ed37e83cf8b5e90eb0d34c3f049c4d1780fa9b0443afa242de4",
|
|
3388
|
+
"mode": 420
|
|
3389
|
+
},
|
|
3325
3390
|
{
|
|
3326
3391
|
"path": "codex-host.d.ts",
|
|
3327
3392
|
"sha256": "0e7c4e32f4627983d04d670efbd63ffe72384fb39b5ebe3bcf22a281421c7985",
|
|
@@ -3379,7 +3444,7 @@
|
|
|
3379
3444
|
},
|
|
3380
3445
|
{
|
|
3381
3446
|
"path": "opencode-adapter.js",
|
|
3382
|
-
"sha256": "
|
|
3447
|
+
"sha256": "213ee1d313a8318617f3865ca261718830c497f9de79ec35f7523bd100ad9c95",
|
|
3383
3448
|
"mode": 420
|
|
3384
3449
|
},
|
|
3385
3450
|
{
|
|
@@ -3389,7 +3454,7 @@
|
|
|
3389
3454
|
},
|
|
3390
3455
|
{
|
|
3391
3456
|
"path": "operations.js",
|
|
3392
|
-
"sha256": "
|
|
3457
|
+
"sha256": "c7d2150f3158a34181c5234f02727b347c6612cdd474877d277e31f1369b31d0",
|
|
3393
3458
|
"mode": 420
|
|
3394
3459
|
},
|
|
3395
3460
|
{
|
|
@@ -3453,5 +3518,5 @@
|
|
|
3453
3518
|
"mode": 420
|
|
3454
3519
|
}
|
|
3455
3520
|
],
|
|
3456
|
-
"snapshotHash": "
|
|
3521
|
+
"snapshotHash": "1f51372beb4f07851dd24d912a7e64042ccfa3bf9a76624cca9857ddf31dcac0"
|
|
3457
3522
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OwnedFile } from "./types.js";
|
|
2
|
+
type HookStatus = "trusted" | "managed" | "untrusted" | "modified" | "disabled" | "missing" | "unknown";
|
|
3
|
+
export interface HookInventory {
|
|
4
|
+
status: HookStatus;
|
|
5
|
+
expected: number;
|
|
6
|
+
observed: number;
|
|
7
|
+
runtime: "unverified";
|
|
8
|
+
reason?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function parseHookInventory(value: unknown, cwd: string, pluginRoot: string, runtime?: {
|
|
11
|
+
codexHome: string;
|
|
12
|
+
files: OwnedFile[];
|
|
13
|
+
}): HookInventory;
|
|
14
|
+
export declare function inspectHooks(codexHome: string, pluginRoot: string, files: OwnedFile[], cwd?: string): HookInventory;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { canonicalAlias, contained, verifyTree } from "./fs-safe.js";
|
|
6
|
+
import { MARKET, REF } from "./paths.js";
|
|
7
|
+
const TIMEOUT_MS = 10000;
|
|
8
|
+
const OUTPUT_LIMIT = 1024 * 1024;
|
|
9
|
+
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
10
|
+
const unknown = (reason, expected = 0, observed = 0) => ({ status: "unknown", expected, observed, runtime: "unverified", reason });
|
|
11
|
+
// Compare native metadata with the verified package snapshot. Merely finding a
|
|
12
|
+
// similarly named plugin or one trusted handler cannot certify the installation.
|
|
13
|
+
export function parseHookInventory(value, cwd, pluginRoot, runtime) {
|
|
14
|
+
let expected = [];
|
|
15
|
+
try {
|
|
16
|
+
const config = JSON.parse(readFileSync(join(pluginRoot, "hooks/hooks.json"), "utf8"));
|
|
17
|
+
if (!record(config) || !record(config.hooks))
|
|
18
|
+
return unknown("invalid-owned-hooks");
|
|
19
|
+
for (const [event, groups] of Object.entries(config.hooks)) {
|
|
20
|
+
if (!Array.isArray(groups))
|
|
21
|
+
return unknown("invalid-owned-hooks");
|
|
22
|
+
for (const group of groups) {
|
|
23
|
+
if (!record(group) || !Array.isArray(group.hooks) || (group.matcher !== undefined && typeof group.matcher !== "string"))
|
|
24
|
+
return unknown("invalid-owned-hooks");
|
|
25
|
+
for (const hook of group.hooks) {
|
|
26
|
+
if (!record(hook) || hook.type !== "command" || typeof hook.command !== "string" || !hook.command)
|
|
27
|
+
return unknown("invalid-owned-hooks");
|
|
28
|
+
expected.push({ eventName: event[0].toLowerCase() + event.slice(1), matcher: group.matcher ?? null, command: hook.command });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return unknown("invalid-owned-hooks");
|
|
35
|
+
}
|
|
36
|
+
if (!expected.length)
|
|
37
|
+
return unknown("empty-owned-hooks");
|
|
38
|
+
const count = expected.length;
|
|
39
|
+
if (!record(value) || !Array.isArray(value.data) || value.data.length !== 1)
|
|
40
|
+
return unknown("malformed-inventory", count);
|
|
41
|
+
const entry = value.data[0];
|
|
42
|
+
if (!record(entry) || typeof entry.cwd !== "string" || !isAbsolute(entry.cwd) || canonicalAlias(resolve(entry.cwd)) !== canonicalAlias(resolve(cwd)) || !Array.isArray(entry.hooks))
|
|
43
|
+
return unknown("malformed-inventory", count);
|
|
44
|
+
if (!Array.isArray(entry.errors) || !Array.isArray(entry.warnings) || entry.errors.length || entry.warnings.length)
|
|
45
|
+
return unknown("inventory-diagnostics", count);
|
|
46
|
+
const statuses = [], keys = new Set();
|
|
47
|
+
let disabled = false;
|
|
48
|
+
const expectedSource = canonicalAlias(join(pluginRoot, "hooks/hooks.json"));
|
|
49
|
+
const verifiedRoots = new Set([canonicalAlias(pluginRoot)]);
|
|
50
|
+
for (const hook of entry.hooks) {
|
|
51
|
+
if (!record(hook))
|
|
52
|
+
return unknown("malformed-inventory", count);
|
|
53
|
+
if (hook.pluginId !== REF)
|
|
54
|
+
continue;
|
|
55
|
+
if (hook.source !== "plugin" || typeof hook.sourcePath !== "string" || !isAbsolute(hook.sourcePath))
|
|
56
|
+
return unknown("hook-source-mismatch", count, statuses.length);
|
|
57
|
+
const source = canonicalAlias(resolve(hook.sourcePath)), root = dirname(dirname(source));
|
|
58
|
+
if (source !== expectedSource) {
|
|
59
|
+
if (!runtime || source !== join(root, "hooks/hooks.json"))
|
|
60
|
+
return unknown("hook-source-mismatch", count, statuses.length);
|
|
61
|
+
const cache = canonicalAlias(join(runtime.codexHome, "plugins/cache", MARKET, "ccl-skills"));
|
|
62
|
+
try {
|
|
63
|
+
if (root === cache || contained(cache, relative(cache, root)) !== root)
|
|
64
|
+
return unknown("hook-source-mismatch", count, statuses.length);
|
|
65
|
+
if (!verifiedRoots.has(root)) {
|
|
66
|
+
if (!runtime.files.length || verifyTree(root, runtime.files).length)
|
|
67
|
+
return unknown("runtime-drift", count, statuses.length);
|
|
68
|
+
verifiedRoots.add(root);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return unknown("hook-source-mismatch", count, statuses.length);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (hook.handlerType !== "command" || typeof hook.command !== "string" || typeof hook.eventName !== "string" || (hook.matcher !== null && typeof hook.matcher !== "string") || typeof hook.enabled !== "boolean" || typeof hook.key !== "string" || !hook.key || keys.has(hook.key) || !["trusted", "untrusted", "modified", "managed"].includes(String(hook.trustStatus)))
|
|
76
|
+
return unknown("malformed-hook", count, statuses.length);
|
|
77
|
+
keys.add(hook.key);
|
|
78
|
+
const commandRoot = dirname(dirname(resolve(hook.sourcePath)));
|
|
79
|
+
const index = expected.findIndex(item => item.eventName === hook.eventName && item.matcher === hook.matcher && item.command.replaceAll("${CLAUDE_PLUGIN_ROOT}", commandRoot).replaceAll("${CODEX_PLUGIN_ROOT}", commandRoot) === hook.command);
|
|
80
|
+
if (index < 0)
|
|
81
|
+
return unknown("hook-definition-mismatch", count, statuses.length);
|
|
82
|
+
expected.splice(index, 1);
|
|
83
|
+
statuses.push(String(hook.trustStatus));
|
|
84
|
+
disabled ||= !hook.enabled;
|
|
85
|
+
}
|
|
86
|
+
const base = { expected: count, observed: statuses.length, runtime: "unverified" };
|
|
87
|
+
if (expected.length)
|
|
88
|
+
return { ...base, status: "missing", reason: "missing-package-hooks" };
|
|
89
|
+
if (statuses.includes("modified"))
|
|
90
|
+
return { ...base, status: "modified" };
|
|
91
|
+
if (statuses.includes("untrusted"))
|
|
92
|
+
return { ...base, status: "untrusted" };
|
|
93
|
+
if (disabled)
|
|
94
|
+
return { ...base, status: "disabled" };
|
|
95
|
+
return { ...base, status: statuses.every(status => status === "managed") ? "managed" : "trusted" };
|
|
96
|
+
}
|
|
97
|
+
// The CLI's operation API is synchronous. Isolate the handshake in a short-lived
|
|
98
|
+
// helper so initialization completes before hooks/list, without starting a turn.
|
|
99
|
+
export function inspectHooks(codexHome, pluginRoot, files, cwd = process.cwd()) {
|
|
100
|
+
const result = spawnSync(process.execPath, [fileURLToPath(import.meta.url), "--inventory-worker", resolve(cwd)], {
|
|
101
|
+
encoding: "utf8", env: { ...process.env, CODEX_HOME: codexHome },
|
|
102
|
+
stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32",
|
|
103
|
+
timeout: TIMEOUT_MS + 1000, killSignal: "SIGKILL", maxBuffer: OUTPUT_LIMIT,
|
|
104
|
+
});
|
|
105
|
+
// The helper and its descendants share an isolated process group. This also
|
|
106
|
+
// catches hosts which leave children alive or hold stdout open after exit.
|
|
107
|
+
if (process.platform !== "win32" && result.pid) {
|
|
108
|
+
try {
|
|
109
|
+
process.kill(-result.pid, "SIGKILL");
|
|
110
|
+
}
|
|
111
|
+
catch { /* group already gone */ }
|
|
112
|
+
}
|
|
113
|
+
if (result.error || result.status !== 0)
|
|
114
|
+
return unknown(result.error?.code === "ETIMEDOUT" ? "timeout" : "unavailable");
|
|
115
|
+
try {
|
|
116
|
+
const payload = JSON.parse(result.stdout);
|
|
117
|
+
if (!record(payload) || payload.ok !== true)
|
|
118
|
+
return unknown(record(payload) && typeof payload.reason === "string" && ["timeout", "unavailable", "malformed-output", "output-limit", "unsupported"].includes(payload.reason) ? payload.reason : "malformed-output");
|
|
119
|
+
return parseHookInventory(payload.result, cwd, pluginRoot, { codexHome, files });
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return unknown("malformed-output");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function inventoryWorker(cwd) {
|
|
126
|
+
const child = spawn("codex", ["app-server", "--stdio"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
127
|
+
let finished = false, initialized = false, received = 0, pending = "";
|
|
128
|
+
const timer = setTimeout(() => finish({ ok: false, reason: "timeout" }), TIMEOUT_MS);
|
|
129
|
+
function finish(value) {
|
|
130
|
+
if (finished)
|
|
131
|
+
return;
|
|
132
|
+
finished = true;
|
|
133
|
+
clearTimeout(timer);
|
|
134
|
+
child.kill("SIGKILL");
|
|
135
|
+
child.stdin.destroy();
|
|
136
|
+
child.stdout.destroy();
|
|
137
|
+
child.stderr.destroy();
|
|
138
|
+
process.stdout.write(JSON.stringify(value));
|
|
139
|
+
}
|
|
140
|
+
const send = (value) => child.stdin.write(`${JSON.stringify(value)}\n`);
|
|
141
|
+
child.on("error", () => finish({ ok: false, reason: "unavailable" }));
|
|
142
|
+
child.on("exit", () => finish({ ok: false, reason: "unavailable" }));
|
|
143
|
+
child.stdin.on("error", () => finish({ ok: false, reason: "unavailable" }));
|
|
144
|
+
child.stderr.on("data", (chunk) => {
|
|
145
|
+
received += chunk.length;
|
|
146
|
+
if (received > OUTPUT_LIMIT)
|
|
147
|
+
finish({ ok: false, reason: "output-limit" });
|
|
148
|
+
});
|
|
149
|
+
child.stdout.setEncoding("utf8");
|
|
150
|
+
child.stdout.on("data", (chunk) => {
|
|
151
|
+
received += Buffer.byteLength(chunk, "utf8");
|
|
152
|
+
if (received > OUTPUT_LIMIT)
|
|
153
|
+
return finish({ ok: false, reason: "output-limit" });
|
|
154
|
+
pending += chunk;
|
|
155
|
+
let newline;
|
|
156
|
+
while (!finished && (newline = pending.indexOf("\n")) >= 0) {
|
|
157
|
+
const line = pending.slice(0, newline);
|
|
158
|
+
pending = pending.slice(newline + 1);
|
|
159
|
+
let response;
|
|
160
|
+
try {
|
|
161
|
+
response = JSON.parse(line);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return finish({ ok: false, reason: "malformed-output" });
|
|
165
|
+
}
|
|
166
|
+
if (!record(response))
|
|
167
|
+
return finish({ ok: false, reason: "malformed-output" });
|
|
168
|
+
if (!Object.hasOwn(response, "id") && typeof response.method === "string")
|
|
169
|
+
continue;
|
|
170
|
+
if (response.id !== (initialized ? 2 : 1))
|
|
171
|
+
return finish({ ok: false, reason: "malformed-output" });
|
|
172
|
+
if (Object.hasOwn(response, "error"))
|
|
173
|
+
return finish({ ok: false, reason: "unsupported" });
|
|
174
|
+
if (!record(response.result))
|
|
175
|
+
return finish({ ok: false, reason: "malformed-output" });
|
|
176
|
+
if (initialized)
|
|
177
|
+
return finish({ ok: true, result: response.result });
|
|
178
|
+
initialized = true;
|
|
179
|
+
send({ method: "initialized", params: {} });
|
|
180
|
+
send({ id: 2, method: "hooks/list", params: { cwds: [cwd] } });
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
send({ id: 1, method: "initialize", params: { clientInfo: { name: "ccl_hook_audit", version: "1.0" }, capabilities: { experimentalApi: true } } });
|
|
184
|
+
}
|
|
185
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url) && process.argv[2] === "--inventory-worker" && isAbsolute(process.argv[3] ?? ""))
|
|
186
|
+
inventoryWorker(process.argv[3]);
|
package/dist/opencode-adapter.js
CHANGED
|
@@ -69,16 +69,21 @@ function source(context) {
|
|
|
69
69
|
throw new Error("invalid CCL_SKILLS_REPO: skills, OpenCode commands, or hook runtime are missing");
|
|
70
70
|
regular(plugin);
|
|
71
71
|
regular(bootstrap);
|
|
72
|
+
for (const helper of ["host-input.py", "skill-loading.py"])
|
|
73
|
+
regular(join(hooks, helper));
|
|
72
74
|
const skillNames = readdirSync(skills, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync(join(skills, entry.name, "SKILL.md"))).map((entry) => entry.name).sort();
|
|
73
75
|
if (!skillNames.length)
|
|
74
76
|
throw new Error("invalid CCL_SKILLS_REPO: no skills found");
|
|
75
77
|
let entries = walk(skills, "skills", "skills");
|
|
76
78
|
entries.push({ source: "packages/opencode-plugin/ccl-skills.ts", destination: "plugins/ccl-skills.ts", sha256: sha256(plugin), mode: regular(plugin).mode & 0o777 });
|
|
77
79
|
entries.push({ source: "agent-context/session-start.md", destination: "ccl-skills/bootstrap.md", sha256: sha256(bootstrap), mode: regular(bootstrap).mode & 0o777 });
|
|
80
|
+
const policy = join(agentContext, "session-policy.md");
|
|
81
|
+
regular(policy);
|
|
82
|
+
entries.push({ source: "agent-context/session-policy.md", destination: "ccl-skills/session-policy.md", sha256: sha256(policy), mode: regular(policy).mode & 0o777 });
|
|
78
83
|
entries.push(...walk(commands, "packages/opencode-plugin/commands", "commands").filter((entry) => /^commands\/ccl-[^/]+\.md$/.test(entry.destination)));
|
|
79
|
-
entries.push(...walk(hooks, "hooks", "ccl-skills/runtime/hooks").filter((entry) =>
|
|
84
|
+
entries.push(...walk(hooks, "hooks", "ccl-skills/runtime/hooks").filter((entry) => ["hooks/hooks.json", "hooks/host-input.py", "hooks/skill-loading.py"].includes(entry.source) || /^hooks\/(?!test_)[^/]+\.sh$/.test(entry.source)));
|
|
80
85
|
entries.push(...walk(ownerDispatch, "scripts/owner-dispatch", "ccl-skills/runtime/scripts/owner-dispatch").filter((entry) => entry.source === "scripts/owner-dispatch/owner-dispatch.sh"));
|
|
81
|
-
entries.push(...walk(agentContext, "agent-context", "ccl-skills/runtime/agent-context").filter((entry) => /^agent-context\/(session-start|subagent-start)\.md$/.test(entry.source)));
|
|
86
|
+
entries.push(...walk(agentContext, "agent-context", "ccl-skills/runtime/agent-context").filter((entry) => /^agent-context\/(session-start|session-policy|subagent-start)\.md$/.test(entry.source)));
|
|
82
87
|
entries = entries.sort((a, b) => a.destination.localeCompare(b.destination));
|
|
83
88
|
const snapshotHash = createHash("sha256").update(JSON.stringify(entries.map(({ source: s, sha256: hash, mode }) => ({ source: s, sha256: hash, mode })))).digest("hex");
|
|
84
89
|
const release = readRelease(join(p.assets, "release.json"));
|
|
@@ -90,7 +95,7 @@ function source(context) {
|
|
|
90
95
|
return { root, entries, snapshotHash, version: release.version, sourceCommit, sourceKind: override ? "override" : "bundled" };
|
|
91
96
|
}
|
|
92
97
|
function allowedDestination(path) {
|
|
93
|
-
return /^skills\/[^/]+\/.+/.test(path) || path === "plugins/ccl-skills.ts" || path === "ccl-skills/bootstrap.md" || /^commands\/ccl-[^/]+\.md$/.test(path) || /^ccl-skills\/runtime\/(hooks|scripts\/owner-dispatch|agent-context)\/[^/]+$/.test(path);
|
|
98
|
+
return /^skills\/[^/]+\/.+/.test(path) || path === "plugins/ccl-skills.ts" || path === "ccl-skills/bootstrap.md" || path === "ccl-skills/session-policy.md" || /^commands\/ccl-[^/]+\.md$/.test(path) || /^ccl-skills\/runtime\/(hooks|scripts\/owner-dispatch|agent-context)\/[^/]+$/.test(path);
|
|
94
99
|
}
|
|
95
100
|
function readManifest(path, root) {
|
|
96
101
|
if (!existsSync(path))
|
package/dist/operations.js
CHANGED
|
@@ -5,6 +5,7 @@ import { checkHost, marketplaceAdd, marketplaceRemove, pluginAdd, pluginRemove,
|
|
|
5
5
|
import { manifestFor, MetadataError, readManifest, readRelease, } from "./manifest.js";
|
|
6
6
|
import { paths, } from "./paths.js";
|
|
7
7
|
import { compare } from "./version.js";
|
|
8
|
+
import { inspectHooks } from "./codex-hooks.js";
|
|
8
9
|
const pending = (message, details = {}) => ({
|
|
9
10
|
code: 3,
|
|
10
11
|
status: "installed-hooks-pending",
|
|
@@ -485,9 +486,13 @@ function doctor(context) {
|
|
|
485
486
|
status: "public-state-mismatch",
|
|
486
487
|
message: "owned files exist but Codex registration does not match the manifest",
|
|
487
488
|
};
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
489
|
+
const pluginPrefix = "marketplace/plugins/ccl-skills/";
|
|
490
|
+
const pluginFiles = manifest.active.ownedFiles.filter(file => file.path.startsWith(pluginPrefix)).map(file => ({ ...file, path: file.path.slice(pluginPrefix.length) }));
|
|
491
|
+
const hooks = inspectHooks(p.codexHome, join(marketPath(p.root, manifest.active.path), "plugins/ccl-skills"), pluginFiles);
|
|
492
|
+
const details = { version: manifest.active.version, hooks };
|
|
493
|
+
if (hooks.status === "trusted" || hooks.status === "managed")
|
|
494
|
+
return { code: 0, status: "installed-hooks-trusted", message: "plugin hooks are configured and trusted; runtime execution is not verified", details };
|
|
495
|
+
return pending(`plugin is installed; hook trust: ${hooks.status}; runtime execution is not verified`, details);
|
|
491
496
|
}
|
|
492
497
|
function installOrUpdate(command, options, context) {
|
|
493
498
|
const p = paths(context);
|
|
@@ -534,13 +539,12 @@ function installOrUpdate(command, options, context) {
|
|
|
534
539
|
message: "public state does not match the owned manifest",
|
|
535
540
|
};
|
|
536
541
|
const comparison = compare(release.version, old.active.version);
|
|
537
|
-
if (comparison === 0)
|
|
542
|
+
if (comparison === 0) {
|
|
543
|
+
const report = doctor(context);
|
|
538
544
|
return command === "install"
|
|
539
|
-
? {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
543
|
-
: doctor(context);
|
|
545
|
+
? { ...report, message: `same version is already installed; ${report.message}` }
|
|
546
|
+
: report;
|
|
547
|
+
}
|
|
544
548
|
if (command === "install")
|
|
545
549
|
return {
|
|
546
550
|
code: 3,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ccoalm/ccl-skills",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"description": "Reusable workflows that help coding agents plan, build, test, review, and release software — for Claude Code, Codex, and OpenCode",
|
|
5
5
|
"keywords": ["skills", "agent-skills", "claude", "claude-code", "codex", "opencode", "agent", "ai", "ai-agents", "cli", "anthropic", "developer-tools"],
|
|
6
6
|
"type": "module",
|