comisai 1.0.24 → 1.0.25

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 (98) hide show
  1. package/node_modules/@comis/agent/package.json +1 -1
  2. package/node_modules/@comis/channels/package.json +1 -1
  3. package/node_modules/@comis/cli/package.json +1 -1
  4. package/node_modules/@comis/core/dist/bootstrap.js +5 -0
  5. package/node_modules/@comis/core/dist/config/env-layer.d.ts +31 -0
  6. package/node_modules/@comis/core/dist/config/env-layer.js +41 -0
  7. package/node_modules/@comis/core/dist/config/layered.d.ts +9 -0
  8. package/node_modules/@comis/core/dist/config/layered.js +11 -0
  9. package/node_modules/@comis/core/package.json +1 -1
  10. package/node_modules/@comis/daemon/dist/daemon.js +3 -0
  11. package/node_modules/@comis/daemon/package.json +1 -1
  12. package/node_modules/@comis/gateway/package.json +1 -1
  13. package/node_modules/@comis/infra/package.json +1 -1
  14. package/node_modules/@comis/memory/package.json +1 -1
  15. package/node_modules/@comis/scheduler/package.json +1 -1
  16. package/node_modules/@comis/shared/package.json +1 -1
  17. package/node_modules/@comis/skills/package.json +1 -1
  18. package/node_modules/@comis/web/dist/assets/{agent-detail-BG9MGWWj.js → agent-detail-ru-AhppM.js} +270 -270
  19. package/node_modules/@comis/web/dist/assets/agent-editor-hjwRuFVp.js +2173 -0
  20. package/node_modules/@comis/web/dist/assets/{agent-list-LHCJ4rw2.js → agent-list-6Uotjatr.js} +170 -170
  21. package/node_modules/@comis/web/dist/assets/{approvals-q9VH_IKr.js → approvals-C-K6hN2U.js} +13 -13
  22. package/node_modules/@comis/web/dist/assets/billing-view-CxysXH0p.js +375 -0
  23. package/node_modules/@comis/web/dist/assets/{channel-detail-CaInesJM.js → channel-detail-BBCKtmne.js} +265 -265
  24. package/node_modules/@comis/web/dist/assets/channel-list-FkfeOLBQ.js +323 -0
  25. package/node_modules/@comis/web/dist/assets/{chat-console-CNmzl0JW.js → chat-console-BumBaIgO.js} +243 -246
  26. package/node_modules/@comis/web/dist/assets/{config-editor-DX4ITw6y.js → config-editor-C9BSwHGy.js} +477 -477
  27. package/node_modules/@comis/web/dist/assets/{context-dag-browser-BwiaF5tf.js → context-dag-browser-BHm00mJD.js} +105 -105
  28. package/node_modules/@comis/web/dist/assets/{context-engine-BZ5Am6hA.js → context-engine-BENY3pWE.js} +136 -136
  29. package/node_modules/@comis/web/dist/assets/decorate-BvWYovGE.js +38 -0
  30. package/node_modules/@comis/web/dist/assets/{delivery-view-OfBZof-m.js → delivery-view-BCnkPsAp.js} +134 -134
  31. package/node_modules/@comis/web/dist/assets/{diagnostics-view-YFwCxgr2.js → diagnostics-view-C_jQFG2H.js} +82 -82
  32. package/node_modules/@comis/web/dist/assets/directive-BOYXJ-K-.js +1 -0
  33. package/node_modules/@comis/web/dist/assets/{extract-variables-BM5qyK-s.js → extract-variables-B7-Doo7l.js} +39 -39
  34. package/node_modules/@comis/web/dist/assets/{ic-array-editor-B7m6x7-S.js → ic-array-editor-BLoEyeLS.js} +29 -29
  35. package/node_modules/@comis/web/dist/assets/{ic-breadcrumb-CUMpp3BL.js → ic-breadcrumb-DqN6G3gc.js} +16 -16
  36. package/node_modules/@comis/web/dist/assets/{ic-budget-segment-bar-BtJ6x5mN.js → ic-budget-segment-bar-zLsMzjDO.js} +20 -20
  37. package/node_modules/@comis/web/dist/assets/ic-chat-message-FdQcZsSQ.js +352 -0
  38. package/node_modules/@comis/web/dist/assets/{ic-confirm-dialog-CCDbB04e.js → ic-confirm-dialog-DGlPbV1T.js} +26 -26
  39. package/node_modules/@comis/web/dist/assets/{ic-connection-dot-CnT1b8xr.js → ic-connection-dot-BgYiK2N4.js} +13 -13
  40. package/node_modules/@comis/web/dist/assets/ic-data-table-CKIvr-ag.js +277 -0
  41. package/node_modules/@comis/web/dist/assets/ic-delivery-row-B3YwjjuM.js +67 -0
  42. package/node_modules/@comis/web/dist/assets/{ic-detail-panel-BF83r-if.js → ic-detail-panel-DiCe4hLr.js} +27 -27
  43. package/node_modules/@comis/web/dist/assets/{ic-empty-state-60l2ePhd.js → ic-empty-state-CM3Wbj2f.js} +19 -19
  44. package/node_modules/@comis/web/dist/assets/ic-graph-canvas-ByRjij68.js +359 -0
  45. package/node_modules/@comis/web/dist/assets/ic-icon-BGNCCPpZ.js +33 -0
  46. package/node_modules/@comis/web/dist/assets/{ic-layer-waterfall-COvEYMg5.js → ic-layer-waterfall-WkaFyu-l.js} +18 -18
  47. package/node_modules/@comis/web/dist/assets/ic-relative-time-B3UAnTqg.js +12 -0
  48. package/node_modules/@comis/web/dist/assets/{ic-search-input-CSOxY9g7.js → ic-search-input-B02AGw1i.js} +22 -22
  49. package/node_modules/@comis/web/dist/assets/{ic-select-Ce-Raudx.js → ic-select-BqfZISjw.js} +29 -29
  50. package/node_modules/@comis/web/dist/assets/ic-tabs-yBjkWKJH.js +95 -0
  51. package/node_modules/@comis/web/dist/assets/ic-tag-CvMVQFRR.js +33 -0
  52. package/node_modules/@comis/web/dist/assets/{ic-time-range-picker-CypCT68y.js → ic-time-range-picker-DXbYeBmY.js} +31 -31
  53. package/node_modules/@comis/web/dist/assets/{ic-tool-call-7MaXSsCW.js → ic-tool-call-DMPHsLyx.js} +51 -51
  54. package/node_modules/@comis/web/dist/assets/index-CVEaS9aY.css +2 -0
  55. package/node_modules/@comis/web/dist/assets/index-FLPhHz8p.js +2792 -0
  56. package/node_modules/@comis/web/dist/assets/{mcp-management-BNZPnpDn.js → mcp-management-5jyScQis.js} +209 -209
  57. package/node_modules/@comis/web/dist/assets/{media-config-BBvTYxOX.js → media-config-J9oT9PPs.js} +154 -154
  58. package/node_modules/@comis/web/dist/assets/{media-test-BkK3RCRK.js → media-test-DGTCtM8-.js} +259 -259
  59. package/node_modules/@comis/web/dist/assets/{memory-inspector-1hDGCGat.js → memory-inspector-D5Re9ptG.js} +450 -450
  60. package/node_modules/@comis/web/dist/assets/{message-center-CXefwsUu.js → message-center-cRLK6ZmG.js} +290 -290
  61. package/node_modules/@comis/web/dist/assets/{models-C1qcU_j3.js → models-D5vu07MR.js} +371 -371
  62. package/node_modules/@comis/web/dist/assets/observability-types-D0tkwElU.js +1 -0
  63. package/node_modules/@comis/web/dist/assets/{observe-view-C0VBhX4C.js → observe-view-CalNNEmd.js} +399 -399
  64. package/node_modules/@comis/web/dist/assets/pipeline-builder-DUYDGwZf.js +1495 -0
  65. package/node_modules/@comis/web/dist/assets/{pipeline-history-DkfOQ6SW.js → pipeline-history-BAO8brOe.js} +124 -124
  66. package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-hyHgD0ai.js → pipeline-history-detail-DectIoQt.js} +65 -65
  67. package/node_modules/@comis/web/dist/assets/{pipeline-list-BPW8hV-q.js → pipeline-list-BHlaBKww.js} +227 -227
  68. package/node_modules/@comis/web/dist/assets/{pipeline-monitor-Bip16T7e.js → pipeline-monitor-BhtpNEHf.js} +298 -298
  69. package/node_modules/@comis/web/dist/assets/{scheduler-BGgwKd06.js → scheduler-VafN_8xi.js} +486 -486
  70. package/node_modules/@comis/web/dist/assets/{security-D15st4xx.js → security-QQXMRTlo.js} +389 -389
  71. package/node_modules/@comis/web/dist/assets/{session-detail-SGEYNJ0M.js → session-detail-BpZ_8Yih.js} +294 -294
  72. package/node_modules/@comis/web/dist/assets/session-key-parser-Dkqcj2Ss.js +1 -0
  73. package/node_modules/@comis/web/dist/assets/session-list-DfCm8Cec.js +231 -0
  74. package/node_modules/@comis/web/dist/assets/{setup-wizard-nT0tz9QP.js → setup-wizard-C-z477CG.js} +486 -494
  75. package/node_modules/@comis/web/dist/assets/{skills-D8yVfSUy.js → skills-BCOGPf6s.js} +329 -329
  76. package/node_modules/@comis/web/dist/assets/{subagents-HHXMeHYo.js → subagents-l-auUraL.js} +74 -74
  77. package/node_modules/@comis/web/dist/assets/{workspace-manager-BQlr10iH.js → workspace-manager-DlvBixiq.js} +236 -236
  78. package/node_modules/@comis/web/dist/index.html +3 -2
  79. package/node_modules/@comis/web/package.json +1 -1
  80. package/package.json +15 -15
  81. package/node_modules/@comis/web/dist/assets/agent-editor-C26Q_xCs.js +0 -2173
  82. package/node_modules/@comis/web/dist/assets/billing-view-CtYvBqTE.js +0 -375
  83. package/node_modules/@comis/web/dist/assets/channel-list-B8dj3O9a.js +0 -323
  84. package/node_modules/@comis/web/dist/assets/directive-DoeGSK_T.js +0 -1
  85. package/node_modules/@comis/web/dist/assets/ic-chat-message-CFyDJd0z.js +0 -352
  86. package/node_modules/@comis/web/dist/assets/ic-data-table-CKUNTxHw.js +0 -277
  87. package/node_modules/@comis/web/dist/assets/ic-delivery-row-GP5Fkygs.js +0 -67
  88. package/node_modules/@comis/web/dist/assets/ic-graph-canvas-C8FuSMe1.js +0 -359
  89. package/node_modules/@comis/web/dist/assets/ic-icon-xeGTVhVG.js +0 -33
  90. package/node_modules/@comis/web/dist/assets/ic-relative-time-3FqpjeAI.js +0 -12
  91. package/node_modules/@comis/web/dist/assets/ic-tabs-B7QtM_v8.js +0 -95
  92. package/node_modules/@comis/web/dist/assets/ic-tag-CPPUnDLF.js +0 -33
  93. package/node_modules/@comis/web/dist/assets/index-CEcM1R_C.js +0 -2830
  94. package/node_modules/@comis/web/dist/assets/index-CIJFuItj.css +0 -1
  95. package/node_modules/@comis/web/dist/assets/observability-types-D7jUtSde.js +0 -1
  96. package/node_modules/@comis/web/dist/assets/pipeline-builder-DcUUIrm0.js +0 -1496
  97. package/node_modules/@comis/web/dist/assets/session-key-parser-DPORMVyU.js +0 -1
  98. package/node_modules/@comis/web/dist/assets/session-list-6ybUTxbY.js +0 -231
@@ -1,24 +1,4 @@
1
- import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S as B}from"./index-CEcM1R_C.js";import"./ic-tabs-B7QtM_v8.js";import"./ic-empty-state-60l2ePhd.js";import"./ic-tag-CPPUnDLF.js";import"./ic-relative-time-3FqpjeAI.js";import"./ic-connection-dot-CnT1b8xr.js";import"./ic-select-Ce-Raudx.js";import"./ic-array-editor-B7m6x7-S.js";import"./ic-icon-xeGTVhVG.js";var j=Object.defineProperty,F=Object.getOwnPropertyDescriptor,T=(e,t,i,a)=>{for(var r=a>1?void 0:a?F(t,i):t,o=e.length-1,c;o>=0;o--)(c=e[o])&&(r=(a?c(t,i,r):c(r))||r);return a&&r&&j(t,i,r),r};let g=class extends x{constructor(){super(...arguments),this.label="",this.value="",this.placeholder="env:SECRET_NAME or file:/path",this.disabled=!1,this._visible=!1}_onInput(e){const t=e.target.value;this.dispatchEvent(new CustomEvent("change",{detail:t,bubbles:!0,composed:!0}))}_toggleVisibility(){this._visible=!this._visible}render(){return s`
2
- <div class="field-wrapper">
3
- ${this.label?s`<label>${this.label}</label>`:p}
4
- <div class="input-row">
5
- <input
6
- type=${this._visible?"text":"password"}
7
- .value=${this.value}
8
- placeholder=${this.placeholder}
9
- ?disabled=${this.disabled}
10
- @input=${this._onInput}
11
- />
12
- <button
13
- class="toggle-btn"
14
- type="button"
15
- aria-label=${this._visible?"Hide value":"Show value"}
16
- @click=${this._toggleVisibility}
17
- >${this._visible?"🙈":"👁"}</button>
18
- </div>
19
- <span class="hint">Format: env:VAR_NAME or file:/path/to/secret</span>
20
- </div>
21
- `}};g.styles=[_,S,w`
1
+ import{c as e,f as t,h as n,l as r,n as i,o as a,r as o,s,t as c,u as l}from"./decorate-BvWYovGE.js";import{a as u,i as d}from"./index-FLPhHz8p.js";import"./ic-tag-CvMVQFRR.js";import"./ic-relative-time-B3UAnTqg.js";import"./ic-array-editor-BLoEyeLS.js";import"./ic-empty-state-CM3Wbj2f.js";import"./ic-tabs-yBjkWKJH.js";import"./ic-connection-dot-BgYiK2N4.js";import"./ic-select-BqfZISjw.js";var f=class extends r{constructor(...e){super(...e),this.label=``,this.value=``,this.placeholder=`env:SECRET_NAME or file:/path`,this.disabled=!1,this._visible=!1}static{this.styles=[o,i,n`
22
2
  :host {
23
3
  display: block;
24
4
  }
@@ -88,71 +68,27 @@ import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S a
88
68
  color: var(--ic-text-dim);
89
69
  font-style: italic;
90
70
  }
