clawclamp 0.1.14 → 0.1.15

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/assets/app.js CHANGED
@@ -324,7 +324,7 @@ policyCreateBtn.addEventListener("click", async () => {
324
324
  body: JSON.stringify(body),
325
325
  });
326
326
  policyStatusEl.textContent = "已新增策略。";
327
- await refreshPolicies();
327
+ await refreshAll();
328
328
  });
329
329
 
330
330
  policyUpdateBtn.addEventListener("click", async () => {
@@ -343,7 +343,7 @@ policyUpdateBtn.addEventListener("click", async () => {
343
343
  body: JSON.stringify({ content }),
344
344
  });
345
345
  policyStatusEl.textContent = "已保存策略。";
346
- await refreshPolicies();
346
+ await refreshAll();
347
347
  });
348
348
 
349
349
  policyDeleteBtn.addEventListener("click", async () => {
@@ -358,5 +358,5 @@ policyDeleteBtn.addEventListener("click", async () => {
358
358
  policyStatusEl.textContent = "已删除策略。";
359
359
  policyIdInput.value = "";
360
360
  policyContentInput.value = "";
361
- await refreshPolicies();
361
+ await refreshAll();
362
362
  });
package/assets/index.html CHANGED
@@ -21,6 +21,40 @@
21
21
  </div>
22
22
  </header>
23
23
 
24
+ <section class="card policy-shell">
25
+ <div class="policy-head">
26
+ <div>
27
+ <h2>Cedar 策略</h2>
28
+ <div class="note">查看与维护当前策略集(policyStoreUri 配置时为只读)。</div>
29
+ </div>
30
+ <div class="policy-badge">Policy Lab</div>
31
+ </div>
32
+ <div class="policy-grid">
33
+ <div class="policy-list-wrap">
34
+ <div class="label">策略列表</div>
35
+ <div class="policy-list" id="policy-list"></div>
36
+ </div>
37
+ <div class="policy-editor">
38
+ <div class="policy-form">
39
+ <label>
40
+ Policy ID
41
+ <input id="policy-id" placeholder="policy-id" />
42
+ </label>
43
+ <label>
44
+ Policy 内容
45
+ <textarea id="policy-content" rows="12" placeholder="permit(principal, action, resource) when { ... }"></textarea>
46
+ </label>
47
+ <div class="policy-actions">
48
+ <button id="policy-create" class="btn primary">新增</button>
49
+ <button id="policy-update" class="btn">保存</button>
50
+ <button id="policy-delete" class="btn warn">删除</button>
51
+ </div>
52
+ <div id="policy-status" class="note"></div>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </section>
57
+
24
58
  <section class="grid">
25
59
  <div class="card">
26
60
  <h2>模式</h2>
@@ -84,32 +118,6 @@
84
118
  </div>
85
119
  <div class="table" id="audit"></div>
86
120
  </section>
87
-
88
- <section class="card">
89
- <h2>Cedar 策略</h2>
90
- <div class="note">查看与维护当前策略集(policyStoreUri 配置时为只读)。</div>
91
- <div class="policy-grid">
92
- <div class="policy-list" id="policy-list"></div>
93
- <div class="policy-editor">
94
- <div class="policy-form">
95
- <label>
96
- Policy ID
97
- <input id="policy-id" placeholder="policy-id" />
98
- </label>
99
- <label>
100
- Policy 内容
101
- <textarea id="policy-content" rows="8" placeholder="permit(principal, action, resource) when { ... }"></textarea>
102
- </label>
103
- <div class="policy-actions">
104
- <button id="policy-create" class="btn primary">新增</button>
105
- <button id="policy-update" class="btn">保存</button>
106
- <button id="policy-delete" class="btn warn">删除</button>
107
- </div>
108
- <div id="policy-status" class="note"></div>
109
- </div>
110
- </div>
111
- </div>
112
- </section>
113
121
  </div>
114
122
 
115
123
  <script type="module" src="/plugins/clawclamp/assets/app.js"></script>
package/assets/styles.css CHANGED
@@ -84,6 +84,33 @@ h1 {
84
84
  box-shadow: var(--shadow);
85
85
  }
86
86
 
87
+ .policy-shell {
88
+ margin-bottom: 16px;
89
+ background:
90
+ linear-gradient(135deg, rgba(0, 163, 255, 0.1), rgba(124, 140, 255, 0.06)),
91
+ var(--panel);
92
+ border-color: #b9d7ea;
93
+ }
94
+
95
+ .policy-head {
96
+ display: flex;
97
+ justify-content: space-between;
98
+ align-items: flex-start;
99
+ gap: 12px;
100
+ margin-bottom: 12px;
101
+ }
102
+
103
+ .policy-badge {
104
+ padding: 6px 10px;
105
+ border: 1px solid #a7d7ff;
106
+ border-radius: 999px;
107
+ font-size: 0.72rem;
108
+ letter-spacing: 0.08em;
109
+ text-transform: uppercase;
110
+ color: #03527d;
111
+ background: rgba(255, 255, 255, 0.8);
112
+ }
113
+
87
114
  h2 {
88
115
  margin: 0 0 8px;
89
116
  font-size: 1rem;
@@ -280,40 +307,58 @@ select {
280
307
 
281
308
  .policy-grid {
282
309
  display: grid;
283
- grid-template-columns: 220px 1fr;
310
+ grid-template-columns: 260px 1fr;
284
311
  gap: 12px;
285
312
  margin-top: 10px;
286
313
  }
287
314
 
315
+ .policy-list-wrap {
316
+ display: grid;
317
+ gap: 8px;
318
+ }
319
+
288
320
  .policy-list {
289
321
  display: grid;
290
322
  gap: 6px;
291
323
  align-content: start;
292
- max-height: 360px;
324
+ max-height: 420px;
293
325
  overflow: auto;
294
- padding-right: 4px;
326
+ padding: 8px;
327
+ border: 1px solid var(--border);
328
+ border-radius: 10px;
329
+ background: rgba(255, 255, 255, 0.7);
330
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
295
331
  }
296
332
 
297
333
  .policy-item {
298
- padding: 6px 8px;
299
- border-radius: 6px;
300
- border: 1px solid var(--border);
301
- background: #f7f8fb;
334
+ padding: 8px 10px;
335
+ border-radius: 8px;
336
+ border: 1px solid #d6e3f0;
337
+ background: linear-gradient(180deg, #ffffff, #f5f9fd);
302
338
  font-family: var(--mono);
303
339
  font-size: 0.75rem;
304
340
  text-align: left;
305
341
  cursor: pointer;
342
+ transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
343
+ }
344
+
345
+ .policy-item:hover {
346
+ transform: translateY(-1px);
347
+ border-color: #8ecdf6;
348
+ background: linear-gradient(180deg, #ffffff, #eef8ff);
306
349
  }
307
350
 
308
351
  .policy-editor {
309
- display: grid;
310
- grid-template-columns: 1fr 1fr;
311
- gap: 12px;
352
+ display: block;
312
353
  }
313
354
 
314
355
  .policy-form {
315
356
  display: grid;
316
- gap: 8px;
357
+ gap: 10px;
358
+ padding: 12px;
359
+ border: 1px solid #d6e3f0;
360
+ border-radius: 12px;
361
+ background: rgba(255, 255, 255, 0.86);
317
362
  }
318
363
 
319
364
  .policy-form label {
@@ -329,8 +374,9 @@ select {
329
374
  padding: 8px 10px;
330
375
  font-size: 0.8rem;
331
376
  font-family: var(--mono);
332
- min-height: 160px;
377
+ min-height: 260px;
333
378
  resize: vertical;
379
+ background: #fbfdff;
334
380
  }
335
381
 
336
382
  .policy-actions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawclamp",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "OpenClaw Cedar authorization guard with audit UI",
5
5
  "type": "module",
6
6
  "dependencies": {
package/src/guard.ts CHANGED
@@ -106,6 +106,7 @@ function parseCedarDecision(raw: unknown): CedarEvaluation {
106
106
  }
107
107
 
108
108
  async function evaluateCedar(params: {
109
+ api: OpenClawPluginApi;
109
110
  cedarling: CedarlingInstance;
110
111
  config: ClawClampConfig;
111
112
  toolName: string;
@@ -133,10 +134,16 @@ async function evaluateCedar(params: {
133
134
  risk: params.risk,
134
135
  },
135
136
  };
137
+ params.api.logger.info(
138
+ `[clawclamp] cedar request ${JSON.stringify(request)}`,
139
+ );
136
140
 
137
141
  try {
138
142
  const result = await params.cedarling.authorize_unsigned(request);
139
143
  const jsonString = result.json_string();
144
+ params.api.logger.info(
145
+ `[clawclamp] cedar response ${JSON.stringify({ request, result: jsonString })}`,
146
+ );
140
147
  const parsed = JSON.parse(jsonString) as unknown;
141
148
  return parseCedarDecision(parsed);
142
149
  } catch (error) {
@@ -172,6 +179,7 @@ export class ClawClampService {
172
179
  try {
173
180
  const cedarling = await this.getCedarlingInstance();
174
181
  cedarDecision = await evaluateCedar({
182
+ api: this.api,
175
183
  cedarling,
176
184
  config: this.config,
177
185
  toolName,
package/src/http.ts CHANGED
@@ -402,6 +402,9 @@ export function createClawClampHttpHandler(params: {
402
402
  ttlSeconds,
403
403
  note,
404
404
  });
405
+ if (params.onPolicyUpdate) {
406
+ await params.onPolicyUpdate();
407
+ }
405
408
  sendJson(res, 200, { grant });
406
409
  return true;
407
410
  } catch (error) {
@@ -417,6 +420,9 @@ export function createClawClampHttpHandler(params: {
417
420
  return true;
418
421
  }
419
422
  const removed = await revokeGrant(params.stateDir, grantId);
423
+ if (params.onPolicyUpdate) {
424
+ await params.onPolicyUpdate();
425
+ }
420
426
  sendJson(res, 200, { ok: removed });
421
427
  return true;
422
428
  }