91
- `];T([d()],g.prototype,"label",2);T([d()],g.prototype,"value",2);T([d()],g.prototype,"placeholder",2);T([d({type:Boolean})],g.prototype,"disabled",2);T([l()],g.prototype,"_visible",2);g=T([$("ic-secret-input")],g);var L=Object.defineProperty,G=Object.getOwnPropertyDescriptor,R=(e,t,i,a)=>{for(var r=a>1?void 0:a?G(t,i):t,o=e.length-1,c;o>=0;o--)(c=e[o])&&(r=(a?c(t,i,r):c(r))||r);return a&&r&&L(t,i,r),r};let y=class extends x{constructor(){super(...arguments),this._tokens=[],this._newTokenScopes=[],this._newSecretDisplay=null}connectedCallback(){super.connectedCallback()}updated(e){e.has("rpc")&&this.rpc&&this._loadTokens()}async _loadTokens(){if(this.rpc)try{const e=await this.rpc.call("tokens.list");this._tokens=e.tokens??[]}catch{}}async _revokeToken(e){if(this.rpc)try{await this.rpc.call("tokens.revoke",{id:e}),this._tokens=this._tokens.filter(t=>t.id!==e),n.show(`Token "${e}" revoked`,"success"),this.dispatchEvent(new CustomEvent("tokens-changed",{bubbles:!0,composed:!0}))}catch(t){const i=t instanceof Error?t.message:"Failed to revoke token";n.show(i,"error")}}async _rotateToken(e){if(this.rpc)try{const t=await this.rpc.call("tokens.rotate",{id:e});this._newSecretDisplay=t.secret,n.show(`Token "${e}" rotated -- new secret shown below`,"success"),this.dispatchEvent(new CustomEvent("tokens-changed",{bubbles:!0,composed:!0}))}catch(t){const i=t instanceof Error?t.message:"Failed to rotate token";n.show(i,"error")}}_onScopeToggle(e,t){t?this._newTokenScopes=[...this._newTokenScopes,e]:this._newTokenScopes=this._newTokenScopes.filter(i=>i!==e)}async _generateToken(){if(this.rpc)try{const e=await this.rpc.call("tokens.create",{scopes:[...this._newTokenScopes]});this._tokens=[...this._tokens,{id:e.id,scopes:e.scopes}],this._newSecretDisplay=e.secret,this._newTokenScopes=[],n.show("Token created -- secret shown below","success"),this.dispatchEvent(new CustomEvent("tokens-changed",{bubbles:!0,composed:!0}))}catch(e){const t=e instanceof Error?e.message:"Failed to create token";n.show(t,"error")}}_renderTokenRow(e){return s`
92
- <div class="data-cell" role="cell">${e.id}</div>
93
- <div class="data-cell scopes-cell" role="cell">
94
- ${e.scopes.map(t=>s`<ic-tag variant="info">${t}</ic-tag>`)}
95
- </div>
96
- <div class="data-cell" role="cell">
97
- <div class="token-actions">
98
- <button class="rotate-btn" @click=${()=>this._rotateToken(e.id)}>Rotate</button>
99
- <button class="revoke-btn" @click=${()=>this._revokeToken(e.id)}>Revoke</button>
100
- </div>
101
- </div>
102
- `}render(){return s`
103
- <div class="grid-table grid-table--tokens" role="table" aria-label="API tokens">
104
- <div class="header-cell" role="columnheader">Token ID</div>
105
- <div class="header-cell" role="columnheader">Scopes</div>
106
- <div class="header-cell" role="columnheader">Actions</div>
107
- ${this._tokens.map(e=>this._renderTokenRow(e))}
108
- </div>
109
-
110
- ${this._newSecretDisplay?s`
111
- <div class="new-secret-banner">
112
- <div class="secret-label">New Token Secret</div>
113
- <div class="secret-value">${this._newSecretDisplay}</div>
114
- <div class="secret-warning">Copy this secret now. It will not be shown again.</div>
115
- </div>
116
- `:p}
117
-
118
- <div class="create-form">
119
- <div class="create-form-title">Create Token</div>
120
- <div class="form-field">
121
- <label class="form-label">Scopes</label>
122
- <div class="checkbox-row">
123
- <input type="checkbox" id="scope-rpc"
124
- .checked=${this._newTokenScopes.includes("rpc")}
125
- @change=${e=>this._onScopeToggle("rpc",e.target.checked)}
126
- /><label for="scope-rpc">rpc</label>
127
- </div>
128
- <div class="checkbox-row">
129
- <input type="checkbox" id="scope-ws"
130
- .checked=${this._newTokenScopes.includes("ws")}
131
- @change=${e=>this._onScopeToggle("ws",e.target.checked)}
132
- /><label for="scope-ws">ws</label>
133
- </div>
134
- <div class="checkbox-row">
135
- <input type="checkbox" id="scope-admin"
136
- .checked=${this._newTokenScopes.includes("admin")}
137
- @change=${e=>this._onScopeToggle("admin",e.target.checked)}
138
- /><label for="scope-admin">admin</label>
139
- </div>
140
- <div class="checkbox-row">
141
- <input type="checkbox" id="scope-api"
142
- .checked=${this._newTokenScopes.includes("api")}
143
- @change=${e=>this._onScopeToggle("api",e.target.checked)}
144
- /><label for="scope-api">api</label>
145
- </div>
146
- <div class="checkbox-row">
147
- <input type="checkbox" id="scope-all"
148
- .checked=${this._newTokenScopes.includes("*")}
149
- @change=${e=>this._onScopeToggle("*",e.target.checked)}
150
- /><label for="scope-all">* (all)</label>
151
- </div>
71
+ `]}_onInput(e){let t=e.target.value;this.dispatchEvent(new CustomEvent(`change`,{detail:t,bubbles:!0,composed:!0}))}_toggleVisibility(){this._visible=!this._visible}render(){return t`
72
+ <div class="field-wrapper">
73
+ ${this.label?t`<label>${this.label}</label>`:l}
74
+ <div class="input-row">
75
+ <input
76
+ type=${this._visible?`text`:`password`}
77
+ .value=${this.value}
78
+ placeholder=${this.placeholder}
79
+ ?disabled=${this.disabled}
80
+ @input=${this._onInput}
81
+ />
82
+ <button
83
+ class="toggle-btn"
84
+ type="button"
85
+ aria-label=${this._visible?`Hide value`:`Show value`}
86
+ @click=${this._toggleVisibility}
87
+ >${this._visible?`🙈`:`👁`}</button>
152
88
  </div>
153
- <button class="generate-btn" @click=${()=>this._generateToken()}>Generate</button>
89
+ <span class="hint">Format: env:VAR_NAME or file:/path/to/secret</span>
154
90
  </div>
155
- `}};y.styles=[_,S,w`
91
+ `}};c([s()],f.prototype,`label`,void 0),c([s()],f.prototype,`value`,void 0),c([s()],f.prototype,`placeholder`,void 0),c([s({type:Boolean})],f.prototype,`disabled`,void 0),c([a()],f.prototype,`_visible`,void 0),f=c([e(`ic-secret-input`)],f);var p=class extends r{constructor(...e){super(...e),this._tokens=[],this._newTokenScopes=[],this._newSecretDisplay=null}static{this.styles=[o,i,n`
156
92
  :host {
157
93
  display: block;
158
94
  }
@@ -317,41 +253,71 @@ import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S a
317
253
  color: var(--ic-text-dim);
318
254
  margin-top: var(--ic-space-xs);
319
255
  }
320
- `];R([d({attribute:!1})],y.prototype,"rpc",2);R([l()],y.prototype,"_tokens",2);R([l()],y.prototype,"_newTokenScopes",2);R([l()],y.prototype,"_newSecretDisplay",2);y=R([$("ic-token-manager")],y);var V=Object.defineProperty,K=Object.getOwnPropertyDescriptor,I=(e,t,i,a)=>{for(var r=a>1?void 0:a?K(t,i):t,o=e.length-1,c;o>=0;o--)(c=e[o])&&(r=(a?c(t,i,r):c(r))||r);return a&&r&&V(t,i,r),r};const U={low:"success",medium:"warning",high:"error",critical:"error"},J={low:"var(--ic-success)",medium:"var(--ic-warning)",high:"var(--ic-error)",critical:"var(--ic-error)"};let C=class extends x{constructor(){super(...arguments),this.approval=null,this._reason="",this._expanded=!1}_onApprove(){this.approval&&this.dispatchEvent(new CustomEvent("approve",{detail:{id:this.approval.id,reason:this._reason},bubbles:!0,composed:!0}))}_onDeny(){this.approval&&this.dispatchEvent(new CustomEvent("deny",{detail:{id:this.approval.id,reason:this._reason},bubbles:!0,composed:!0}))}render(){if(!this.approval)return p;const e=this.approval,t=U[e.classification]??"default",i=J[e.classification]??"var(--ic-border)";return s`
321
- <div
322
- class="card"
323
- role="article"
324
- aria-label="${e.agentId} ${e.action} approval request"
325
- style="border-left-color: ${i};"
326
- >
327
- <div class="card-header">
328
- <span class="agent-id">${e.agentId}</span>
329
- <span class="action-name">${e.action}</span>
330
- <ic-tag variant=${t}>${e.classification}</ic-tag>
331
- </div>
332
- <div class="timestamp">
333
- <ic-relative-time .timestamp=${e.requestedAt}></ic-relative-time>
256
+ `]}connectedCallback(){super.connectedCallback()}updated(e){e.has(`rpc`)&&this.rpc&&this._loadTokens()}async _loadTokens(){if(this.rpc)try{let e=await this.rpc.call(`tokens.list`);this._tokens=e.tokens??[]}catch{}}async _revokeToken(e){if(this.rpc)try{await this.rpc.call(`tokens.revoke`,{id:e}),this._tokens=this._tokens.filter(t=>t.id!==e),u.show(`Token "${e}" revoked`,`success`),this.dispatchEvent(new CustomEvent(`tokens-changed`,{bubbles:!0,composed:!0}))}catch(e){let t=e instanceof Error?e.message:`Failed to revoke token`;u.show(t,`error`)}}async _rotateToken(e){if(this.rpc)try{let t=await this.rpc.call(`tokens.rotate`,{id:e});this._newSecretDisplay=t.secret,u.show(`Token "${e}" rotated -- new secret shown below`,`success`),this.dispatchEvent(new CustomEvent(`tokens-changed`,{bubbles:!0,composed:!0}))}catch(e){let t=e instanceof Error?e.message:`Failed to rotate token`;u.show(t,`error`)}}_onScopeToggle(e,t){t?this._newTokenScopes=[...this._newTokenScopes,e]:this._newTokenScopes=this._newTokenScopes.filter(t=>t!==e)}async _generateToken(){if(this.rpc)try{let e=await this.rpc.call(`tokens.create`,{scopes:[...this._newTokenScopes]});this._tokens=[...this._tokens,{id:e.id,scopes:e.scopes}],this._newSecretDisplay=e.secret,this._newTokenScopes=[],u.show(`Token created -- secret shown below`,`success`),this.dispatchEvent(new CustomEvent(`tokens-changed`,{bubbles:!0,composed:!0}))}catch(e){let t=e instanceof Error?e.message:`Failed to create token`;u.show(t,`error`)}}_renderTokenRow(e){return t`
257
+ <div class="data-cell" role="cell">${e.id}</div>
258
+ <div class="data-cell scopes-cell" role="cell">
259
+ ${e.scopes.map(e=>t`<ic-tag variant="info">${e}</ic-tag>`)}
260
+ </div>
261
+ <div class="data-cell" role="cell">
262
+ <div class="token-actions">
263
+ <button class="rotate-btn" @click=${()=>this._rotateToken(e.id)}>Rotate</button>
264
+ <button class="revoke-btn" @click=${()=>this._revokeToken(e.id)}>Revoke</button>
334
265
  </div>
335
- ${e.user?s`<div class="user-row"><span class="user-label">Requested by:</span> ${e.user}</div>`:p}
336
- <button
337
- class="context-toggle"
338
- @click=${()=>{this._expanded=!this._expanded}}
339
- >${this._expanded?"Hide details":"Show details"}</button>
340
- ${this._expanded?s`<div class="context-details">${e.context}</div>`:p}
341
- <input
342
- class="reason-input"
343
- type="text"
344
- placeholder="Reason (optional)"
345
- aria-label="Decision reason"
346
- .value=${this._reason}
347
- @input=${a=>{this._reason=a.target.value}}
348
- />
349
- <div class="action-buttons">
350
- <button class="approve-btn" @click=${()=>this._onApprove()}>Approve</button>
351
- <button class="deny-btn" @click=${()=>this._onDeny()}>Deny</button>
266
+ </div>
267
+ `}render(){return t`
268
+ <div class="grid-table grid-table--tokens" role="table" aria-label="API tokens">
269
+ <div class="header-cell" role="columnheader">Token ID</div>
270
+ <div class="header-cell" role="columnheader">Scopes</div>
271
+ <div class="header-cell" role="columnheader">Actions</div>
272
+ ${this._tokens.map(e=>this._renderTokenRow(e))}
273
+ </div>
274
+
275
+ ${this._newSecretDisplay?t`
276
+ <div class="new-secret-banner">
277
+ <div class="secret-label">New Token Secret</div>
278
+ <div class="secret-value">${this._newSecretDisplay}</div>
279
+ <div class="secret-warning">Copy this secret now. It will not be shown again.</div>
280
+ </div>
281
+ `:l}
282
+
283
+ <div class="create-form">
284
+ <div class="create-form-title">Create Token</div>
285
+ <div class="form-field">
286
+ <label class="form-label">Scopes</label>
287
+ <div class="checkbox-row">
288
+ <input type="checkbox" id="scope-rpc"
289
+ .checked=${this._newTokenScopes.includes(`rpc`)}
290
+ @change=${e=>this._onScopeToggle(`rpc`,e.target.checked)}
291
+ /><label for="scope-rpc">rpc</label>
292
+ </div>
293
+ <div class="checkbox-row">
294
+ <input type="checkbox" id="scope-ws"
295
+ .checked=${this._newTokenScopes.includes(`ws`)}
296
+ @change=${e=>this._onScopeToggle(`ws`,e.target.checked)}
297
+ /><label for="scope-ws">ws</label>
298
+ </div>
299
+ <div class="checkbox-row">
300
+ <input type="checkbox" id="scope-admin"
301
+ .checked=${this._newTokenScopes.includes(`admin`)}
302
+ @change=${e=>this._onScopeToggle(`admin`,e.target.checked)}
303
+ /><label for="scope-admin">admin</label>
304
+ </div>
305
+ <div class="checkbox-row">
306
+ <input type="checkbox" id="scope-api"
307
+ .checked=${this._newTokenScopes.includes(`api`)}
308
+ @change=${e=>this._onScopeToggle(`api`,e.target.checked)}
309
+ /><label for="scope-api">api</label>
310
+ </div>
311
+ <div class="checkbox-row">
312
+ <input type="checkbox" id="scope-all"
313
+ .checked=${this._newTokenScopes.includes(`*`)}
314
+ @change=${e=>this._onScopeToggle(`*`,e.target.checked)}
315
+ /><label for="scope-all">* (all)</label>
316
+ </div>
352
317
  </div>
318
+ <button class="generate-btn" @click=${()=>this._generateToken()}>Generate</button>
353
319
  </div>
354
- `}};C.styles=[_,S,w`
320
+ `}};c([s({attribute:!1})],p.prototype,`rpc`,void 0),c([a()],p.prototype,`_tokens`,void 0),c([a()],p.prototype,`_newTokenScopes`,void 0),c([a()],p.prototype,`_newSecretDisplay`,void 0),p=c([e(`ic-token-manager`)],p);var m={low:`success`,medium:`warning`,high:`error`,critical:`error`},h={low:`var(--ic-success)`,medium:`var(--ic-warning)`,high:`var(--ic-error)`,critical:`var(--ic-error)`},g=class extends r{constructor(...e){super(...e),this.approval=null,this._reason=``,this._expanded=!1}static{this.styles=[o,i,n`
355
321
  :host {
356
322
  display: block;
357
323
  width: 100%;
@@ -483,119 +449,41 @@ import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S a
483
449
  .deny-btn:hover {
484
450
  background: color-mix(in srgb, var(--ic-error) 25%, transparent);
485
451
  }
486
- `];I([d({type:Object})],C.prototype,"approval",2);I([l()],C.prototype,"_reason",2);I([l()],C.prototype,"_expanded",2);C=I([$("ic-approval-card")],C);var Q=Object.defineProperty,Y=Object.getOwnPropertyDescriptor,k=(e,t,i,a)=>{for(var r=a>1?void 0:a?Y(t,i):t,o=e.length-1,c;o>=0;o--)(c=e[o])&&(r=(a?c(t,i,r):c(r))||r);return a&&r&&Q(t,i,r),r};function M(e){return{id:e.requestId,agentId:e.agentId,action:e.action||e.toolName,classification:e.trustLevel==="admin"?"low":e.trustLevel==="user"?"medium":"high",context:JSON.stringify(e.params,null,2),requestedAt:e.createdAt}}const q="ic:approval-history",H=10080*60*1e3;function X(){try{const e=localStorage.getItem(q);if(!e)return[];const t=JSON.parse(e),i=Date.now()-H;return t.filter(a=>a.resolvedAt>i)}catch{return[]}}function P(e){try{const t=Date.now()-H,i=e.filter(a=>a.resolvedAt>t);localStorage.setItem(q,JSON.stringify(i))}catch{}}let m=class extends x{constructor(){super(...arguments),this.securityConfig={},this.activeSubTab="pending",this._pendingApprovals=[],this._resolvedApprovals=[],this._approvalRules={defaultMode:"manual",timeoutMs:0}}connectedCallback(){super.connectedCallback(),this._resolvedApprovals=X()}updated(e){e.has("rpc")&&this.rpc&&this._loadApprovals(),e.has("securityConfig")&&(this._approvalRules=this.securityConfig.approvalRules??{defaultMode:"manual",timeoutMs:0})}async _loadApprovals(){if(this.rpc)try{const e=await this.rpc.call("admin.approval.pending");this._pendingApprovals=(e.requests??[]).map(M)}catch{}}onApprovalPending(e){const t=e;t?.requestId&&(this._pendingApprovals=[M(t),...this._pendingApprovals])}onApprovalResolved(e){const t=e,i=t?.requestId;if(!i)return;this._pendingApprovals=this._pendingApprovals.filter(o=>o.id!==i);const r={...M(t),outcome:t.approved?"approved":"denied",reason:t.reason??"",resolvedAt:t.resolvedAt??Date.now(),resolvedBy:t.approvedBy??"system"};this._resolvedApprovals=[r,...this._resolvedApprovals],P(this._resolvedApprovals)}async _handleApprove(e){if(!this.rpc)return;const{id:t,reason:i}=e.detail;try{await this.rpc.call("admin.approval.resolve",{requestId:t,approved:!0,approvedBy:"operator",reason:i});const a=this._pendingApprovals.find(r=>r.id===t);if(this._pendingApprovals=this._pendingApprovals.filter(r=>r.id!==t),a){const r={...a,outcome:"approved",reason:i,resolvedAt:Date.now(),resolvedBy:"operator"};this._resolvedApprovals=[r,...this._resolvedApprovals],P(this._resolvedApprovals)}n.show("Approval granted","success"),this.dispatchEvent(new CustomEvent("approvals-changed",{bubbles:!0,composed:!0}))}catch(a){n.show(a instanceof Error?a.message:"Failed to approve request","error")}}async _handleDeny(e){if(!this.rpc)return;const{id:t,reason:i}=e.detail;try{await this.rpc.call("admin.approval.resolve",{requestId:t,approved:!1,approvedBy:"operator",reason:i});const a=this._pendingApprovals.find(r=>r.id===t);if(this._pendingApprovals=this._pendingApprovals.filter(r=>r.id!==t),a){const r={...a,outcome:"denied",reason:i,resolvedAt:Date.now(),resolvedBy:"operator"};this._resolvedApprovals=[r,...this._resolvedApprovals],P(this._resolvedApprovals)}n.show("Approval denied","success"),this.dispatchEvent(new CustomEvent("approvals-changed",{bubbles:!0,composed:!0}))}catch(a){n.show(a instanceof Error?a.message:"Failed to deny request","error")}}async _handleResolveAll(e){if(!(!this.rpc||this._pendingApprovals.length===0))try{const t=await this.rpc.call("admin.approval.resolveAll",{approved:e,approvedBy:"operator",reason:e?"Bulk approved by operator":"Bulk denied by operator"});for(const i of this._pendingApprovals){const a={...i,outcome:e?"approved":"denied",reason:e?"Bulk approved by operator":"Bulk denied by operator",resolvedAt:Date.now(),resolvedBy:"operator"};this._resolvedApprovals=[a,...this._resolvedApprovals]}this._pendingApprovals=[],P(this._resolvedApprovals),n.show(`${t.resolved} approval(s) ${e?"approved":"denied"}`,"success"),this.dispatchEvent(new CustomEvent("approvals-changed",{bubbles:!0,composed:!0}))}catch(t){n.show(t instanceof Error?t.message:"Bulk operation failed","error")}}async _handleClearDenialCache(){if(this.rpc)try{await this.rpc.call("admin.approval.clearDenialCache",{}),n.show("Denial cache cleared","success")}catch(e){n.show(e instanceof Error?e.message:"Failed to clear denial cache","error")}}async _patchConfig(e,t){if(!this.rpc)return!1;try{const i=e.indexOf("."),a=i>0?e.slice(0,i):e,r=i>0?e.slice(i+1):void 0;return await this.rpc.call("config.patch",{section:a,key:r,value:t}),n.show("Configuration updated","success"),!0}catch(i){return n.show(i instanceof Error?i.message:"Failed to update configuration","error"),!1}}async _onActionConfirmationChange(e,t){const i={...this.securityConfig.actionConfirmation,[e]:t};await this._patchConfig("security.actionConfirmation",i)}async _onAgentToAgentEnabledChange(e){const t={...this.securityConfig.agentToAgent,enabled:e};await this._patchConfig("security.agentToAgent",t)}async _onAgentToAgentAllowChange(e){const t={...this.securityConfig.agentToAgent,allowAgents:e};await this._patchConfig("security.agentToAgent",t)}async _onPermissionToggleChange(e){const t={...this.securityConfig.permission,enableNodePermissions:e};await this._patchConfig("security.permission",t)}async _onPermissionPathsChange(e,t){const i={...this.securityConfig.permission,[e]:t};await this._patchConfig("security.permission",i)}async _saveApprovalRules(){if(this.rpc)try{await this.rpc.call("config.patch",{section:"security",key:"approvalRules",value:this._approvalRules}),n.show("Approval rules updated","success")}catch(e){n.show(e instanceof Error?e.message:"Failed to update approval rules","error")}}_renderHistoryRow(e){const t=e.outcome==="approved"?"success":"error",i={low:"success",medium:"warning",high:"error",critical:"error"}[e.classification]??"default";return s`
487
- <div class="data-cell" role="cell">${e.agentId}</div>
488
- <div class="data-cell" role="cell">${e.action}</div>
489
- <div class="data-cell" role="cell"><ic-tag variant=${i}>${e.classification}</ic-tag></div>
490
- <div class="data-cell" role="cell"><ic-tag variant=${t}>${e.outcome}</ic-tag></div>
491
- <div class="data-cell data-cell--muted" role="cell">${e.reason||"---"}</div>
492
- <div class="data-cell data-cell--muted" role="cell"><ic-relative-time .timestamp=${e.resolvedAt}></ic-relative-time></div>
493
- <div class="data-cell data-cell--muted" role="cell">${e.resolvedBy}</div>
494
- `}_renderRulesContent(){const e=this.securityConfig.actionConfirmation??{},t=this.securityConfig.agentToAgent??{},i=this.securityConfig.permission??{},a=[{value:"manual",label:"Manual (all require approval)"},{value:"auto-low",label:"Auto-approve low risk"},{value:"auto-medium",label:"Auto-approve low + medium risk"},{value:"auto-all",label:"Auto-approve all (no approvals)"}];return s`
495
- <div class="policy-section">
496
- <div class="section-header">Action Confirmation</div>
497
- <ic-toggle label="Require for destructive actions"
498
- .checked=${e.requireForDestructive??!0}
499
- @change=${r=>this._onActionConfirmationChange("requireForDestructive",r.detail)}
500
- ></ic-toggle>
501
- <div style="margin-top: var(--ic-space-sm);">
502
- <ic-toggle label="Require for sensitive actions"
503
- .checked=${e.requireForSensitive??!1}
504
- @change=${r=>this._onActionConfirmationChange("requireForSensitive",r.detail)}
505
- ></ic-toggle>
506
- </div>
507
- <div style="margin-top: var(--ic-space-md);">
508
- <ic-array-editor label="Auto-approve list" .items=${e.autoApprove??[]} placeholder="Action name to auto-approve"
509
- @change=${r=>this._onActionConfirmationChange("autoApprove",r.detail)}
510
- ></ic-array-editor>
511
- </div>
512
- </div>
513
-
514
- <div class="policy-section">
515
- <div class="section-header">Agent-to-Agent Policy</div>
516
- <ic-toggle label="Enable cross-agent messaging"
517
- .checked=${t.enabled??!0}
518
- @change=${r=>this._onAgentToAgentEnabledChange(r.detail)}
519
- ></ic-toggle>
520
- <div style="margin-top: var(--ic-space-md);">
521
- <ic-array-editor label="Allowed agents" .items=${t.allowAgents??[]} placeholder="Agent ID"
522
- @change=${r=>this._onAgentToAgentAllowChange(r.detail)}
523
- ></ic-array-editor>
524
- </div>
525
- </div>
526
-
527
- <div class="policy-section">
528
- <div class="section-header">Permissions</div>
529
- <ic-toggle label="Enable Node.js permission model"
530
- .checked=${i.enableNodePermissions??!1}
531
- @change=${r=>this._onPermissionToggleChange(r.detail)}
532
- ></ic-toggle>
533
- <div style="margin-top: var(--ic-space-md);">
534
- <ic-array-editor label="Allowed filesystem paths" .items=${i.allowedFsPaths??[]} placeholder="/path/to/allow"
535
- @change=${r=>this._onPermissionPathsChange("allowedFsPaths",r.detail)}
536
- ></ic-array-editor>
452
+ `]}_onApprove(){this.approval&&this.dispatchEvent(new CustomEvent(`approve`,{detail:{id:this.approval.id,reason:this._reason},bubbles:!0,composed:!0}))}_onDeny(){this.approval&&this.dispatchEvent(new CustomEvent(`deny`,{detail:{id:this.approval.id,reason:this._reason},bubbles:!0,composed:!0}))}render(){if(!this.approval)return l;let e=this.approval,n=m[e.classification]??`default`,r=h[e.classification]??`var(--ic-border)`;return t`
453
+ <div
454
+ class="card"
455
+ role="article"
456
+ aria-label="${e.agentId} ${e.action} approval request"
457
+ style="border-left-color: ${r};"
458
+ >
459
+ <div class="card-header">
460
+ <span class="agent-id">${e.agentId}</span>
461
+ <span class="action-name">${e.action}</span>
462
+ <ic-tag variant=${n}>${e.classification}</ic-tag>
537
463
  </div>
538
- <div style="margin-top: var(--ic-space-md);">
539
- <ic-array-editor label="Allowed network hosts" .items=${i.allowedNetHosts??[]} placeholder="hostname or IP"
540
- @change=${r=>this._onPermissionPathsChange("allowedNetHosts",r.detail)}
541
- ></ic-array-editor>
464
+ <div class="timestamp">
465
+ <ic-relative-time .timestamp=${e.requestedAt}></ic-relative-time>
542
466
  </div>
543
- </div>
544
-
545
- <div class="policy-section">
546
- <div class="section-header">Approval Mode</div>
547
- <div class="rules-form">
548
- <ic-select label="Default Mode" .value=${this._approvalRules.defaultMode} .options=${a}
549
- @change=${r=>{this._approvalRules={...this._approvalRules,defaultMode:r.detail}}}
550
- ></ic-select>
551
- <div class="form-field">
552
- <label class="form-label">Timeout (seconds)</label>
553
- <input class="number-input" type="number" min="0"
554
- .value=${String(Math.round(this._approvalRules.timeoutMs/1e3))}
555
- @change=${r=>{const o=parseInt(r.target.value,10);!isNaN(o)&&o>=0&&(this._approvalRules={...this._approvalRules,timeoutMs:o*1e3})}}
556
- />
557
- <span class="form-hint">0 = no timeout (request waits indefinitely)</span>
558
- </div>
559
- <button class="save-btn" @click=${()=>this._saveApprovalRules()}>Save Rules</button>
467
+ ${e.user?t`<div class="user-row"><span class="user-label">Requested by:</span> ${e.user}</div>`:l}
468
+ <button
469
+ class="context-toggle"
470
+ @click=${()=>{this._expanded=!this._expanded}}
471
+ >${this._expanded?`Hide details`:`Show details`}</button>
472
+ ${this._expanded?t`<div class="context-details">${e.context}</div>`:l}
473
+ <input
474
+ class="reason-input"
475
+ type="text"
476
+ placeholder="Reason (optional)"
477
+ aria-label="Decision reason"
478
+ .value=${this._reason}
479
+ @input=${e=>{this._reason=e.target.value}}
480
+ />
481
+ <div class="action-buttons">
482
+ <button class="approve-btn" @click=${()=>this._onApprove()}>Approve</button>
483
+ <button class="deny-btn" @click=${()=>this._onDeny()}>Deny</button>
560
484
  </div>
561
485
  </div>
562
- `}_renderPendingContent(){const e=[...this._pendingApprovals].sort((t,i)=>i.requestedAt-t.requestedAt);return s`
563
- <div class="queue-header">
564
- <span>Pending</span>
565
- <span class="queue-count">${this._pendingApprovals.length}</span>
566
- </div>
567
- <div class="bulk-actions">
568
- <button class="action-btn action-btn--success" ?disabled=${this._pendingApprovals.length===0}
569
- @click=${()=>this._handleResolveAll(!0)}>Approve All (${this._pendingApprovals.length})</button>
570
- <button class="action-btn action-btn--danger" ?disabled=${this._pendingApprovals.length===0}
571
- @click=${()=>this._handleResolveAll(!1)}>Deny All (${this._pendingApprovals.length})</button>
572
- <button class="action-btn" @click=${()=>this._handleClearDenialCache()}>Clear Denial Cache</button>
573
- </div>
574
- ${e.length===0?s`<ic-empty-state icon="security" message="No pending approvals" description="Approval requests will appear here as they arrive."></ic-empty-state>`:s`
575
- <div class="queue-list">
576
- ${e.map(t=>s`
577
- <ic-approval-card .approval=${t}
578
- @approve=${i=>this._handleApprove(i)}
579
- @deny=${i=>this._handleDeny(i)}
580
- ></ic-approval-card>
581
- `)}
582
- </div>
583
- `}
584
-
585
- <div class="history-divider">Recent History</div>
586
- ${this._resolvedApprovals.length===0?s`<p style="font-size: var(--ic-text-sm); color: var(--ic-text-dim); font-style: italic;">No resolved approvals in the last 7 days.</p>`:s`
587
- <div class="history-grid" role="table" aria-label="Resolved approvals">
588
- <div class="header-cell" role="columnheader">Agent</div>
589
- <div class="header-cell" role="columnheader">Action</div>
590
- <div class="header-cell" role="columnheader">Risk</div>
591
- <div class="header-cell" role="columnheader">Outcome</div>
592
- <div class="header-cell" role="columnheader">Reason</div>
593
- <div class="header-cell" role="columnheader">Resolved At</div>
594
- <div class="header-cell" role="columnheader">Resolved By</div>
595
- ${this._resolvedApprovals.map(t=>this._renderHistoryRow(t))}
596
- </div>
597
- `}
598
- `}render(){return this.activeSubTab==="rules"?this._renderRulesContent():this._renderPendingContent()}};m.styles=[_,S,w`
486
+ `}};c([s({type:Object})],g.prototype,`approval`,void 0),c([a()],g.prototype,`_reason`,void 0),c([a()],g.prototype,`_expanded`,void 0),g=c([e(`ic-approval-card`)],g);function _(e){return{id:e.requestId,agentId:e.agentId,action:e.action||e.toolName,classification:e.trustLevel===`admin`?`low`:e.trustLevel===`user`?`medium`:`high`,context:JSON.stringify(e.params,null,2),requestedAt:e.createdAt}}var v=`ic:approval-history`,y=10080*60*1e3;function b(){try{let e=localStorage.getItem(v);if(!e)return[];let t=JSON.parse(e),n=Date.now()-y;return t.filter(e=>e.resolvedAt>n)}catch{return[]}}function x(e){try{let t=Date.now()-y,n=e.filter(e=>e.resolvedAt>t);localStorage.setItem(v,JSON.stringify(n))}catch{}}var S=class extends r{constructor(...e){super(...e),this.securityConfig={},this.activeSubTab=`pending`,this._pendingApprovals=[],this._resolvedApprovals=[],this._approvalRules={defaultMode:`manual`,timeoutMs:0}}static{this.styles=[o,i,n`
599
487
  :host {
600
488
  display: block;
601
489
  }
@@ -772,24 +660,119 @@ import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S a
772
660
  opacity: 0.5;
773
661
  cursor: not-allowed;
774
662
  }
775
- `];k([d({attribute:!1})],m.prototype,"rpc",2);k([d({attribute:!1})],m.prototype,"securityConfig",2);k([d({type:String})],m.prototype,"activeSubTab",2);k([l()],m.prototype,"_pendingApprovals",2);k([l()],m.prototype,"_resolvedApprovals",2);k([l()],m.prototype,"_approvalRules",2);m=k([$("ic-approval-queue")],m);var W=Object.defineProperty,Z=Object.getOwnPropertyDescriptor,N=(e,t,i,a)=>{for(var r=a>1?void 0:a?Z(t,i):t,o=e.length-1,c;o>=0;o--)(c=e[o])&&(r=(a?c(t,i,r):c(r))||r);return a&&r&&W(t,i,r),r};const ee={low:"success",medium:"warning",high:"error",critical:"error"};let z=class extends x{constructor(){super(...arguments),this.event=null}render(){if(!this.event)return s`
776
- <div class="cell cell--muted" role="cell">---</div>
777
- <div class="cell cell--muted" role="cell">---</div>
778
- <div class="cell cell--muted" role="cell">---</div>
779
- <div class="cell cell--muted" role="cell">---</div>
780
- <div class="cell cell--muted" role="cell">---</div>
781
- `;const e=this.event,t=ee[e.classification]??"default";return s`
782
- <div class="cell cell--muted" role="cell">
783
- <ic-relative-time .timestamp=${e.timestamp}></ic-relative-time>
784
- </div>
785
- <div class="cell" role="cell">${e.agentId||"---"}</div>
786
- <div class="cell" role="cell">${e.action||"---"}</div>
787
- <div class="cell" role="cell">
788
- <ic-tag variant=${t}>${e.classification||"unknown"}</ic-tag>
663
+ `]}connectedCallback(){super.connectedCallback(),this._resolvedApprovals=b()}updated(e){e.has(`rpc`)&&this.rpc&&this._loadApprovals(),e.has(`securityConfig`)&&(this._approvalRules=this.securityConfig.approvalRules??{defaultMode:`manual`,timeoutMs:0})}async _loadApprovals(){if(this.rpc)try{let e=await this.rpc.call(`admin.approval.pending`);this._pendingApprovals=(e.requests??[]).map(_)}catch{}}onApprovalPending(e){let t=e;t?.requestId&&(this._pendingApprovals=[_(t),...this._pendingApprovals])}onApprovalResolved(e){let t=e,n=t?.requestId;if(!n)return;this._pendingApprovals=this._pendingApprovals.filter(e=>e.id!==n);let r={..._(t),outcome:t.approved?`approved`:`denied`,reason:t.reason??``,resolvedAt:t.resolvedAt??Date.now(),resolvedBy:t.approvedBy??`system`};this._resolvedApprovals=[r,...this._resolvedApprovals],x(this._resolvedApprovals)}async _handleApprove(e){if(!this.rpc)return;let{id:t,reason:n}=e.detail;try{await this.rpc.call(`admin.approval.resolve`,{requestId:t,approved:!0,approvedBy:`operator`,reason:n});let e=this._pendingApprovals.find(e=>e.id===t);if(this._pendingApprovals=this._pendingApprovals.filter(e=>e.id!==t),e){let t={...e,outcome:`approved`,reason:n,resolvedAt:Date.now(),resolvedBy:`operator`};this._resolvedApprovals=[t,...this._resolvedApprovals],x(this._resolvedApprovals)}u.show(`Approval granted`,`success`),this.dispatchEvent(new CustomEvent(`approvals-changed`,{bubbles:!0,composed:!0}))}catch(e){u.show(e instanceof Error?e.message:`Failed to approve request`,`error`)}}async _handleDeny(e){if(!this.rpc)return;let{id:t,reason:n}=e.detail;try{await this.rpc.call(`admin.approval.resolve`,{requestId:t,approved:!1,approvedBy:`operator`,reason:n});let e=this._pendingApprovals.find(e=>e.id===t);if(this._pendingApprovals=this._pendingApprovals.filter(e=>e.id!==t),e){let t={...e,outcome:`denied`,reason:n,resolvedAt:Date.now(),resolvedBy:`operator`};this._resolvedApprovals=[t,...this._resolvedApprovals],x(this._resolvedApprovals)}u.show(`Approval denied`,`success`),this.dispatchEvent(new CustomEvent(`approvals-changed`,{bubbles:!0,composed:!0}))}catch(e){u.show(e instanceof Error?e.message:`Failed to deny request`,`error`)}}async _handleResolveAll(e){if(!(!this.rpc||this._pendingApprovals.length===0))try{let t=await this.rpc.call(`admin.approval.resolveAll`,{approved:e,approvedBy:`operator`,reason:e?`Bulk approved by operator`:`Bulk denied by operator`});for(let t of this._pendingApprovals){let n={...t,outcome:e?`approved`:`denied`,reason:e?`Bulk approved by operator`:`Bulk denied by operator`,resolvedAt:Date.now(),resolvedBy:`operator`};this._resolvedApprovals=[n,...this._resolvedApprovals]}this._pendingApprovals=[],x(this._resolvedApprovals),u.show(`${t.resolved} approval(s) ${e?`approved`:`denied`}`,`success`),this.dispatchEvent(new CustomEvent(`approvals-changed`,{bubbles:!0,composed:!0}))}catch(e){u.show(e instanceof Error?e.message:`Bulk operation failed`,`error`)}}async _handleClearDenialCache(){if(this.rpc)try{await this.rpc.call(`admin.approval.clearDenialCache`,{}),u.show(`Denial cache cleared`,`success`)}catch(e){u.show(e instanceof Error?e.message:`Failed to clear denial cache`,`error`)}}async _patchConfig(e,t){if(!this.rpc)return!1;try{let n=e.indexOf(`.`),r=n>0?e.slice(0,n):e,i=n>0?e.slice(n+1):void 0;return await this.rpc.call(`config.patch`,{section:r,key:i,value:t}),u.show(`Configuration updated`,`success`),!0}catch(e){return u.show(e instanceof Error?e.message:`Failed to update configuration`,`error`),!1}}async _onActionConfirmationChange(e,t){let n={...this.securityConfig.actionConfirmation,[e]:t};await this._patchConfig(`security.actionConfirmation`,n)}async _onAgentToAgentEnabledChange(e){let t={...this.securityConfig.agentToAgent,enabled:e};await this._patchConfig(`security.agentToAgent`,t)}async _onAgentToAgentAllowChange(e){let t={...this.securityConfig.agentToAgent,allowAgents:e};await this._patchConfig(`security.agentToAgent`,t)}async _onPermissionToggleChange(e){let t={...this.securityConfig.permission,enableNodePermissions:e};await this._patchConfig(`security.permission`,t)}async _onPermissionPathsChange(e,t){let n={...this.securityConfig.permission,[e]:t};await this._patchConfig(`security.permission`,n)}async _saveApprovalRules(){if(this.rpc)try{await this.rpc.call(`config.patch`,{section:`security`,key:`approvalRules`,value:this._approvalRules}),u.show(`Approval rules updated`,`success`)}catch(e){u.show(e instanceof Error?e.message:`Failed to update approval rules`,`error`)}}_renderHistoryRow(e){let n=e.outcome===`approved`?`success`:`error`,r={low:`success`,medium:`warning`,high:`error`,critical:`error`}[e.classification]??`default`;return t`
664
+ <div class="data-cell" role="cell">${e.agentId}</div>
665
+ <div class="data-cell" role="cell">${e.action}</div>
666
+ <div class="data-cell" role="cell"><ic-tag variant=${r}>${e.classification}</ic-tag></div>
667
+ <div class="data-cell" role="cell"><ic-tag variant=${n}>${e.outcome}</ic-tag></div>
668
+ <div class="data-cell data-cell--muted" role="cell">${e.reason||`---`}</div>
669
+ <div class="data-cell data-cell--muted" role="cell"><ic-relative-time .timestamp=${e.resolvedAt}></ic-relative-time></div>
670
+ <div class="data-cell data-cell--muted" role="cell">${e.resolvedBy}</div>
671
+ `}_renderRulesContent(){let e=this.securityConfig.actionConfirmation??{},n=this.securityConfig.agentToAgent??{},r=this.securityConfig.permission??{};return t`
672
+ <div class="policy-section">
673
+ <div class="section-header">Action Confirmation</div>
674
+ <ic-toggle label="Require for destructive actions"
675
+ .checked=${e.requireForDestructive??!0}
676
+ @change=${e=>this._onActionConfirmationChange(`requireForDestructive`,e.detail)}
677
+ ></ic-toggle>
678
+ <div style="margin-top: var(--ic-space-sm);">
679
+ <ic-toggle label="Require for sensitive actions"
680
+ .checked=${e.requireForSensitive??!1}
681
+ @change=${e=>this._onActionConfirmationChange(`requireForSensitive`,e.detail)}
682
+ ></ic-toggle>
683
+ </div>
684
+ <div style="margin-top: var(--ic-space-md);">
685
+ <ic-array-editor label="Auto-approve list" .items=${e.autoApprove??[]} placeholder="Action name to auto-approve"
686
+ @change=${e=>this._onActionConfirmationChange(`autoApprove`,e.detail)}
687
+ ></ic-array-editor>
688
+ </div>
689
+ </div>
690
+
691
+ <div class="policy-section">
692
+ <div class="section-header">Agent-to-Agent Policy</div>
693
+ <ic-toggle label="Enable cross-agent messaging"
694
+ .checked=${n.enabled??!0}
695
+ @change=${e=>this._onAgentToAgentEnabledChange(e.detail)}
696
+ ></ic-toggle>
697
+ <div style="margin-top: var(--ic-space-md);">
698
+ <ic-array-editor label="Allowed agents" .items=${n.allowAgents??[]} placeholder="Agent ID"
699
+ @change=${e=>this._onAgentToAgentAllowChange(e.detail)}
700
+ ></ic-array-editor>
701
+ </div>
702
+ </div>
703
+
704
+ <div class="policy-section">
705
+ <div class="section-header">Permissions</div>
706
+ <ic-toggle label="Enable Node.js permission model"
707
+ .checked=${r.enableNodePermissions??!1}
708
+ @change=${e=>this._onPermissionToggleChange(e.detail)}
709
+ ></ic-toggle>
710
+ <div style="margin-top: var(--ic-space-md);">
711
+ <ic-array-editor label="Allowed filesystem paths" .items=${r.allowedFsPaths??[]} placeholder="/path/to/allow"
712
+ @change=${e=>this._onPermissionPathsChange(`allowedFsPaths`,e.detail)}
713
+ ></ic-array-editor>
714
+ </div>
715
+ <div style="margin-top: var(--ic-space-md);">
716
+ <ic-array-editor label="Allowed network hosts" .items=${r.allowedNetHosts??[]} placeholder="hostname or IP"
717
+ @change=${e=>this._onPermissionPathsChange(`allowedNetHosts`,e.detail)}
718
+ ></ic-array-editor>
719
+ </div>
720
+ </div>
721
+
722
+ <div class="policy-section">
723
+ <div class="section-header">Approval Mode</div>
724
+ <div class="rules-form">
725
+ <ic-select label="Default Mode" .value=${this._approvalRules.defaultMode} .options=${[{value:`manual`,label:`Manual (all require approval)`},{value:`auto-low`,label:`Auto-approve low risk`},{value:`auto-medium`,label:`Auto-approve low + medium risk`},{value:`auto-all`,label:`Auto-approve all (no approvals)`}]}
726
+ @change=${e=>{this._approvalRules={...this._approvalRules,defaultMode:e.detail}}}
727
+ ></ic-select>
728
+ <div class="form-field">
729
+ <label class="form-label">Timeout (seconds)</label>
730
+ <input class="number-input" type="number" min="0"
731
+ .value=${String(Math.round(this._approvalRules.timeoutMs/1e3))}
732
+ @change=${e=>{let t=parseInt(e.target.value,10);!isNaN(t)&&t>=0&&(this._approvalRules={...this._approvalRules,timeoutMs:t*1e3})}}
733
+ />
734
+ <span class="form-hint">0 = no timeout (request waits indefinitely)</span>
735
+ </div>
736
+ <button class="save-btn" @click=${()=>this._saveApprovalRules()}>Save Rules</button>
737
+ </div>
789
738
  </div>
790
- <div class="cell cell--muted" role="cell">${e.user||"---"}</div>
791
- ${e.details?s`<div class="cell cell--details" role="cell" style="grid-column: 1 / -1;">${e.details}</div>`:p}
792
- `}};z.styles=[_,w`
739
+ `}_renderPendingContent(){let e=[...this._pendingApprovals].sort((e,t)=>t.requestedAt-e.requestedAt);return t`
740
+ <div class="queue-header">
741
+ <span>Pending</span>
742
+ <span class="queue-count">${this._pendingApprovals.length}</span>
743
+ </div>
744
+ <div class="bulk-actions">
745
+ <button class="action-btn action-btn--success" ?disabled=${this._pendingApprovals.length===0}
746
+ @click=${()=>this._handleResolveAll(!0)}>Approve All (${this._pendingApprovals.length})</button>
747
+ <button class="action-btn action-btn--danger" ?disabled=${this._pendingApprovals.length===0}
748
+ @click=${()=>this._handleResolveAll(!1)}>Deny All (${this._pendingApprovals.length})</button>
749
+ <button class="action-btn" @click=${()=>this._handleClearDenialCache()}>Clear Denial Cache</button>
750
+ </div>
751
+ ${e.length===0?t`<ic-empty-state icon="security" message="No pending approvals" description="Approval requests will appear here as they arrive."></ic-empty-state>`:t`
752
+ <div class="queue-list">
753
+ ${e.map(e=>t`
754
+ <ic-approval-card .approval=${e}
755
+ @approve=${e=>this._handleApprove(e)}
756
+ @deny=${e=>this._handleDeny(e)}
757
+ ></ic-approval-card>
758
+ `)}
759
+ </div>
760
+ `}
761
+
762
+ <div class="history-divider">Recent History</div>
763
+ ${this._resolvedApprovals.length===0?t`<p style="font-size: var(--ic-text-sm); color: var(--ic-text-dim); font-style: italic;">No resolved approvals in the last 7 days.</p>`:t`
764
+ <div class="history-grid" role="table" aria-label="Resolved approvals">
765
+ <div class="header-cell" role="columnheader">Agent</div>
766
+ <div class="header-cell" role="columnheader">Action</div>
767
+ <div class="header-cell" role="columnheader">Risk</div>
768
+ <div class="header-cell" role="columnheader">Outcome</div>
769
+ <div class="header-cell" role="columnheader">Reason</div>
770
+ <div class="header-cell" role="columnheader">Resolved At</div>
771
+ <div class="header-cell" role="columnheader">Resolved By</div>
772
+ ${this._resolvedApprovals.map(e=>this._renderHistoryRow(e))}
773
+ </div>
774
+ `}
775
+ `}render(){return this.activeSubTab===`rules`?this._renderRulesContent():this._renderPendingContent()}};c([s({attribute:!1})],S.prototype,`rpc`,void 0),c([s({attribute:!1})],S.prototype,`securityConfig`,void 0),c([s({type:String})],S.prototype,`activeSubTab`,void 0),c([a()],S.prototype,`_pendingApprovals`,void 0),c([a()],S.prototype,`_resolvedApprovals`,void 0),c([a()],S.prototype,`_approvalRules`,void 0),S=c([e(`ic-approval-queue`)],S);var C={low:`success`,medium:`warning`,high:`error`,critical:`error`},w=class extends r{constructor(...e){super(...e),this.event=null}static{this.styles=[o,n`
793
776
  :host {
794
777
  display: contents;
795
778
  }
@@ -812,47 +795,24 @@ import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S a
812
795
  color: var(--ic-text-dim);
813
796
  font-size: var(--ic-text-xs);
814
797
  }
815
- `];N([d({type:Object})],z.prototype,"event",2);z=N([$("ic-audit-row")],z);var te=Object.defineProperty,ie=Object.getOwnPropertyDescriptor,E=(e,t,i,a)=>{for(var r=a>1?void 0:a?ie(t,i):t,o=e.length-1,c;o>=0;o--)(c=e[o])&&(r=(a?c(t,i,r):c(r))||r);return a&&r&&te(t,i,r),r};let f=class extends x{constructor(){super(...arguments),this.activeSubTab="events",this.securityEvents=[],this.inputGuardSummary={blockedAttempts:0,patternsTriggered:[],period:"session"},this._auditEntries=[],this._paused=!1,this._pauseBuffer=[],this._expandedEvents=new Set}onAuditEvent(e){const t=e;if(t){if(this._paused){this._pauseBuffer=[...this._pauseBuffer.slice(-199),t];return}this._auditEntries=[...this._auditEntries.slice(-199),t]}}get auditEntries(){return this._auditEntries}get paused(){return this._paused}get pauseBuffer(){return this._pauseBuffer}_severityVariant(e){switch(e){case"critical":case"high":return"error";case"medium":return"warning";default:return"info"}}_toggleEventDetails(e){this._expandedEvents.has(e)?this._expandedEvents.delete(e):this._expandedEvents.add(e),this.requestUpdate()}_togglePause(){if(this._paused){const e=[...this._auditEntries,...this._pauseBuffer].slice(-200);this._auditEntries=e,this._pauseBuffer=[]}this._paused=!this._paused}_renderEventsContent(){return s`
816
- <div class="guard-summary">
817
- <span style="font-size: var(--ic-text-sm); font-weight: 500; color: var(--ic-text-muted);">Input Guard</span>
818
- <ic-tag variant="error">${this.inputGuardSummary.blockedAttempts} blocked</ic-tag>
819
- ${this.inputGuardSummary.patternsTriggered.length>0?s`<ic-tag variant="warning">${this.inputGuardSummary.patternsTriggered.join(", ")}</ic-tag>`:p}
798
+ `]}render(){if(!this.event)return t`
799
+ <div class="cell cell--muted" role="cell">---</div>
800
+ <div class="cell cell--muted" role="cell">---</div>
801
+ <div class="cell cell--muted" role="cell">---</div>
802
+ <div class="cell cell--muted" role="cell">---</div>
803
+ <div class="cell cell--muted" role="cell">---</div>
804
+ `;let e=this.event,n=C[e.classification]??`default`;return t`
805
+ <div class="cell cell--muted" role="cell">
806
+ <ic-relative-time .timestamp=${e.timestamp}></ic-relative-time>
820
807
  </div>
821
- ${this.securityEvents.length===0?s`<ic-empty-state icon="security" message="No security events" description="Security events will appear here in real-time as they are detected."></ic-empty-state>`:s`
822
- <div role="list" aria-label="Security events">
823
- ${this.securityEvents.map(e=>s`
824
- <div class="event-row" role="listitem">
825
- <ic-tag variant=${this._severityVariant(e.severity)}>${e.severity}</ic-tag>
826
- <ic-tag variant="default">${e.type}</ic-tag>
827
- <span class="event-message">${e.message}</span>
828
- ${e.agentId?s`<ic-tag variant="info">${e.agentId}</ic-tag>`:p}
829
- <ic-relative-time .timestamp=${e.timestamp}></ic-relative-time>
830
- <button class="event-details-toggle"
831
- @click=${()=>this._toggleEventDetails(e.id)}
832
- >${this._expandedEvents.has(e.id)?"hide":"details"}</button>
833
- </div>
834
- ${this._expandedEvents.has(e.id)?s`<pre class="event-details">${JSON.stringify(e.details,null,2)}</pre>`:p}
835
- `)}
836
- </div>
837
- `}
838
- `}_renderAuditContent(){return s`
839
- <div class="audit-controls">
840
- <button class="pause-btn" ?data-active=${this._paused}
841
- @click=${()=>this._togglePause()}
842
- >${this._paused?"Resume":"Pause"}</button>
843
- ${this._paused?s`<span style="font-size: var(--ic-text-xs); color: var(--ic-text-dim);">${this._pauseBuffer.length} buffered</span>`:p}
808
+ <div class="cell" role="cell">${e.agentId||`---`}</div>
809
+ <div class="cell" role="cell">${e.action||`---`}</div>
810
+ <div class="cell" role="cell">
811
+ <ic-tag variant=${n}>${e.classification||`unknown`}</ic-tag>
844
812
  </div>
845
- ${this._auditEntries.length===0?s`<ic-empty-state icon="security" message="No audit events" description="Events will appear here as they occur."></ic-empty-state>`:s`
846
- <div class="audit-grid" role="table" aria-label="Audit log">
847
- <div class="header-cell" role="columnheader">Time</div>
848
- <div class="header-cell" role="columnheader">Agent</div>
849
- <div class="header-cell" role="columnheader">Action</div>
850
- <div class="header-cell" role="columnheader">Risk</div>
851
- <div class="header-cell" role="columnheader">User</div>
852
- ${this._auditEntries.map(e=>s`<ic-audit-row .event=${e} role="row"></ic-audit-row>`)}
853
- </div>
854
- `}
855
- `}render(){return this.activeSubTab==="audit"?this._renderAuditContent():this._renderEventsContent()}};f.styles=[_,S,w`
813
+ <div class="cell cell--muted" role="cell">${e.user||`---`}</div>
814
+ ${e.details?t`<div class="cell cell--details" role="cell" style="grid-column: 1 / -1;">${e.details}</div>`:l}
815
+ `}};c([s({type:Object})],w.prototype,`event`,void 0),w=c([e(`ic-audit-row`)],w);var T=200,E=class extends r{constructor(...e){super(...e),this.activeSubTab=`events`,this.securityEvents=[],this.inputGuardSummary={blockedAttempts:0,patternsTriggered:[],period:`session`},this._auditEntries=[],this._paused=!1,this._pauseBuffer=[],this._expandedEvents=new Set}static{this.styles=[o,i,n`
856
816
  :host {
857
817
  display: block;
858
818
  }
@@ -951,120 +911,47 @@ import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S a
951
911
  top: 0;
952
912
  z-index: 1;
953
913
  }
954
- `];E([d({type:String})],f.prototype,"activeSubTab",2);E([d({attribute:!1})],f.prototype,"securityEvents",2);E([d({attribute:!1})],f.prototype,"inputGuardSummary",2);E([l()],f.prototype,"_auditEntries",2);E([l()],f.prototype,"_paused",2);f=E([$("ic-security-event-feed")],f);var re=Object.defineProperty,ae=Object.getOwnPropertyDescriptor,u=(e,t,i,a)=>{for(var r=a>1?void 0:a?ae(t,i):t,o=e.length-1,c;o>=0;o--)(c=e[o])&&(r=(a?c(t,i,r):c(r))||r);return a&&r&&re(t,i,r),r};const b=200,O=100,se=[{id:"events",label:"Security Events"},{id:"audit",label:"Audit Log"},{id:"tokens",label:"API Tokens"},{id:"secrets",label:"Secrets"},{id:"rules",label:"Approval Rules"},{id:"pending",label:"Pending Approvals"},{id:"health",label:"Provider Health"}];let v=class extends x{constructor(){super(...arguments),this.rpcClient=null,this.apiClient=null,this.eventDispatcher=null,this._sse=null,this._loadState="loading",this._error="",this._activeTab="events",this._securityEvents=[],this._inputGuardSummary={blockedAttempts:0,patternsTriggered:[],period:"session"},this._securityConfig={},this._providerHealth=[],this._failoverLog=[],this._authCooldowns=[],this._healthReloadDebounce=null}_scheduleHealthReload(e=300){this._healthReloadDebounce!==null&&clearTimeout(this._healthReloadDebounce),this._healthReloadDebounce=setTimeout(()=>{this._healthReloadDebounce=null,this._loadProviderHealth()},e)}connectedCallback(){super.connectedCallback(),this._initSse()}disconnectedCallback(){super.disconnectedCallback(),this._healthReloadDebounce!==null&&(clearTimeout(this._healthReloadDebounce),this._healthReloadDebounce=null)}updated(e){e.has("rpcClient")&&this.rpcClient&&this._loadData(),e.has("eventDispatcher")&&this.eventDispatcher&&!this._sse&&this._initSse()}get _eventFeed(){return this.shadowRoot?.querySelector("ic-security-event-feed")??null}get _approvalQueue(){return this.shadowRoot?.querySelector("ic-approval-queue")??null}_initSse(){!this.eventDispatcher||this._sse||(this._sse=new B(this,this.eventDispatcher,{"audit:event":e=>{this._eventFeed?.onAuditEvent(e);const t=e;if(t.actionType==="output_guard"){const i=t.metadata??{},a=i.action,r=a==="redacted"?"high":"medium",o=i.findingCount??0,c={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:"output_guard",severity:r,message:`Output guard ${a??"scan"}: ${o} finding(s)`,details:{findingTypes:i.findingTypes,severities:i.severities,action:i.action,context:i.context},timestamp:t.timestamp??Date.now(),agentId:t.agentId};this._securityEvents=[c,...this._securityEvents].slice(0,b)}},"approval:requested":e=>{this._approvalQueue?.onApprovalPending(e)},"approval:resolved":e=>{this._approvalQueue?.onApprovalResolved(e)},"security:injection_detected":e=>{const t=e,i=t.riskLevel??"medium",r={high:"high",medium:"medium",low:"low"}[i]??"medium",o=t.source??"unknown",c=t.patterns??[],D={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:"injection",severity:r,message:`Injection detected from ${o}`,details:{patterns:c,source:o,sessionKey:t.sessionKey},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[D,...this._securityEvents].slice(0,b);const A=[...new Set([...this._inputGuardSummary.patternsTriggered,...c])];this._inputGuardSummary={...this._inputGuardSummary,blockedAttempts:this._inputGuardSummary.blockedAttempts+1,patternsTriggered:A}},"security:injection_rate_exceeded":e=>{const t=e,i=t.count??0,a=t.threshold??0,r=t.action??"block",o={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:"input_guard",severity:"critical",message:`Rate limit exceeded: ${i}/${a} (action: ${r})`,details:{sessionKey:t.sessionKey,count:i,threshold:a,action:r},timestamp:Date.now()};this._securityEvents=[o,...this._securityEvents].slice(0,b)},"security:memory_tainted":e=>{const t=e,i=t.blocked??!1,a=t.originalTrustLevel??"unknown",r=t.adjustedTrustLevel??"unknown",o={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:"memory_tainted",severity:i?"high":"medium",message:`Memory tainted for ${t.agentId??"unknown"}: ${a} -> ${r}`,details:{patterns:t.patterns,blocked:i,originalTrustLevel:a,adjustedTrustLevel:r},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[o,...this._securityEvents].slice(0,b)},"security:warn":e=>{const t=e,i={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:"warn",severity:"medium",message:t.message??"Security warning",details:{category:t.category},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[i,...this._securityEvents].slice(0,b)},"secret:accessed":e=>{const t=e,i=t.outcome??"unknown",r={denied:"high",not_found:"medium",success:"low"}[i]??"medium",o=t.secretName??"unknown",c={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:"secret_access",severity:r,message:`Secret '${o}' ${i} by ${t.agentId??"unknown"}`,details:{secretName:o,outcome:i},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[c,...this._securityEvents].slice(0,b)},"secret:modified":e=>{const t=e,i=t.secretName??"unknown",a=t.action??"modified",r={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:"secret_access",severity:"medium",message:`Secret '${i}' ${a}`,details:{secretName:i,action:a},timestamp:Date.now()};this._securityEvents=[r,...this._securityEvents].slice(0,b)},"provider:degraded":e=>{const i=e.provider??"";this._providerHealth=this._providerHealth.map(a=>a.providerId===i?{...a,status:"degraded"}:a),this._scheduleHealthReload()},"provider:recovered":e=>{const i=e.provider??"";this._providerHealth=this._providerHealth.map(a=>a.providerId===i?{...a,status:"healthy"}:a),this._scheduleHealthReload()},"model:auth_cooldown":e=>{const t=e,i={keyName:t.keyName,provider:t.provider,cooldownMs:t.cooldownMs,failureCount:t.failureCount,timestamp:t.timestamp};this._authCooldowns=[i,...this._authCooldowns].slice(0,50),this._scheduleHealthReload(500)},"model:fallback_attempt":e=>{const t=e,i={fromProvider:t.fromProvider,fromModel:t.fromModel,toProvider:t.toProvider,toModel:t.toModel,error:t.error,attemptNumber:t.attemptNumber,timestamp:t.timestamp};this._failoverLog=[i,...this._failoverLog].slice(0,O),this._scheduleHealthReload()},"model:fallback_exhausted":e=>{const t=e,i={provider:t.provider,model:t.model,totalAttempts:t.totalAttempts,timestamp:t.timestamp,exhausted:!0};this._failoverLog=[i,...this._failoverLog].slice(0,O),this._scheduleHealthReload()},"observability:token_usage":()=>{this._scheduleHealthReload(500)}}))}async _loadProviderHealth(){if(this.rpcClient)try{const e=await this.rpcClient.call("agent.cacheStats"),t=Date.now(),i=t-300*1e3,a=(e.providers??[]).map(r=>{const o=this._failoverLog.filter(h=>h.fromProvider===r.provider||h.provider===r.provider),c=o.length>0?Math.max(...o.map(h=>h.timestamp)):void 0;let D="healthy";const A=this._authCooldowns.find(h=>h.provider===r.provider&&h.timestamp+h.cooldownMs>t);return A&&(D="degraded"),this._failoverLog.find(h=>h.exhausted===!0&&h.provider===r.provider&&h.timestamp>i)&&(D="down"),{providerId:r.provider,name:r.provider,status:D,cacheHitRate:r.cacheHitRate,failoverCount:o.length,lastFailover:c,authCooldownUntil:A?A.timestamp+A.cooldownMs:void 0}});this._providerHealth=a}catch{}}async _loadData(){if(this.rpcClient){this._loadState="loading",this._error="";try{const e=await this.rpcClient.call("config.read");this._securityConfig=e.config.security??{},this._loadState="loaded",this._loadProviderHealth()}catch(e){this._error=e instanceof Error?e.message:"Failed to load security configuration",this._loadState="error"}}}async _patchConfig(e,t){if(!this.rpcClient)return!1;try{const i=e.indexOf("."),a=i>0?e.slice(0,i):e,r=i>0?e.slice(i+1):void 0;return await this.rpcClient.call("config.patch",{section:a,key:r,value:t}),n.show("Configuration updated","success"),!0}catch(i){const a=i instanceof Error?i.message:"Failed to update configuration";return n.show(a,"error"),!1}}async _onSecretsEnabledChange(e){const t={...this._securityConfig.secrets,enabled:e};await this._patchConfig("security.secrets",t)&&(this._securityConfig={...this._securityConfig,secrets:t})}_renderSecretsTab(){const e=this._securityConfig.secrets??{};return s`
955
- <div class="policy-section">
956
- <div class="section-header">Encrypted Secrets Store</div>
957
- <ic-toggle
958
- label="Enabled"
959
- .checked=${e.enabled??!1}
960
- @change=${t=>this._onSecretsEnabledChange(t.detail)}
961
- ></ic-toggle>
962
- <div style="margin-top: var(--ic-space-md);">
963
- <div class="tls-row">
964
- <span class="tls-label">DB Path</span>
965
- <span class="tls-value">${e.dbPath??"secrets.db"}</span>
966
- </div>
967
- </div>
914
+ `]}onAuditEvent(e){let t=e;if(t){if(this._paused){this._pauseBuffer=[...this._pauseBuffer.slice(-(T-1)),t];return}this._auditEntries=[...this._auditEntries.slice(-(T-1)),t]}}get auditEntries(){return this._auditEntries}get paused(){return this._paused}get pauseBuffer(){return this._pauseBuffer}_severityVariant(e){switch(e){case`critical`:case`high`:return`error`;case`medium`:return`warning`;default:return`info`}}_toggleEventDetails(e){this._expandedEvents.has(e)?this._expandedEvents.delete(e):this._expandedEvents.add(e),this.requestUpdate()}_togglePause(){if(this._paused){let e=[...this._auditEntries,...this._pauseBuffer].slice(-T);this._auditEntries=e,this._pauseBuffer=[]}this._paused=!this._paused}_renderEventsContent(){return t`
915
+ <div class="guard-summary">
916
+ <span style="font-size: var(--ic-text-sm); font-weight: 500; color: var(--ic-text-muted);">Input Guard</span>
917
+ <ic-tag variant="error">${this.inputGuardSummary.blockedAttempts} blocked</ic-tag>
918
+ ${this.inputGuardSummary.patternsTriggered.length>0?t`<ic-tag variant="warning">${this.inputGuardSummary.patternsTriggered.join(`, `)}</ic-tag>`:l}
968
919
  </div>
969
- `}_statusToDotStatus(e){switch(e){case"healthy":return"connected";case"degraded":return"reconnecting";case"down":return"disconnected";default:return"disconnected"}}_renderHealthTab(){const e=Date.now(),t=this._authCooldowns.filter(i=>i.timestamp+i.cooldownMs>e);return s`
970
- <div class="section-header">Provider Status</div>
971
- ${this._providerHealth.length===0?s`<ic-empty-state icon="cloud" message="No provider data" description="Provider health data will appear after LLM calls are made."></ic-empty-state>`:s`
972
- <div class="health-grid">
973
- ${this._providerHealth.map(i=>s`
974
- <div class="health-card">
975
- <div class="health-card-header">
976
- <strong>${i.name}</strong>
977
- <ic-connection-dot
978
- status=${this._statusToDotStatus(i.status)}
979
- size="8px"
980
- ></ic-connection-dot>
981
- </div>
982
- <ic-progress-bar
983
- .value=${Math.round(i.cacheHitRate*100)}
984
- label="Cache Hit Rate"
985
- .thresholds=${{green:101,yellow:102}}
986
- ></ic-progress-bar>
987
- <div class="health-card-stat">
988
- Failovers: ${i.failoverCount}
989
- ${i.lastFailover?s` &mdash; last <ic-relative-time .timestamp=${i.lastFailover}></ic-relative-time>`:p}
990
- </div>
991
- ${i.authCooldownUntil&&i.authCooldownUntil>e?s`
992
- <div class="health-card-stat">
993
- <ic-tag variant="warning">Auth cooldown</ic-tag>
994
- ${Math.ceil((i.authCooldownUntil-e)/1e3)}s remaining
995
- </div>
996
- `:p}
997
- </div>
998
- `)}
999
- </div>
1000
- `}
1001
-
1002
- <div class="section-header" style="margin-top: var(--ic-space-xl);">Failover Event Log</div>
1003
- ${this._failoverLog.length===0?s`<p style="font-size: var(--ic-text-sm); color: var(--ic-text-dim); font-style: italic;">No failover events recorded</p>`:s`
1004
- <div class="failover-log">
1005
- ${this._failoverLog.map(i=>s`
1006
- <div class="failover-entry">
1007
- <ic-relative-time .timestamp=${i.timestamp}></ic-relative-time>
1008
- ${i.exhausted?s`
1009
- <span>${i.provider??"unknown"} exhausted after ${i.totalAttempts??"?"} attempts</span>
1010
- <ic-tag variant="error">EXHAUSTED</ic-tag>
1011
- `:s`
1012
- <span>${i.fromProvider??"?"}/${i.fromModel??"?"} &rarr; ${i.toProvider??"?"}/${i.toModel??"?"}</span>
1013
- ${i.attemptNumber!=null?s`<ic-tag variant="info">#${i.attemptNumber}</ic-tag>`:p}
1014
- ${i.error?s`<span style="color: var(--ic-text-dim);">${i.error}</span>`:p}
1015
- `}
920
+ ${this.securityEvents.length===0?t`<ic-empty-state icon="security" message="No security events" description="Security events will appear here in real-time as they are detected."></ic-empty-state>`:t`
921
+ <div role="list" aria-label="Security events">
922
+ ${this.securityEvents.map(e=>t`
923
+ <div class="event-row" role="listitem">
924
+ <ic-tag variant=${this._severityVariant(e.severity)}>${e.severity}</ic-tag>
925
+ <ic-tag variant="default">${e.type}</ic-tag>
926
+ <span class="event-message">${e.message}</span>
927
+ ${e.agentId?t`<ic-tag variant="info">${e.agentId}</ic-tag>`:l}
928
+ <ic-relative-time .timestamp=${e.timestamp}></ic-relative-time>
929
+ <button class="event-details-toggle"
930
+ @click=${()=>this._toggleEventDetails(e.id)}
931
+ >${this._expandedEvents.has(e.id)?`hide`:`details`}</button>
1016
932
  </div>
933
+ ${this._expandedEvents.has(e.id)?t`<pre class="event-details">${JSON.stringify(e.details,null,2)}</pre>`:l}
1017
934
  `)}
1018
935
  </div>
1019
936
  `}
1020
-
1021
- <div class="section-header" style="margin-top: var(--ic-space-xl);">Auth Cooldowns</div>
1022
- ${t.length===0?s`<p style="font-size: var(--ic-text-sm); color: var(--ic-text-dim); font-style: italic;">No active cooldowns</p>`:s`
1023
- <div class="cooldown-list">
1024
- ${t.map(i=>s`
1025
- <div class="cooldown-entry">
1026
- <ic-tag variant="warning">${i.provider}</ic-tag>
1027
- <span>${i.keyName}</span>
1028
- <span style="color: var(--ic-text-dim);">${i.failureCount} failures</span>
1029
- <span>${Math.ceil((i.timestamp+i.cooldownMs-e)/1e3)}s remaining</span>
1030
- </div>
1031
- `)}
937
+ `}_renderAuditContent(){return t`
938
+ <div class="audit-controls">
939
+ <button class="pause-btn" ?data-active=${this._paused}
940
+ @click=${()=>this._togglePause()}
941
+ >${this._paused?`Resume`:`Pause`}</button>
942
+ ${this._paused?t`<span style="font-size: var(--ic-text-xs); color: var(--ic-text-dim);">${this._pauseBuffer.length} buffered</span>`:l}
943
+ </div>
944
+ ${this._auditEntries.length===0?t`<ic-empty-state icon="security" message="No audit events" description="Events will appear here as they occur."></ic-empty-state>`:t`
945
+ <div class="audit-grid" role="table" aria-label="Audit log">
946
+ <div class="header-cell" role="columnheader">Time</div>
947
+ <div class="header-cell" role="columnheader">Agent</div>
948
+ <div class="header-cell" role="columnheader">Action</div>
949
+ <div class="header-cell" role="columnheader">Risk</div>
950
+ <div class="header-cell" role="columnheader">User</div>
951
+ ${this._auditEntries.map(e=>t`<ic-audit-row .event=${e} role="row"></ic-audit-row>`)}
1032
952
  </div>
1033
953
  `}
1034
- `}_renderTabContent(){switch(this._activeTab){case"events":return s`<ic-security-event-feed
1035
- activeSubTab="events"
1036
- .securityEvents=${this._securityEvents}
1037
- .inputGuardSummary=${this._inputGuardSummary}
1038
- ></ic-security-event-feed>`;case"audit":return s`<ic-security-event-feed
1039
- activeSubTab="audit"
1040
- .securityEvents=${this._securityEvents}
1041
- .inputGuardSummary=${this._inputGuardSummary}
1042
- ></ic-security-event-feed>`;case"tokens":return s`<ic-token-manager .rpc=${this.rpcClient}></ic-token-manager>`;case"secrets":return this._renderSecretsTab();case"rules":return s`<ic-approval-queue
1043
- activeSubTab="rules"
1044
- .rpc=${this.rpcClient}
1045
- .securityConfig=${this._securityConfig}
1046
- ></ic-approval-queue>`;case"pending":return s`<ic-approval-queue
1047
- activeSubTab="pending"
1048
- .rpc=${this.rpcClient}
1049
- .securityConfig=${this._securityConfig}
1050
- ></ic-approval-queue>`;case"health":return this._renderHealthTab();default:return p}}render(){return this._loadState==="loading"?s`<ic-skeleton-view variant="list"></ic-skeleton-view>`:this._loadState==="error"?s`
1051
- <div class="error-container">
1052
- <span class="error-message">${this._error}</span>
1053
- <button class="retry-btn" @click=${()=>this._loadData()}>Retry</button>
1054
- </div>
1055
- `:s`
1056
- <div class="view-header">
1057
- <div class="view-title">Security</div>
1058
- </div>
1059
- <ic-tabs
1060
- .tabs=${se}
1061
- .activeTab=${this._activeTab}
1062
- @tab-change=${e=>{this._activeTab=e.detail}}
1063
- ></ic-tabs>
1064
- <div class="tab-content">
1065
- ${this._renderTabContent()}
1066
- </div>
1067
- `}};v.styles=[_,S,w`
954
+ `}render(){return this.activeSubTab===`audit`?this._renderAuditContent():this._renderEventsContent()}};c([s({type:String})],E.prototype,`activeSubTab`,void 0),c([s({attribute:!1})],E.prototype,`securityEvents`,void 0),c([s({attribute:!1})],E.prototype,`inputGuardSummary`,void 0),c([a()],E.prototype,`_auditEntries`,void 0),c([a()],E.prototype,`_paused`,void 0),E=c([e(`ic-security-event-feed`)],E);var D=200,O=100,k=[{id:`events`,label:`Security Events`},{id:`audit`,label:`Audit Log`},{id:`tokens`,label:`API Tokens`},{id:`secrets`,label:`Secrets`},{id:`rules`,label:`Approval Rules`},{id:`pending`,label:`Pending Approvals`},{id:`health`,label:`Provider Health`}],A=class extends r{constructor(...e){super(...e),this.rpcClient=null,this.apiClient=null,this.eventDispatcher=null,this._sse=null,this._loadState=`loading`,this._error=``,this._activeTab=`events`,this._securityEvents=[],this._inputGuardSummary={blockedAttempts:0,patternsTriggered:[],period:`session`},this._securityConfig={},this._providerHealth=[],this._failoverLog=[],this._authCooldowns=[],this._healthReloadDebounce=null}static{this.styles=[o,i,n`
1068
955
  :host {
1069
956
  display: block;
1070
957
  }
@@ -1221,4 +1108,117 @@ import{s as _,f as S,i as w,n as d,r as l,a as x,A as p,b as s,t as $,I as n,S a
1221
1108
  align-items: center;
1222
1109
  font-size: var(--ic-text-sm);
1223
1110
  }
1224
- `];u([d({attribute:!1})],v.prototype,"rpcClient",2);u([d({attribute:!1})],v.prototype,"apiClient",2);u([d({attribute:!1})],v.prototype,"eventDispatcher",2);u([l()],v.prototype,"_loadState",2);u([l()],v.prototype,"_error",2);u([l()],v.prototype,"_activeTab",2);u([l()],v.prototype,"_securityEvents",2);u([l()],v.prototype,"_inputGuardSummary",2);u([l()],v.prototype,"_securityConfig",2);u([l()],v.prototype,"_providerHealth",2);u([l()],v.prototype,"_failoverLog",2);u([l()],v.prototype,"_authCooldowns",2);v=u([$("ic-security-view")],v);export{v as IcSecurityView};
1111
+ `]}_scheduleHealthReload(e=300){this._healthReloadDebounce!==null&&clearTimeout(this._healthReloadDebounce),this._healthReloadDebounce=setTimeout(()=>{this._healthReloadDebounce=null,this._loadProviderHealth()},e)}connectedCallback(){super.connectedCallback(),this._initSse()}disconnectedCallback(){super.disconnectedCallback(),this._healthReloadDebounce!==null&&(clearTimeout(this._healthReloadDebounce),this._healthReloadDebounce=null)}updated(e){e.has(`rpcClient`)&&this.rpcClient&&this._loadData(),e.has(`eventDispatcher`)&&this.eventDispatcher&&!this._sse&&this._initSse()}get _eventFeed(){return this.shadowRoot?.querySelector(`ic-security-event-feed`)??null}get _approvalQueue(){return this.shadowRoot?.querySelector(`ic-approval-queue`)??null}_initSse(){!this.eventDispatcher||this._sse||(this._sse=new d(this,this.eventDispatcher,{"audit:event":e=>{this._eventFeed?.onAuditEvent(e);let t=e;if(t.actionType===`output_guard`){let e=t.metadata??{},n=e.action,r=n===`redacted`?`high`:`medium`,i=e.findingCount??0,a={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:`output_guard`,severity:r,message:`Output guard ${n??`scan`}: ${i} finding(s)`,details:{findingTypes:e.findingTypes,severities:e.severities,action:e.action,context:e.context},timestamp:t.timestamp??Date.now(),agentId:t.agentId};this._securityEvents=[a,...this._securityEvents].slice(0,D)}},"approval:requested":e=>{this._approvalQueue?.onApprovalPending(e)},"approval:resolved":e=>{this._approvalQueue?.onApprovalResolved(e)},"security:injection_detected":e=>{let t=e,n={high:`high`,medium:`medium`,low:`low`}[t.riskLevel??`medium`]??`medium`,r=t.source??`unknown`,i=t.patterns??[],a={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:`injection`,severity:n,message:`Injection detected from ${r}`,details:{patterns:i,source:r,sessionKey:t.sessionKey},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[a,...this._securityEvents].slice(0,D);let o=[...new Set([...this._inputGuardSummary.patternsTriggered,...i])];this._inputGuardSummary={...this._inputGuardSummary,blockedAttempts:this._inputGuardSummary.blockedAttempts+1,patternsTriggered:o}},"security:injection_rate_exceeded":e=>{let t=e,n=t.count??0,r=t.threshold??0,i=t.action??`block`,a={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:`input_guard`,severity:`critical`,message:`Rate limit exceeded: ${n}/${r} (action: ${i})`,details:{sessionKey:t.sessionKey,count:n,threshold:r,action:i},timestamp:Date.now()};this._securityEvents=[a,...this._securityEvents].slice(0,D)},"security:memory_tainted":e=>{let t=e,n=t.blocked??!1,r=t.originalTrustLevel??`unknown`,i=t.adjustedTrustLevel??`unknown`,a={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:`memory_tainted`,severity:n?`high`:`medium`,message:`Memory tainted for ${t.agentId??`unknown`}: ${r} -> ${i}`,details:{patterns:t.patterns,blocked:n,originalTrustLevel:r,adjustedTrustLevel:i},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[a,...this._securityEvents].slice(0,D)},"security:warn":e=>{let t=e,n={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:`warn`,severity:`medium`,message:t.message??`Security warning`,details:{category:t.category},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[n,...this._securityEvents].slice(0,D)},"secret:accessed":e=>{let t=e,n=t.outcome??`unknown`,r={denied:`high`,not_found:`medium`,success:`low`}[n]??`medium`,i=t.secretName??`unknown`,a={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:`secret_access`,severity:r,message:`Secret '${i}' ${n} by ${t.agentId??`unknown`}`,details:{secretName:i,outcome:n},timestamp:Date.now(),agentId:t.agentId};this._securityEvents=[a,...this._securityEvents].slice(0,D)},"secret:modified":e=>{let t=e,n=t.secretName??`unknown`,r=t.action??`modified`,i={id:`sec-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,type:`secret_access`,severity:`medium`,message:`Secret '${n}' ${r}`,details:{secretName:n,action:r},timestamp:Date.now()};this._securityEvents=[i,...this._securityEvents].slice(0,D)},"provider:degraded":e=>{let t=e.provider??``;this._providerHealth=this._providerHealth.map(e=>e.providerId===t?{...e,status:`degraded`}:e),this._scheduleHealthReload()},"provider:recovered":e=>{let t=e.provider??``;this._providerHealth=this._providerHealth.map(e=>e.providerId===t?{...e,status:`healthy`}:e),this._scheduleHealthReload()},"model:auth_cooldown":e=>{let t=e,n={keyName:t.keyName,provider:t.provider,cooldownMs:t.cooldownMs,failureCount:t.failureCount,timestamp:t.timestamp};this._authCooldowns=[n,...this._authCooldowns].slice(0,50),this._scheduleHealthReload(500)},"model:fallback_attempt":e=>{let t=e,n={fromProvider:t.fromProvider,fromModel:t.fromModel,toProvider:t.toProvider,toModel:t.toModel,error:t.error,attemptNumber:t.attemptNumber,timestamp:t.timestamp};this._failoverLog=[n,...this._failoverLog].slice(0,O),this._scheduleHealthReload()},"model:fallback_exhausted":e=>{let t=e,n={provider:t.provider,model:t.model,totalAttempts:t.totalAttempts,timestamp:t.timestamp,exhausted:!0};this._failoverLog=[n,...this._failoverLog].slice(0,O),this._scheduleHealthReload()},"observability:token_usage":()=>{this._scheduleHealthReload(500)}}))}async _loadProviderHealth(){if(this.rpcClient)try{let e=await this.rpcClient.call(`agent.cacheStats`),t=Date.now(),n=t-300*1e3,r=(e.providers??[]).map(e=>{let r=this._failoverLog.filter(t=>t.fromProvider===e.provider||t.provider===e.provider),i=r.length>0?Math.max(...r.map(e=>e.timestamp)):void 0,a=`healthy`,o=this._authCooldowns.find(n=>n.provider===e.provider&&n.timestamp+n.cooldownMs>t);return o&&(a=`degraded`),this._failoverLog.find(t=>t.exhausted===!0&&t.provider===e.provider&&t.timestamp>n)&&(a=`down`),{providerId:e.provider,name:e.provider,status:a,cacheHitRate:e.cacheHitRate,failoverCount:r.length,lastFailover:i,authCooldownUntil:o?o.timestamp+o.cooldownMs:void 0}});this._providerHealth=r}catch{}}async _loadData(){if(this.rpcClient){this._loadState=`loading`,this._error=``;try{let e=await this.rpcClient.call(`config.read`);this._securityConfig=e.config.security??{},this._loadState=`loaded`,this._loadProviderHealth()}catch(e){this._error=e instanceof Error?e.message:`Failed to load security configuration`,this._loadState=`error`}}}async _patchConfig(e,t){if(!this.rpcClient)return!1;try{let n=e.indexOf(`.`),r=n>0?e.slice(0,n):e,i=n>0?e.slice(n+1):void 0;return await this.rpcClient.call(`config.patch`,{section:r,key:i,value:t}),u.show(`Configuration updated`,`success`),!0}catch(e){let t=e instanceof Error?e.message:`Failed to update configuration`;return u.show(t,`error`),!1}}async _onSecretsEnabledChange(e){let t={...this._securityConfig.secrets,enabled:e};await this._patchConfig(`security.secrets`,t)&&(this._securityConfig={...this._securityConfig,secrets:t})}_renderSecretsTab(){let e=this._securityConfig.secrets??{};return t`
1112
+ <div class="policy-section">
1113
+ <div class="section-header">Encrypted Secrets Store</div>
1114
+ <ic-toggle
1115
+ label="Enabled"
1116
+ .checked=${e.enabled??!1}
1117
+ @change=${e=>this._onSecretsEnabledChange(e.detail)}
1118
+ ></ic-toggle>
1119
+ <div style="margin-top: var(--ic-space-md);">
1120
+ <div class="tls-row">
1121
+ <span class="tls-label">DB Path</span>
1122
+ <span class="tls-value">${e.dbPath??`secrets.db`}</span>
1123
+ </div>
1124
+ </div>
1125
+ </div>
1126
+ `}_statusToDotStatus(e){switch(e){case`healthy`:return`connected`;case`degraded`:return`reconnecting`;case`down`:return`disconnected`;default:return`disconnected`}}_renderHealthTab(){let e=Date.now(),n=this._authCooldowns.filter(t=>t.timestamp+t.cooldownMs>e);return t`
1127
+ <div class="section-header">Provider Status</div>
1128
+ ${this._providerHealth.length===0?t`<ic-empty-state icon="cloud" message="No provider data" description="Provider health data will appear after LLM calls are made."></ic-empty-state>`:t`
1129
+ <div class="health-grid">
1130
+ ${this._providerHealth.map(n=>t`
1131
+ <div class="health-card">
1132
+ <div class="health-card-header">
1133
+ <strong>${n.name}</strong>
1134
+ <ic-connection-dot
1135
+ status=${this._statusToDotStatus(n.status)}
1136
+ size="8px"
1137
+ ></ic-connection-dot>
1138
+ </div>
1139
+ <ic-progress-bar
1140
+ .value=${Math.round(n.cacheHitRate*100)}
1141
+ label="Cache Hit Rate"
1142
+ .thresholds=${{green:101,yellow:102}}
1143
+ ></ic-progress-bar>
1144
+ <div class="health-card-stat">
1145
+ Failovers: ${n.failoverCount}
1146
+ ${n.lastFailover?t` &mdash; last <ic-relative-time .timestamp=${n.lastFailover}></ic-relative-time>`:l}
1147
+ </div>
1148
+ ${n.authCooldownUntil&&n.authCooldownUntil>e?t`
1149
+ <div class="health-card-stat">
1150
+ <ic-tag variant="warning">Auth cooldown</ic-tag>
1151
+ ${Math.ceil((n.authCooldownUntil-e)/1e3)}s remaining
1152
+ </div>
1153
+ `:l}
1154
+ </div>
1155
+ `)}
1156
+ </div>
1157
+ `}
1158
+
1159
+ <div class="section-header" style="margin-top: var(--ic-space-xl);">Failover Event Log</div>
1160
+ ${this._failoverLog.length===0?t`<p style="font-size: var(--ic-text-sm); color: var(--ic-text-dim); font-style: italic;">No failover events recorded</p>`:t`
1161
+ <div class="failover-log">
1162
+ ${this._failoverLog.map(e=>t`
1163
+ <div class="failover-entry">
1164
+ <ic-relative-time .timestamp=${e.timestamp}></ic-relative-time>
1165
+ ${e.exhausted?t`
1166
+ <span>${e.provider??`unknown`} exhausted after ${e.totalAttempts??`?`} attempts</span>
1167
+ <ic-tag variant="error">EXHAUSTED</ic-tag>
1168
+ `:t`
1169
+ <span>${e.fromProvider??`?`}/${e.fromModel??`?`} &rarr; ${e.toProvider??`?`}/${e.toModel??`?`}</span>
1170
+ ${e.attemptNumber==null?l:t`<ic-tag variant="info">#${e.attemptNumber}</ic-tag>`}
1171
+ ${e.error?t`<span style="color: var(--ic-text-dim);">${e.error}</span>`:l}
1172
+ `}
1173
+ </div>
1174
+ `)}
1175
+ </div>
1176
+ `}
1177
+
1178
+ <div class="section-header" style="margin-top: var(--ic-space-xl);">Auth Cooldowns</div>
1179
+ ${n.length===0?t`<p style="font-size: var(--ic-text-sm); color: var(--ic-text-dim); font-style: italic;">No active cooldowns</p>`:t`
1180
+ <div class="cooldown-list">
1181
+ ${n.map(n=>t`
1182
+ <div class="cooldown-entry">
1183
+ <ic-tag variant="warning">${n.provider}</ic-tag>
1184
+ <span>${n.keyName}</span>
1185
+ <span style="color: var(--ic-text-dim);">${n.failureCount} failures</span>
1186
+ <span>${Math.ceil((n.timestamp+n.cooldownMs-e)/1e3)}s remaining</span>
1187
+ </div>
1188
+ `)}
1189
+ </div>
1190
+ `}
1191
+ `}_renderTabContent(){switch(this._activeTab){case`events`:return t`<ic-security-event-feed
1192
+ activeSubTab="events"
1193
+ .securityEvents=${this._securityEvents}
1194
+ .inputGuardSummary=${this._inputGuardSummary}
1195
+ ></ic-security-event-feed>`;case`audit`:return t`<ic-security-event-feed
1196
+ activeSubTab="audit"
1197
+ .securityEvents=${this._securityEvents}
1198
+ .inputGuardSummary=${this._inputGuardSummary}
1199
+ ></ic-security-event-feed>`;case`tokens`:return t`<ic-token-manager .rpc=${this.rpcClient}></ic-token-manager>`;case`secrets`:return this._renderSecretsTab();case`rules`:return t`<ic-approval-queue
1200
+ activeSubTab="rules"
1201
+ .rpc=${this.rpcClient}
1202
+ .securityConfig=${this._securityConfig}
1203
+ ></ic-approval-queue>`;case`pending`:return t`<ic-approval-queue
1204
+ activeSubTab="pending"
1205
+ .rpc=${this.rpcClient}
1206
+ .securityConfig=${this._securityConfig}
1207
+ ></ic-approval-queue>`;case`health`:return this._renderHealthTab();default:return l}}render(){return this._loadState===`loading`?t`<ic-skeleton-view variant="list"></ic-skeleton-view>`:this._loadState===`error`?t`
1208
+ <div class="error-container">
1209
+ <span class="error-message">${this._error}</span>
1210
+ <button class="retry-btn" @click=${()=>this._loadData()}>Retry</button>
1211
+ </div>
1212
+ `:t`
1213
+ <div class="view-header">
1214
+ <div class="view-title">Security</div>
1215
+ </div>
1216
+ <ic-tabs
1217
+ .tabs=${k}
1218
+ .activeTab=${this._activeTab}
1219
+ @tab-change=${e=>{this._activeTab=e.detail}}
1220
+ ></ic-tabs>
1221
+ <div class="tab-content">
1222
+ ${this._renderTabContent()}
1223
+ </div>
1224
+ `}};c([s({attribute:!1})],A.prototype,`rpcClient`,void 0),c([s({attribute:!1})],A.prototype,`apiClient`,void 0),c([s({attribute:!1})],A.prototype,`eventDispatcher`,void 0),c([a()],A.prototype,`_loadState`,void 0),c([a()],A.prototype,`_error`,void 0),c([a()],A.prototype,`_activeTab`,void 0),c([a()],A.prototype,`_securityEvents`,void 0),c([a()],A.prototype,`_inputGuardSummary`,void 0),c([a()],A.prototype,`_securityConfig`,void 0),c([a()],A.prototype,`_providerHealth`,void 0),c([a()],A.prototype,`_failoverLog`,void 0),c([a()],A.prototype,`_authCooldowns`,void 0),A=c([e(`ic-security-view`)],A);export{A as IcSecurityView};