@muxoai/platform 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +1 -1
- package/.claude-plugin/marketplace.json +2 -2
- package/README.md +1 -1
- package/dist/cli.js +94 -3
- package/dist/composio-catalog.d.ts +177 -1
- package/dist/composio-catalog.js +1427 -7
- package/dist/config.d.ts +6 -0
- package/dist/config.js +11 -1
- package/dist/durable-workflow.d.ts +71 -4
- package/dist/durable-workflow.js +199 -5
- package/dist/engine.d.ts +82 -3
- package/dist/engine.js +406 -41
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/mcp-schema.d.ts +162 -1
- package/dist/mcp-schema.js +1544 -40
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +474 -26
- package/dist/memory-graph.d.ts +26 -2
- package/dist/memory-graph.js +127 -7
- package/dist/oss-suite.d.ts +217 -0
- package/dist/oss-suite.js +836 -0
- package/dist/policy.d.ts +108 -1
- package/dist/policy.js +406 -1
- package/dist/providers/composio-instant.js +38 -3
- package/dist/providers/composio-sdk.d.ts +59 -2
- package/dist/providers/composio-sdk.js +273 -59
- package/dist/providers/stripe-projects.d.ts +4 -0
- package/dist/providers/stripe-projects.js +548 -126
- package/dist/sdk.d.ts +24 -1
- package/dist/sdk.js +53 -2
- package/dist/server.js +659 -64
- package/dist/store.js +2 -0
- package/dist/types.d.ts +34 -1
- package/dist/ui/console-html.d.ts +31 -1
- package/dist/ui/console-html.js +922 -368
- package/dist/ui/design-tokens.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
- package/plugins/muxo/.claude-plugin/plugin.json +2 -2
- package/plugins/muxo/.codex-plugin/plugin.json +15 -8
- package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
- package/plugins/muxo/hooks/session-start.sh +15 -3
- package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
- package/plugins/muxo/mcp.json +0 -10
- package/plugins/muxo/plugin.json +4 -4
- package/plugins/muxo/skills/muxo/SKILL.md +25 -16
- package/plugins/muxo/skills/muxo/references/cli.md +5 -1
- package/plugins/muxo/skills/muxo/references/mcp.md +11 -6
- package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
- package/plugins/muxo/skills/setup/SKILL.md +1 -1
- package/src/catalogues/stripe-projects-catalog.json +140 -0
package/dist/ui/console-html.js
CHANGED
|
@@ -4,11 +4,13 @@ export const CONSOLE_ROUTES = Object.freeze({
|
|
|
4
4
|
"/": "overview",
|
|
5
5
|
"/console": "overview",
|
|
6
6
|
"/dashboard": "overview",
|
|
7
|
-
"/catalog": "
|
|
7
|
+
"/catalog": "catalog",
|
|
8
|
+
"/tools": "catalog",
|
|
8
9
|
"/connections": "overview",
|
|
9
10
|
"/infrastructure": "overview",
|
|
10
11
|
"/keys": "setup",
|
|
11
12
|
"/setup": "setup",
|
|
13
|
+
"/workspaces": "workspaces",
|
|
12
14
|
"/activity": "activity",
|
|
13
15
|
"/receipts": "activity",
|
|
14
16
|
"/governance": "activity",
|
|
@@ -39,6 +41,7 @@ const consoleCss = `
|
|
|
39
41
|
.workspace-chip:hover{background:var(--color-surface-2)}
|
|
40
42
|
.workspace-chip #workspace-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
41
43
|
.workspace-chip .tier{flex:none;color:var(--color-muted);font-size:12px}
|
|
44
|
+
.workspace-chip>.ui-icon{width:12px;height:12px;transform:rotate(90deg)}
|
|
42
45
|
.topbar-links{display:flex;align-items:center;gap:20px;margin-left:auto}
|
|
43
46
|
.nav-link{display:inline-flex;align-items:center;min-height:44px;color:var(--color-muted);font-size:13px;text-decoration:none}
|
|
44
47
|
.nav-link:hover{color:var(--color-text)}
|
|
@@ -47,6 +50,13 @@ const consoleCss = `
|
|
|
47
50
|
.theme-sun{display:none}html[data-theme=dark] .theme-sun{display:inline-block}html[data-theme=dark] .theme-moon{display:none}
|
|
48
51
|
.account{display:flex;align-items:center;gap:12px}
|
|
49
52
|
.account-label{max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--color-muted);font-size:13px}
|
|
53
|
+
.mobile-menu-toggle{display:none}
|
|
54
|
+
.mobile-menu-content{display:flex;flex-direction:column;gap:24px;min-height:100%;padding:24px}
|
|
55
|
+
dialog.sheet.mobile-menu{inset:0 auto 0 0;width:min(340px,calc(100% - 32px));height:100dvh;max-height:100dvh;margin:0;border-radius:0 20px 20px 0}
|
|
56
|
+
.mobile-menu .nav-item{min-height:46px;margin:0}
|
|
57
|
+
.mobile-menu .nav-group p{padding-inline:12px}
|
|
58
|
+
.mobile-menu-account{display:grid;gap:12px;margin-top:auto;padding-top:20px;border-top:1px solid var(--color-border)}
|
|
59
|
+
.mobile-menu-account p{overflow-wrap:anywhere;color:var(--color-muted);font-size:13px}
|
|
50
60
|
|
|
51
61
|
.console-layout{display:grid;grid-template-columns:var(--sidebar-width) minmax(0,1fr);min-height:calc(100dvh - var(--header-height))}
|
|
52
62
|
.console-sidebar{position:sticky;top:var(--header-height);display:flex;flex-direction:column;gap:24px;height:calc(100dvh - var(--header-height));overflow-y:auto;overscroll-behavior:contain;padding:24px;border-right:1px solid var(--color-border);background:var(--color-sidebar)}
|
|
@@ -54,6 +64,7 @@ const consoleCss = `
|
|
|
54
64
|
.nav-item{display:flex;align-items:center;gap:12px;min-height:38px;padding:8px 12px;margin-inline:-12px;border-radius:var(--radius-sm);color:var(--color-muted);font-size:13px;text-decoration:none}
|
|
55
65
|
.nav-item:hover{color:var(--color-text);background:var(--color-surface-2)}
|
|
56
66
|
.nav-item[aria-current=page]{color:var(--color-text);background:var(--color-surface-2);font-weight:500}
|
|
67
|
+
.nav-item[aria-current=page]>.ui-icon:first-child{color:var(--color-accent)}
|
|
57
68
|
.nav-item .ui-icon{width:18px;height:18px}
|
|
58
69
|
.nav-item .count{margin-left:auto;color:var(--color-muted);font-size:12px;font-weight:400;font-variant-numeric:tabular-nums}
|
|
59
70
|
.sidebar-usage{display:grid;gap:8px;margin-top:auto;padding-top:16px;border-top:1px solid var(--color-border);font-size:12px;color:var(--color-muted)}
|
|
@@ -70,7 +81,10 @@ const consoleCss = `
|
|
|
70
81
|
.page-header h1{font-size:clamp(28px,3vw,34px);line-height:1.15}
|
|
71
82
|
.lede{max-width:62ch;margin-top:8px;color:var(--color-muted);font-size:15px;text-wrap:pretty}
|
|
72
83
|
.page-actions{display:flex;align-items:center;flex-wrap:wrap;gap:8px}
|
|
73
|
-
.
|
|
84
|
+
.overview-header{display:block}
|
|
85
|
+
.overview-title{display:flex;align-items:center;justify-content:space-between;gap:16px}
|
|
86
|
+
.overview-title .page-actions{flex:none}
|
|
87
|
+
.stack{display:grid;grid-template-columns:minmax(0,1fr);min-width:0;gap:20px}
|
|
74
88
|
.split{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:20px}
|
|
75
89
|
.split.even{grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
76
90
|
.panel{min-width:0;padding:24px;border:1px solid var(--color-border);border-radius:18px;background:var(--color-surface)}
|
|
@@ -78,6 +92,60 @@ const consoleCss = `
|
|
|
78
92
|
.panel-header h2{font-size:17px;line-height:1.3}
|
|
79
93
|
.panel-header p{margin-top:4px;color:var(--color-muted);font-size:13px}
|
|
80
94
|
.panel-header>.pill,.panel-header>.btn{flex:none}
|
|
95
|
+
.dashboard-layout{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:20px;align-items:start}
|
|
96
|
+
.dashboard-aside{display:grid;gap:20px}
|
|
97
|
+
.section-label{margin-bottom:8px;color:var(--color-muted);font-size:12px;font-weight:500}
|
|
98
|
+
.workspace-summary{display:flex;align-items:center;gap:14px;min-width:0}
|
|
99
|
+
.workspace-avatar,.action-icon{display:grid;place-items:center;flex:none;width:40px;height:40px;border:1px solid var(--color-border);border-radius:12px;background:var(--color-surface-2);color:var(--color-muted)}
|
|
100
|
+
.workspace-avatar .ui-icon,.action-icon .ui-icon{width:18px;height:18px}
|
|
101
|
+
.workspace-summary h2{font-size:16px;overflow-wrap:anywhere}
|
|
102
|
+
.workspace-summary p{margin-top:3px;color:var(--color-muted);font-size:12px}
|
|
103
|
+
.workspace-summary>div:last-child{min-width:0}
|
|
104
|
+
.summary-links{display:grid;margin-top:20px;border-top:1px solid var(--color-border)}
|
|
105
|
+
.summary-link{display:flex;align-items:center;gap:10px;min-height:46px;border-bottom:1px solid var(--color-border);color:var(--color-text);font-size:13px;text-decoration:none}
|
|
106
|
+
.summary-link:last-child{border-bottom:0}
|
|
107
|
+
.summary-link .ui-icon{width:16px;height:16px;color:var(--color-muted)}
|
|
108
|
+
.summary-link .ui-icon:last-child{margin-left:auto}
|
|
109
|
+
.summary-link:hover{color:var(--color-accent)}
|
|
110
|
+
.activity-row{display:flex;align-items:center;gap:12px;padding:18px 0;border-bottom:1px solid var(--color-border)}
|
|
111
|
+
.activity-row:last-child{border-bottom:0;padding-bottom:0}
|
|
112
|
+
.activity-row>div:nth-child(2){min-width:0;flex:1}
|
|
113
|
+
.activity-row strong{display:block;font-size:14px;font-weight:500;overflow-wrap:anywhere}
|
|
114
|
+
.activity-row small{display:block;margin-top:5px;color:var(--color-muted);font-size:12px}
|
|
115
|
+
.activity-row .pill{font-size:11px}
|
|
116
|
+
.activity-row .icon-button{width:32px;height:32px}
|
|
117
|
+
.activity-row .icon-button .ui-icon{width:16px;height:16px}
|
|
118
|
+
.activity-empty{display:grid;justify-items:center;gap:10px;padding:32px 20px;text-align:center}
|
|
119
|
+
.activity-empty h3{margin-top:6px;font-size:16px}
|
|
120
|
+
.activity-empty p{max-width:36ch;color:var(--color-muted);font-size:13px}
|
|
121
|
+
.activity-empty .btn{margin-top:8px}
|
|
122
|
+
.action-icon[data-tone=ok]{border-color:var(--color-ok-border);background:var(--color-ok-bg);color:var(--color-ok)}
|
|
123
|
+
.action-icon[data-tone=danger]{border-color:var(--color-danger-border);background:var(--color-danger-bg);color:var(--color-danger)}
|
|
124
|
+
.action-icon[data-tone=warn]{border-color:var(--color-warn-border);background:var(--color-warn-bg);color:var(--color-warn)}
|
|
125
|
+
.approval-notice{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 20px;border:1px solid var(--color-warn-border);border-radius:14px;background:var(--color-warn-bg);font-size:13px}
|
|
126
|
+
.approval-notice p{margin-top:3px;color:var(--color-muted);font-size:12px}
|
|
127
|
+
.tool-row{display:flex;align-items:center;gap:12px;padding:13px 0;border-bottom:1px solid var(--color-border);color:var(--color-text);text-decoration:none}
|
|
128
|
+
.tool-row:last-child{border-bottom:0;padding-bottom:0}
|
|
129
|
+
.tool-row>div{flex:1;min-width:0}
|
|
130
|
+
.tool-row strong{display:block;font-size:13px;font-weight:500;overflow-wrap:anywhere}
|
|
131
|
+
.tool-row small{display:block;margin-top:3px;color:var(--color-muted);font-size:12px}
|
|
132
|
+
.tool-row>.ui-icon{width:16px;height:16px;color:var(--color-muted)}
|
|
133
|
+
.tool-row:hover strong{color:var(--color-accent)}
|
|
134
|
+
.docs-link{display:inline-flex;align-items:center;gap:7px;color:var(--color-accent);font-size:13px;text-decoration:none}
|
|
135
|
+
.docs-link:hover{text-decoration:underline}
|
|
136
|
+
.docs-link .ui-icon{width:15px;height:15px}
|
|
137
|
+
.workspace-context{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:18px 20px;border:1px solid var(--color-border);border-radius:14px;background:var(--color-sidebar)}
|
|
138
|
+
.access-layout{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:20px;align-items:start}
|
|
139
|
+
.endpoint{padding:14px 0;border-bottom:1px solid var(--color-border)}
|
|
140
|
+
.endpoint:last-child{border-bottom:0;padding-bottom:0}
|
|
141
|
+
.endpoint>div{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:13px}
|
|
142
|
+
.endpoint code{display:block;margin-top:6px;color:var(--color-muted);font:12px/1.6 var(--font-mono);overflow-wrap:anywhere}
|
|
143
|
+
.team-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}
|
|
144
|
+
.team-form>.field:first-child{grid-column:1/-1}
|
|
145
|
+
.team-form-footer{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:16px;grid-column:1/-1;padding-top:8px}
|
|
146
|
+
.team-form-footer p{max-width:44ch;color:var(--color-muted);font-size:12px}
|
|
147
|
+
.team-kit-secret{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:10px;padding:12px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-bg)}
|
|
148
|
+
.team-kit-secret code{min-width:0;overflow-wrap:anywhere;font-size:12px}
|
|
81
149
|
|
|
82
150
|
.metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));overflow:hidden;border:1px solid var(--color-border);border-radius:18px;background:var(--color-surface)}
|
|
83
151
|
.metric{min-width:0;padding:20px 24px;border-left:1px solid var(--color-border)}
|
|
@@ -87,6 +155,12 @@ const consoleCss = `
|
|
|
87
155
|
.metric-value[data-tone=ok]{color:var(--color-ok)}
|
|
88
156
|
.metric-value[data-tone=danger]{color:var(--color-danger)}
|
|
89
157
|
.metric-sub{margin-top:4px;color:var(--color-muted);font-size:12px}
|
|
158
|
+
.metric-link{display:block;color:var(--color-text);text-decoration:none;transition:background-color var(--motion-fast)}
|
|
159
|
+
.metric-link:hover{background:var(--color-surface-2)}
|
|
160
|
+
.metric-link:focus-visible{position:relative;z-index:1;outline-offset:-3px}
|
|
161
|
+
.metric-link .metric-label{display:flex;align-items:center;justify-content:space-between;gap:8px}
|
|
162
|
+
.metric-link .metric-label .ui-icon{width:13px;height:13px;color:var(--color-muted)}
|
|
163
|
+
.metric-value[data-tone=warn]{color:var(--color-warn)}
|
|
90
164
|
|
|
91
165
|
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:36px;padding:7px 16px;border:1px solid var(--color-border-strong);border-radius:var(--radius-pill);background:transparent;color:var(--color-text);font-size:13px;line-height:1.3;text-decoration:none;white-space:nowrap;transition:background-color var(--motion-fast),border-color var(--motion-fast),opacity var(--motion-fast)}
|
|
92
166
|
.btn:not(:disabled):hover{background:var(--color-surface-2);text-decoration:none}
|
|
@@ -116,6 +190,7 @@ input[type=search]::-webkit-search-cancel-button{display:none}
|
|
|
116
190
|
input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--color-button-primary)}
|
|
117
191
|
.form-grid{display:grid;gap:14px}
|
|
118
192
|
.form-row{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:12px}
|
|
193
|
+
.provider-key-form{grid-template-columns:minmax(0,1fr) minmax(0,1.4fr) auto;align-items:end;margin-bottom:16px}
|
|
119
194
|
.inline-form{display:flex;align-items:center;gap:8px}
|
|
120
195
|
.inline-form input{flex:1}
|
|
121
196
|
.checks{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
|
|
@@ -136,6 +211,13 @@ input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--color-bu
|
|
|
136
211
|
.search-field input{border:0;padding-left:0;background:transparent}
|
|
137
212
|
.search-field input:focus{box-shadow:none}
|
|
138
213
|
.search-field .ui-icon{width:16px;height:16px}
|
|
214
|
+
.search-field .clear-search{width:32px;height:32px;margin-right:4px}
|
|
215
|
+
.catalog-toolbar .search-field{width:min(420px,100%)}
|
|
216
|
+
.catalog-empty{display:grid;justify-items:center;gap:10px}
|
|
217
|
+
.catalog-empty h2{font-size:17px;color:var(--color-text)}
|
|
218
|
+
.catalog-empty p{max-width:38ch;font-size:13px}
|
|
219
|
+
.catalog-empty .btn{margin-top:6px}
|
|
220
|
+
.key-dismiss{float:right;margin:-6px -6px 4px 8px}
|
|
139
221
|
|
|
140
222
|
.pill{display:inline-flex;align-items:center;gap:6px;padding:1px 10px;border-radius:var(--radius-pill);background:var(--color-surface-2);color:var(--color-muted);font-size:12px;line-height:20px;white-space:nowrap;vertical-align:middle}
|
|
141
223
|
.pill.dot::before{content:"";width:6px;height:6px;flex:none;border-radius:50%;background:currentColor}
|
|
@@ -165,7 +247,7 @@ input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--color-bu
|
|
|
165
247
|
.empty-note{padding:20px 0;color:var(--color-muted);font-size:13px}
|
|
166
248
|
.key-value{display:block;margin:10px 0;padding:10px 12px;border-radius:var(--radius-sm);background:var(--color-bg);font-size:12.5px;overflow-wrap:anywhere}
|
|
167
249
|
|
|
168
|
-
.table-wrap{overflow-x:auto;border:1px solid var(--color-border);border-radius:18px;background:var(--color-surface)}
|
|
250
|
+
.table-wrap{position:relative;min-width:0;max-width:100%;overflow-x:auto;border:1px solid var(--color-border);border-radius:18px;background:var(--color-surface)}
|
|
169
251
|
.panel .table-wrap{border-radius:var(--radius-md)}
|
|
170
252
|
table{width:100%;border-collapse:collapse;text-align:left;font-size:13px;font-variant-numeric:tabular-nums}
|
|
171
253
|
th{padding:12px 16px;border-bottom:1px solid var(--color-border);color:var(--color-muted);font-size:12px;font-weight:500;white-space:nowrap}
|
|
@@ -185,6 +267,9 @@ th.right,.cell-actions{text-align:right}
|
|
|
185
267
|
.row strong{display:block;font-size:14px;font-weight:500;overflow-wrap:anywhere}
|
|
186
268
|
.row small{display:block;margin-top:2px;color:var(--color-muted);font-size:12px;overflow-wrap:anywhere}
|
|
187
269
|
.row>.btn,.row>.pill{flex:none}
|
|
270
|
+
.api-key-row{flex-wrap:wrap}
|
|
271
|
+
.api-key-row>.row-actions{max-width:100%;flex-wrap:wrap}
|
|
272
|
+
.api-key-row .pill{max-width:100%;overflow:hidden;text-overflow:ellipsis}
|
|
188
273
|
|
|
189
274
|
.ask{display:flex;align-items:center;gap:10px;padding:5px 5px 5px 16px;border:1px solid var(--color-control-border);border-radius:var(--radius-pill);background:var(--color-bg);color:var(--color-muted)}
|
|
190
275
|
.ask:focus-within{border-color:var(--color-accent);box-shadow:0 0 0 4px var(--color-accent-soft)}
|
|
@@ -235,50 +320,105 @@ body:has(dialog[open]){overflow:hidden}
|
|
|
235
320
|
.toast[data-tone=danger]{background:var(--color-button-danger);color:#fff}
|
|
236
321
|
|
|
237
322
|
.auth-view{display:grid;place-items:center;min-height:calc(100dvh - var(--header-height));padding:48px 20px}
|
|
238
|
-
|
|
239
|
-
.auth-
|
|
240
|
-
.auth-
|
|
241
|
-
.
|
|
242
|
-
.
|
|
243
|
-
.
|
|
244
|
-
.
|
|
245
|
-
.
|
|
323
|
+
body:not(:has(.console-topbar)) .auth-view{min-height:100dvh;padding:36px 20px}
|
|
324
|
+
.auth-card{width:min(460px,100%);padding:36px;border:1px solid var(--color-border);border-radius:20px;background:var(--color-surface);text-align:left;box-shadow:0 24px 64px rgba(0,0,0,.18)}
|
|
325
|
+
.auth-card.oauth-card{width:min(480px,100%);padding:0;overflow:hidden}
|
|
326
|
+
.oauth-card-top{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 24px;border-bottom:1px solid var(--color-border);background:var(--color-surface-2);color:var(--color-muted);font:400 11.5px/1.4 var(--font-mono)}
|
|
327
|
+
.oauth-brand{display:inline-flex;align-items:center;gap:8px;color:var(--color-text);text-decoration:none;font:600 15px/1.2 var(--font-sans);letter-spacing:var(--tracking-heading)}
|
|
328
|
+
.oauth-brand svg{width:20px;height:20px}
|
|
329
|
+
.oauth-top-meta{display:inline-flex;align-items:center;gap:10px}
|
|
330
|
+
.oauth-step-tag{padding:2px 8px;border:1px solid var(--color-border);border-radius:var(--radius-pill);background:var(--color-surface);color:var(--color-muted);font:400 11px/1.5 var(--font-mono)}
|
|
331
|
+
.oauth-theme-btn{width:30px;height:30px;border-radius:8px}
|
|
332
|
+
.oauth-theme-btn .ui-icon{width:15px;height:15px}
|
|
333
|
+
.oauth-card-body{padding:28px 28px 24px}
|
|
334
|
+
.oauth-card-foot{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;padding:14px 28px;border-top:1px solid var(--color-border);background:var(--color-surface-2);color:var(--color-muted);font-size:12px}
|
|
335
|
+
.oauth-card-foot strong{color:var(--color-text);font-weight:600}
|
|
336
|
+
.oauth-card-foot a{color:var(--color-accent);text-decoration:none}
|
|
337
|
+
.oauth-card-foot a:hover{text-decoration:underline}
|
|
338
|
+
.auth-mark{display:inline-grid;place-items:center;width:44px;height:44px;margin-bottom:16px;border:1px solid var(--color-border);border-radius:12px;background:var(--color-surface-2);color:var(--color-text)}
|
|
339
|
+
.auth-mark svg{width:24px;height:24px}
|
|
340
|
+
.auth-card h1{font-size:clamp(22px,2.6vw,26px);line-height:1.18;letter-spacing:var(--tracking-heading)}
|
|
341
|
+
.auth-card .lede{margin:8px 0 0;color:var(--color-muted);font-size:14px;line-height:1.55}
|
|
342
|
+
.auth-card .segmented{display:grid;grid-template-columns:1fr 1fr;width:100%;margin-top:20px}
|
|
343
|
+
.auth-form{display:grid;gap:14px;margin-top:20px;text-align:left}
|
|
344
|
+
.auth-alt{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;margin-top:18px;padding-top:16px;border-top:1px solid var(--color-border)}
|
|
246
345
|
.row-actions{display:inline-flex;align-items:center;gap:8px;flex:none}
|
|
247
|
-
.clerk-auth{display:flex;justify-content:center;min-height:120px;margin-top:
|
|
248
|
-
.clerk-loading{display:flex;align-items:center;gap:10px;align-self:center;margin:0;color:var(--color-muted);font-size:
|
|
346
|
+
.clerk-auth{display:flex;justify-content:center;min-height:120px;margin-top:18px;text-align:left}
|
|
347
|
+
.clerk-loading{display:flex;align-items:center;gap:10px;align-self:center;margin:0;color:var(--color-muted);font-size:14px}
|
|
249
348
|
.spinner{flex:none;width:18px;height:18px;border:2px solid var(--color-border);border-top-color:var(--color-text);border-radius:50%;animation:muxo-spin .8s linear infinite}
|
|
250
349
|
@keyframes muxo-spin{to{transform:rotate(360deg)}}
|
|
251
350
|
@media (prefers-reduced-motion:reduce){.spinner{animation:none}}
|
|
252
|
-
.auth-switch{margin-top:
|
|
351
|
+
.auth-switch{margin-top:8px}
|
|
253
352
|
.auth-switch:has([hidden]){display:none}
|
|
254
|
-
.auth-foot{margin-top:16px;color:var(--color-muted);font-size:12px}
|
|
353
|
+
.auth-foot{margin-top:16px;color:var(--color-muted);font-size:12px;line-height:1.5}
|
|
255
354
|
.auth-foot code{font-size:11.5px}
|
|
256
355
|
|
|
257
|
-
@media (max-width:1100px){.metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.metric:nth-child(3){border-left:0}.metric:nth-child(n+3){border-top:1px solid var(--color-border)}.split,.split.even{grid-template-columns:1fr}}
|
|
356
|
+
@media (max-width:1100px){.metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.metric:nth-child(3){border-left:0}.metric:nth-child(n+3){border-top:1px solid var(--color-border)}.split,.split.even,.dashboard-layout,.access-layout{grid-template-columns:1fr}.dashboard-aside{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
|
258
357
|
@media (max-width:900px){
|
|
259
358
|
.console-layout{grid-template-columns:1fr}
|
|
260
|
-
.console-sidebar{
|
|
261
|
-
.
|
|
262
|
-
.nav-item{flex:none;margin:0;white-space:nowrap}
|
|
359
|
+
.console-sidebar{display:none}
|
|
360
|
+
.mobile-menu-toggle{display:grid}
|
|
263
361
|
.console-main{padding:28px 20px 80px}
|
|
264
|
-
.topbar-links .nav-link,.
|
|
362
|
+
.topbar-links .nav-link,.topbar-links .account,.account-label{display:none}
|
|
363
|
+
.topbar-in{gap:12px}
|
|
364
|
+
.workspace-chip{max-width:300px;flex:1}.workspace-chip .tier{display:none}
|
|
365
|
+
.brand-section{display:none}
|
|
366
|
+
.catalog-toolbar{align-items:stretch}
|
|
367
|
+
.catalog-toolbar .search-field{width:100%}
|
|
368
|
+
.catalog-toolbar .segmented{width:100%;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));border-radius:var(--radius-md)}
|
|
369
|
+
.catalog-toolbar .segmented button{padding-inline:8px;white-space:normal;border-radius:var(--radius-sm)}
|
|
265
370
|
.checks{grid-template-columns:repeat(2,minmax(0,1fr))}
|
|
266
371
|
}
|
|
267
|
-
@media (max-width:560px){
|
|
372
|
+
@media (max-width:560px){
|
|
373
|
+
.console-main{padding:24px 16px 64px}
|
|
374
|
+
.page-header{margin-bottom:20px}
|
|
375
|
+
.overview-title{gap:8px}.overview-title h1{font-size:28px}
|
|
376
|
+
.overview-title .btn{padding-inline:12px}
|
|
377
|
+
.overview-header .lede{font-size:14px}
|
|
378
|
+
.metric{padding:16px}.metric-value{font-size:26px}
|
|
379
|
+
.metric-sub{font-size:11px}
|
|
380
|
+
.form-row,.team-form,.dashboard-aside{grid-template-columns:1fr}
|
|
381
|
+
.panel{padding:20px}.panel-header{gap:10px}.panel-header h2{font-size:16px}
|
|
382
|
+
.panel-header .btn{padding-inline:8px}
|
|
383
|
+
.auth-card{padding:28px 22px}.auth-card.oauth-card{padding:0}.oauth-card-top{padding:12px 18px}.oauth-card-body{padding:22px 18px 20px}.oauth-card-foot{padding:12px 18px}.inline-form{flex-wrap:wrap}
|
|
384
|
+
.topbar-in{gap:8px;padding-inline:12px}.topbar-links{gap:4px}
|
|
385
|
+
.workspace-chip{max-width:none;padding-inline:10px}.brand{font-size:18px;gap:5px}.brand svg{width:22px;height:22px}
|
|
386
|
+
.activity-row{display:grid;grid-template-columns:32px minmax(0,1fr) auto;gap:8px 10px}
|
|
387
|
+
.activity-row>.action-icon{width:32px;height:32px;grid-row:1/3;align-self:start}
|
|
388
|
+
.activity-row>div:nth-child(2){grid-column:2;grid-row:1}
|
|
389
|
+
.activity-row>.pill{grid-column:2;grid-row:2;justify-self:start}
|
|
390
|
+
.activity-row>.icon-button{grid-column:3;grid-row:1/3}
|
|
391
|
+
.activity-empty{padding:24px 8px}
|
|
392
|
+
.workspace-context{align-items:flex-start;flex-wrap:wrap}
|
|
393
|
+
.team-kit-secret{align-items:flex-start;flex-wrap:wrap}
|
|
394
|
+
.tool-grid{grid-template-columns:minmax(0,1fr)}
|
|
395
|
+
input[type=text],input[type=email],input[type=password],input[type=number],input[type=search],select,textarea{font-size:16px}
|
|
396
|
+
.provider-key-form{grid-template-columns:1fr}
|
|
397
|
+
}
|
|
268
398
|
@media (forced-colors:active){.btn,.chip,.segmented button,input,select,textarea{border:1px solid ButtonText}}
|
|
399
|
+
@media (hover:none){.btn,.chip,.segmented button,.icon-button,.workspace-chip,.nav-item{min-height:44px}.icon-button{min-width:44px}}
|
|
269
400
|
`;
|
|
270
401
|
const consoleScript = String.raw `
|
|
271
|
-
var VIEW_PATHS = { overview: '/', setup: '/keys', activity: '/activity', billing: '/billing', login: '/login', signup: '/signup' };
|
|
272
|
-
var VIEW_TITLES = { overview: '
|
|
402
|
+
var VIEW_PATHS = { overview: '/', catalog: '/catalog', setup: '/keys', workspaces: '/workspaces', activity: '/activity', billing: '/billing', login: '/login', signup: '/signup' };
|
|
403
|
+
var VIEW_TITLES = { overview: 'Overview', catalog: 'Tools', setup: 'API access', workspaces: 'Workspaces', activity: 'Activity', billing: 'Billing and credits', login: 'Sign in', signup: 'Create account' };
|
|
273
404
|
var LANE_LABELS = { composio_instant: 'Instant tool', composio_sdk: 'Connected app', stripe_projects: 'Cloud service' };
|
|
274
405
|
var STATUS_LABELS = {
|
|
275
406
|
executed: 'Completed',
|
|
276
407
|
succeeded: 'Completed',
|
|
408
|
+
completed: 'Completed',
|
|
277
409
|
guardrail_applied: 'Guardrail active',
|
|
278
410
|
memory_saved: 'Saved to memory',
|
|
279
411
|
planned_dry_run: 'Planned',
|
|
280
|
-
|
|
281
|
-
|
|
412
|
+
pending_approval: 'Needs your review',
|
|
413
|
+
awaiting_approval: 'Needs your review',
|
|
414
|
+
awaiting_oauth_connection: 'Connect app to continue',
|
|
415
|
+
running: 'In progress',
|
|
416
|
+
in_progress: 'In progress',
|
|
417
|
+
queued: 'In progress',
|
|
418
|
+
disabled: 'Not enabled',
|
|
419
|
+
not_enabled: 'Not enabled',
|
|
420
|
+
unknown: 'Could not verify',
|
|
421
|
+
unverified: 'Could not verify'
|
|
282
422
|
};
|
|
283
423
|
var DEFAULT_PARAM_LABELS = {
|
|
284
424
|
defaultRegion: 'Default cloud region',
|
|
@@ -332,9 +472,8 @@ function sanitizeForDisplay(val) {
|
|
|
332
472
|
return out;
|
|
333
473
|
}
|
|
334
474
|
|
|
335
|
-
var state = { view: 'overview', boot: null,
|
|
475
|
+
var state = { view: 'overview', boot: null, lane: 'all', factsMode: 'current', facts: null, authMode: 'login', activeMemoryDefaults: {}, plainEnglishGuardrails: null, billingInterval: 'month', planCatalog: null };
|
|
336
476
|
var currentTool = null;
|
|
337
|
-
var activeKeyHint = 'mk_live_...';
|
|
338
477
|
var externalApiKey = readToken();
|
|
339
478
|
var latestSpawnedKey = '';
|
|
340
479
|
var currentWorkspaceId = '';
|
|
@@ -342,6 +481,7 @@ var activeWorkspaceOverrideId = '';
|
|
|
342
481
|
var pendingModalPlan = null;
|
|
343
482
|
var pendingModalHandoff = null;
|
|
344
483
|
var toastTimer = null;
|
|
484
|
+
var catalogRequestId = 0;
|
|
345
485
|
var authConfig = { provider: 'password', clerk: null };
|
|
346
486
|
var clerk = null;
|
|
347
487
|
var clerkMounted = '';
|
|
@@ -374,8 +514,8 @@ function riskBadge(risk) {
|
|
|
374
514
|
function statusBadge(status) {
|
|
375
515
|
var s = String(status || 'unknown');
|
|
376
516
|
var tone = /^(active|succeeded|approved|auto_approved|completed|executed|guardrail_applied|memory_saved)$/.test(s) ? 'ok'
|
|
377
|
-
: /(fail|error|denied|rejected|blocked|revoked|expired)/.test(s) ? 'danger'
|
|
378
|
-
: /(pending|initiated|waiting|
|
|
517
|
+
: /(fail|error|denied|rejected|blocked|revoked|expired|unknown|unverified)/.test(s) ? 'danger'
|
|
518
|
+
: /(pending|initiated|waiting|awaiting)/.test(s) ? 'warn' : '';
|
|
379
519
|
return pill(STATUS_LABELS[s] || s.replace(/_/g, ' '), tone, true);
|
|
380
520
|
}
|
|
381
521
|
|
|
@@ -407,6 +547,11 @@ function applyTheme(theme) {
|
|
|
407
547
|
b.setAttribute('aria-pressed', String(theme === 'dark'));
|
|
408
548
|
b.setAttribute('aria-label', theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode');
|
|
409
549
|
}
|
|
550
|
+
if (clerk && clerkMounted && (state.view === 'login' || state.view === 'signup')) {
|
|
551
|
+
var prev = clerkMounted;
|
|
552
|
+
unmountClerkAuth();
|
|
553
|
+
mountClerkAuth(prev);
|
|
554
|
+
}
|
|
410
555
|
}
|
|
411
556
|
function toggleTheme() {
|
|
412
557
|
var next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
|
|
@@ -416,6 +561,10 @@ function toggleTheme() {
|
|
|
416
561
|
|
|
417
562
|
function openDialog(id) { var d = byId(id); if (d && !d.open) { if (d.showModal) d.showModal(); else d.setAttribute('open', ''); } }
|
|
418
563
|
function closeDialog(id) { var d = byId(id); if (d && d.open) { if (d.close) d.close(); else d.removeAttribute('open'); } }
|
|
564
|
+
function openMobileMenu() {
|
|
565
|
+
openDialog('mobile-menu');
|
|
566
|
+
byId('mobile-menu-toggle').setAttribute('aria-expanded', 'true');
|
|
567
|
+
}
|
|
419
568
|
function askInput(o) {
|
|
420
569
|
return new Promise(function (resolve) {
|
|
421
570
|
var d = byId('ask-dialog');
|
|
@@ -491,6 +640,8 @@ function navigate(view, opts) {
|
|
|
491
640
|
opts = opts || {};
|
|
492
641
|
if (!VIEW_PATHS[view]) view = 'overview';
|
|
493
642
|
var authView = view === 'login' || view === 'signup';
|
|
643
|
+
closeDialog('mobile-menu');
|
|
644
|
+
byId('mobile-menu-toggle').hidden = authView;
|
|
494
645
|
state.view = view;
|
|
495
646
|
byId('console-shell').hidden = authView;
|
|
496
647
|
byId('auth-view').hidden = !authView;
|
|
@@ -511,7 +662,8 @@ function navigate(view, opts) {
|
|
|
511
662
|
}
|
|
512
663
|
function loadView(view) {
|
|
513
664
|
var job = null;
|
|
514
|
-
if (view === 'overview' || view === 'setup') job = refreshOverview();
|
|
665
|
+
if (view === 'overview' || view === 'setup' || view === 'workspaces') job = refreshOverview();
|
|
666
|
+
else if (view === 'catalog') job = loadCatalog();
|
|
515
667
|
else if (view === 'activity') job = Promise.all([loadRuns(), loadPlans()]);
|
|
516
668
|
else if (view === 'billing') job = loadLedger();
|
|
517
669
|
if (job && job.catch) job.catch(showError);
|
|
@@ -656,13 +808,18 @@ function renderWorkspaceList(workspaces) {
|
|
|
656
808
|
}).join('') : '<p class="empty-note">Sign in or paste a workspace API key below to link a workspace.</p>';
|
|
657
809
|
var dialogBox = byId('workspace-dialog-list');
|
|
658
810
|
if (dialogBox) dialogBox.innerHTML = html;
|
|
659
|
-
var setupBox = byId('
|
|
811
|
+
var setupBox = byId('workspaces-list');
|
|
660
812
|
if (setupBox) setupBox.innerHTML = html;
|
|
661
813
|
}
|
|
662
814
|
async function switchExternalWorkspacePrompt() {
|
|
663
815
|
renderWorkspaceList();
|
|
664
816
|
openDialog('workspace-dialog');
|
|
665
817
|
}
|
|
818
|
+
async function openWorkspaceForm(kind) {
|
|
819
|
+
await switchExternalWorkspacePrompt();
|
|
820
|
+
var input = byId(kind === 'create' ? 'create-workspace-name-input' : 'join-workspace-key-input');
|
|
821
|
+
if (input) input.focus();
|
|
822
|
+
}
|
|
666
823
|
async function selectWorkspaceFromUi(workspaceId) {
|
|
667
824
|
if (!workspaceId) return;
|
|
668
825
|
activeWorkspaceOverrideId = workspaceId;
|
|
@@ -745,13 +902,14 @@ async function onboardTeamFromForm() {
|
|
|
745
902
|
var box = byId('team-kit-box');
|
|
746
903
|
if (box) {
|
|
747
904
|
box.hidden = false;
|
|
748
|
-
setText('team-kit-title',
|
|
905
|
+
setText('team-kit-title', (kit.teamName || teamName) + ' is ready');
|
|
906
|
+
setText('team-kit-workspace', (kit.workspace && kit.workspace.name) || (res.workspace && res.workspace.name) || '');
|
|
749
907
|
setText('team-kit-key', kit.apiKey || '');
|
|
750
908
|
setText('team-kit-cli', kit.cliSetupCommand || '');
|
|
751
909
|
setText('team-kit-instructions', kit.instructions || '');
|
|
752
910
|
}
|
|
753
911
|
if (teamInput) teamInput.value = '';
|
|
754
|
-
showToast('
|
|
912
|
+
showToast('Created team access for ' + teamName);
|
|
755
913
|
await refreshOverview();
|
|
756
914
|
}
|
|
757
915
|
async function setExternalWorkspaceKey(key, toastMsg) {
|
|
@@ -865,6 +1023,8 @@ function renderAccount(s) {
|
|
|
865
1023
|
byId('account-signin').hidden = signedIn;
|
|
866
1024
|
byId('account-signed-in').hidden = !signedIn;
|
|
867
1025
|
setText('account-label', user.email || user.name || 'Signed in');
|
|
1026
|
+
setText('mobile-account-label', user.email || user.name || 'Signed in');
|
|
1027
|
+
byId('mobile-account-actions').hidden = !signedIn;
|
|
868
1028
|
var badge = byId('workspace-auth-badge');
|
|
869
1029
|
if (badge) {
|
|
870
1030
|
badge.textContent = usingKey ? 'API key ' + externalApiKey.slice(0, 12) + '…' : signedIn ? 'Signed in' : 'Local workspace';
|
|
@@ -881,12 +1041,7 @@ function syncPolicyForm(policy) {
|
|
|
881
1041
|
if (byId('policy-ring')) byId('policy-ring').value = String(policy.executionRing != null ? policy.executionRing : 2);
|
|
882
1042
|
if (byId('policy-block-sql')) byId('policy-block-sql').checked = policy.blockDestructiveSql !== false;
|
|
883
1043
|
}
|
|
884
|
-
function renderIdentity(
|
|
885
|
-
if (!g) return;
|
|
886
|
-
setText('gov-did', g.agentDid || '');
|
|
887
|
-
var pub = g.publicKeyHex || g.ed25519PublicKey || '';
|
|
888
|
-
setText('gov-pubkey', pub ? pub.slice(0, 32) + '…' : '');
|
|
889
|
-
}
|
|
1044
|
+
function renderIdentity() {}
|
|
890
1045
|
function renderApiKeys(keys) {
|
|
891
1046
|
byId('api-keys-list').innerHTML = keys.length ? keys.map(function (k) {
|
|
892
1047
|
var revoked = Boolean(k.revokedAt);
|
|
@@ -895,16 +1050,31 @@ function renderApiKeys(keys) {
|
|
|
895
1050
|
k.role ? pill(k.role) : '',
|
|
896
1051
|
pill(k.environment === 'test' ? 'Test' : 'Live', k.environment === 'test' ? 'warn' : 'ok')
|
|
897
1052
|
].filter(Boolean).join(' ');
|
|
898
|
-
return '<div class="row"><div><strong>' + esc(k.name) + '</strong><small class="mono">' + esc(k.keyPrefix) + '</small></div>' +
|
|
1053
|
+
return '<div class="row api-key-row"><div><strong>' + esc(k.name) + '</strong><small class="mono">' + esc(k.keyPrefix) + '</small></div>' +
|
|
899
1054
|
(revoked ? pill('Revoked', 'danger') : '<span class="row-actions">' + metaBadges + ' ' +
|
|
900
1055
|
'<button class="btn btn-sm" type="button" data-action="revoke-key" data-id="' + esc(k.id) + '" data-name="' + esc(k.name) + '">Revoke</button></span>') + '</div>';
|
|
901
|
-
}).join('') : '<p class="empty-note">No keys yet. Create one to connect an agent or
|
|
1056
|
+
}).join('') : '<p class="empty-note">No API keys yet. Create one to connect an agent or app.</p>';
|
|
902
1057
|
}
|
|
903
1058
|
function renderRecentRuns(runs) {
|
|
904
|
-
byId('recent-runs').innerHTML = runs.length ? runs.slice(0,
|
|
1059
|
+
byId('recent-runs').innerHTML = runs.length ? runs.slice(0, 6).map(function (r) {
|
|
905
1060
|
var meta = [LANE_LABELS[r.lane] || '', timeAgo(r.createdAt || r.startedAt), r.durationMs != null ? r.durationMs + ' ms' : ''].filter(Boolean).join(' · ');
|
|
906
|
-
|
|
907
|
-
|
|
1061
|
+
var failed = /(fail|error|denied|rejected|blocked)/.test(r.status || '');
|
|
1062
|
+
var completed = /^(succeeded|completed|executed)$/.test(r.status || '');
|
|
1063
|
+
var tone = failed ? 'danger' : completed ? 'ok' : 'warn';
|
|
1064
|
+
var icon = failed ? '${uiIcon("close")}' : completed ? '${uiIcon("check")}' : '${uiIcon("activity")}';
|
|
1065
|
+
return '<div class="activity-row"><span class="action-icon" data-tone="' + tone + '">' + icon + '</span><div><strong>' + esc(formatToolLabel(r.toolSlug)) + '</strong><small>' + esc(meta) + '</small></div>' + statusBadge(r.status) +
|
|
1066
|
+
(r.receiptId ? '<button class="icon-button" type="button" data-action="inspect-receipt" data-id="' + esc(r.receiptId) + '" aria-label="Inspect audit record for ' + esc(formatToolLabel(r.toolSlug)) + '">${uiIcon("arrow")}</button>' : '') + '</div>';
|
|
1067
|
+
}).join('') : '<div class="activity-empty"><span class="action-icon">${uiIcon("shield")}</span><h3>No actions yet</h3><p>Choose a tool to get started. Every action leaves an audit trail.</p><a class="btn" href="/catalog" data-nav="catalog">Explore tools ${uiIcon("arrow")}</a></div>';
|
|
1068
|
+
var seen = {};
|
|
1069
|
+
var recentTools = runs.filter(function (r) {
|
|
1070
|
+
if (!r.toolSlug || seen[r.toolSlug]) return false;
|
|
1071
|
+
seen[r.toolSlug] = true;
|
|
1072
|
+
return true;
|
|
1073
|
+
}).slice(0, 4);
|
|
1074
|
+
byId('recent-tools').innerHTML = recentTools.length ? recentTools.map(function (r) {
|
|
1075
|
+
return '<a class="tool-row" href="/catalog" data-action="run-tool" data-slug="' + esc(r.toolSlug) + '"><div><strong>' + esc(formatToolLabel(r.toolSlug)) + '</strong><small>' + esc(LANE_LABELS[r.lane] || 'Tool') + '</small></div>${uiIcon("chevron")}</a>';
|
|
1076
|
+
}).join('') : '<a class="tool-row" href="/catalog" data-action="browse-lane" data-lane="composio_instant"><div><strong>Search & research</strong><small>Web, scraping, and data</small></div>${uiIcon("chevron")}</a><a class="tool-row" href="/catalog" data-action="browse-lane" data-lane="composio_sdk"><div><strong>Connected apps</strong><small>Tools for your team’s apps</small></div>${uiIcon("chevron")}</a><a class="tool-row" href="/catalog" data-action="browse-lane" data-lane="stripe_projects"><div><strong>Cloud services</strong><small>Provision and manage resources</small></div>${uiIcon("chevron")}</a>';
|
|
1077
|
+
setText('recent-tools-title', recentTools.length ? 'Recently used tools' : 'Explore tools');
|
|
908
1078
|
}
|
|
909
1079
|
function countActive(list) { return (list || []).filter(function (x) { return x.status === 'active'; }).length; }
|
|
910
1080
|
function setCount(id, n) { setText(id, n ? fmt(n) : ''); }
|
|
@@ -924,18 +1094,34 @@ async function refreshOverview() {
|
|
|
924
1094
|
var pending = plans.filter(function (p) { return p.approvalStatus === 'pending_approval'; }).length;
|
|
925
1095
|
var tier = String(org.tier || 'free');
|
|
926
1096
|
var tierLabel = tier.charAt(0).toUpperCase() + tier.slice(1) + ' plan';
|
|
1097
|
+
if (currentWorkspaceId && currentWorkspaceId !== org.id) {
|
|
1098
|
+
byId('new-key-banner').hidden = true;
|
|
1099
|
+
setText('new-key-value', '');
|
|
1100
|
+
byId('team-kit-box').hidden = true;
|
|
1101
|
+
['team-kit-key', 'team-kit-cli', 'team-kit-instructions', 'team-kit-workspace'].forEach(function (id) { setText(id, ''); });
|
|
1102
|
+
}
|
|
927
1103
|
currentWorkspaceId = org.id || '';
|
|
928
1104
|
setText('workspace-name', org.name || 'Workspace');
|
|
929
1105
|
setText('workspace-tier', tierLabel);
|
|
930
|
-
setText('workspace-slug', org.
|
|
1106
|
+
setText('workspace-slug', org.name || org.slug || 'Primary workspace');
|
|
1107
|
+
setText('overview-workspace-name', org.name || 'Workspace');
|
|
1108
|
+
setText('overview-workspace-tier', tierLabel);
|
|
1109
|
+
setText('access-workspace-name', org.name || 'Workspace');
|
|
1110
|
+
setText('workspace-count', fmt((s.workspaces || []).length) + ((s.workspaces || []).length === 1 ? ' workspace' : ' workspaces'));
|
|
1111
|
+
setText('kpi-pending', fmt(pending));
|
|
1112
|
+
byId('kpi-pending').dataset.tone = pending ? 'warn' : '';
|
|
1113
|
+
setText('kpi-pending-sub', pending ? 'Ready for your review' : 'You’re all caught up');
|
|
1114
|
+
byId('approval-notice').hidden = !pending;
|
|
1115
|
+
setText('approval-notice-title', fmt(pending) + (pending === 1 ? ' action needs approval' : ' actions need approval'));
|
|
1116
|
+
setText('api-base-url', window.location.origin + '/api/v1');
|
|
1117
|
+
setText('api-mcp-url', window.location.origin + '/mcp');
|
|
931
1118
|
setText('kpi-credits', fmt(credits));
|
|
932
1119
|
setText('kpi-tier-badge', tierLabel);
|
|
933
1120
|
setText('kpi-actions', fmt(used));
|
|
934
1121
|
setText('kpi-actions-sub', 'of ' + fmt(limit) + ' included');
|
|
935
1122
|
setText('kpi-connections', fmt(activeConns + activeRes));
|
|
936
|
-
setText('kpi-runs', fmt(runs.length));
|
|
937
1123
|
setText('meter-actions-text', fmt(used) + ' / ' + fmt(limit));
|
|
938
|
-
byId('meter-actions-bar').style.width = Math.min(100, Math.max(
|
|
1124
|
+
byId('meter-actions-bar').style.width = Math.min(100, Math.max(0, Math.round((used / Math.max(1, limit)) * 100))) + '%';
|
|
939
1125
|
setText('meter-credits-text', fmt(credits));
|
|
940
1126
|
setText('billing-plan', tierLabel);
|
|
941
1127
|
setText('billing-credits', fmt(credits));
|
|
@@ -949,8 +1135,6 @@ async function refreshOverview() {
|
|
|
949
1135
|
state.plainEnglishGuardrails = s.plainEnglishGuardrails || null;
|
|
950
1136
|
renderPlainEnglishGuardrails(state.plainEnglishGuardrails, org.policy);
|
|
951
1137
|
renderActiveMemoryDefaults(state.activeMemoryDefaults, s.activeGuardrails || (s.supermemory && s.supermemory.activeGuardrails) || []);
|
|
952
|
-
activeKeyHint = externalApiKey || s.defaultApiKey || ((s.apiKeys || [])[0] ? s.apiKeys[0].keyPrefix : 'mk_live_...');
|
|
953
|
-
setHarnessSnippet(state.harness);
|
|
954
1138
|
renderIdentity(s.governance);
|
|
955
1139
|
renderApiKeys(s.apiKeys || []);
|
|
956
1140
|
renderWorkspaceList(s.workspaces || []);
|
|
@@ -958,78 +1142,6 @@ async function refreshOverview() {
|
|
|
958
1142
|
return s;
|
|
959
1143
|
}
|
|
960
1144
|
|
|
961
|
-
function setHarnessSnippet(kind) {
|
|
962
|
-
state.harness = kind || 'plugin';
|
|
963
|
-
document.querySelectorAll('#harness-tabs button').forEach(function (b) { b.setAttribute('aria-pressed', String(b.dataset.kind === state.harness)); });
|
|
964
|
-
var el = byId('mcp-config-snippet');
|
|
965
|
-
var origin = window.location.origin;
|
|
966
|
-
var lines;
|
|
967
|
-
if (state.harness === 'plugin') {
|
|
968
|
-
lines = [
|
|
969
|
-
'# Claude Code',
|
|
970
|
-
'claude plugin marketplace add ' + origin + '/.claude-plugin/marketplace.json',
|
|
971
|
-
'claude plugin install muxo@muxo',
|
|
972
|
-
'',
|
|
973
|
-
'# OpenAI Codex',
|
|
974
|
-
'codex mcp add muxo --url ' + origin + '/mcp',
|
|
975
|
-
'',
|
|
976
|
-
'# Any agent with a terminal (Node.js 22+)',
|
|
977
|
-
'npx -y @muxoai/cli@latest login --signup --name "my-agent"'
|
|
978
|
-
];
|
|
979
|
-
} else if (state.harness === 'oauth') {
|
|
980
|
-
lines = [
|
|
981
|
-
'# Sign in from the CLI, then connect an app in your browser',
|
|
982
|
-
'npx -y @muxoai/cli@latest login --signup --name "my-agent" --url ' + origin,
|
|
983
|
-
'npx -y @muxoai/cli@latest whoami',
|
|
984
|
-
'npx -y @muxoai/cli@latest link github --wait',
|
|
985
|
-
'',
|
|
986
|
-
'# Check that your agent can reach Muxo',
|
|
987
|
-
'npx -y @muxoai/cli@latest harness'
|
|
988
|
-
];
|
|
989
|
-
} else if (state.harness === 'sdk') {
|
|
990
|
-
lines = [
|
|
991
|
-
'import { MuxoClient } from "@muxoai/sdk";',
|
|
992
|
-
'',
|
|
993
|
-
'const muxo = new MuxoClient({',
|
|
994
|
-
' baseUrl: "' + origin + '",',
|
|
995
|
-
' apiKey: process.env.MUXO_API_KEY || "' + activeKeyHint + '"',
|
|
996
|
-
'});',
|
|
997
|
-
'',
|
|
998
|
-
'const result = await muxo.do("Fetch top 3 stories on Hacker News");'
|
|
999
|
-
];
|
|
1000
|
-
} else if (state.harness === 'mastra') {
|
|
1001
|
-
lines = [
|
|
1002
|
-
'import { MCPClient } from "@mastra/mcp";',
|
|
1003
|
-
'',
|
|
1004
|
-
'export const muxo = new MCPClient({',
|
|
1005
|
-
' servers: {',
|
|
1006
|
-
' muxo: {',
|
|
1007
|
-
' url: new URL("' + origin + '/mcp"),',
|
|
1008
|
-
' requestInit: { headers: { Authorization: "Bearer ' + activeKeyHint + '" } }',
|
|
1009
|
-
' }',
|
|
1010
|
-
' }',
|
|
1011
|
-
'});'
|
|
1012
|
-
];
|
|
1013
|
-
} else if (state.harness === 'pi') {
|
|
1014
|
-
lines = [
|
|
1015
|
-
'# Pi coding agent',
|
|
1016
|
-
'curl -sL ' + origin + '/skill.md > ~/.pi/skills/muxo.md',
|
|
1017
|
-
'export MUXO_API_KEY="' + activeKeyHint + '"'
|
|
1018
|
-
];
|
|
1019
|
-
} else if (state.harness === 'curl') {
|
|
1020
|
-
lines = [
|
|
1021
|
-
'# Run any request in plain English over HTTPS',
|
|
1022
|
-
'curl -sX POST ' + origin + '/api/v1/do \\',
|
|
1023
|
-
' -H "Authorization: Bearer ' + activeKeyHint + '" \\',
|
|
1024
|
-
' -H "Content-Type: application/json" \\',
|
|
1025
|
-
' -d ' + JSON.stringify(JSON.stringify({ prompt: 'Audit https://muxo.ai for technical SEO' }))
|
|
1026
|
-
];
|
|
1027
|
-
} else {
|
|
1028
|
-
lines = [json({ mcpServers: { muxo: { url: origin + '/mcp', headers: { Authorization: 'Bearer ' + activeKeyHint } } } })];
|
|
1029
|
-
}
|
|
1030
|
-
el.textContent = lines.join('\n');
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
1145
|
function showNewKey(key, title, canSwitch) {
|
|
1034
1146
|
byId('new-key-banner').hidden = false;
|
|
1035
1147
|
setText('new-key-title', title);
|
|
@@ -1137,20 +1249,35 @@ function toolTile(t) {
|
|
|
1137
1249
|
'<div class="tool-foot"><span>' + esc(cost) + '</span><button class="btn btn-sm" data-action="run-tool" data-slug="' + esc(t.slug) + '">Plan and run</button></div></article>';
|
|
1138
1250
|
}
|
|
1139
1251
|
async function loadCatalog() {
|
|
1252
|
+
var requestId = ++catalogRequestId;
|
|
1140
1253
|
var q = byId('catalog-search').value.trim();
|
|
1141
1254
|
var grid = byId('catalog-grid');
|
|
1255
|
+
byId('clear-catalog-search').hidden = !q;
|
|
1142
1256
|
grid.setAttribute('aria-busy', 'true');
|
|
1143
1257
|
setText('catalog-status', 'Loading tools…');
|
|
1144
1258
|
try {
|
|
1145
1259
|
var data = await api('/api/v1/tools?query=' + encodeURIComponent(q) + '&lane=' + encodeURIComponent(state.lane) + '&limit=48');
|
|
1260
|
+
if (requestId !== catalogRequestId) return;
|
|
1146
1261
|
var tools = data.tools || [];
|
|
1147
1262
|
setText('nav-catalog-count', data.total ? fmt(data.total) : '');
|
|
1148
1263
|
setText('catalog-status', fmt(data.total != null ? data.total : tools.length) + ' tools' + (q ? ' matching "' + q + '"' : '') + (tools.length < (data.total || 0) ? ', showing ' + tools.length : ''));
|
|
1149
|
-
grid.innerHTML = tools.length ? tools.map(toolTile).join('') : '<div class="empty-state">No tools
|
|
1264
|
+
grid.innerHTML = tools.length ? tools.map(toolTile).join('') : '<div class="empty-state catalog-empty"><span class="action-icon">${uiIcon("search")}</span><h2>No matching tools</h2><p>Try another search or reset your filters.</p><button class="btn" type="button" data-action="reset-catalog">Reset filters</button></div>';
|
|
1265
|
+
} catch (err) {
|
|
1266
|
+
if (requestId !== catalogRequestId) return;
|
|
1267
|
+
setText('catalog-status', 'Tools could not be loaded.');
|
|
1268
|
+
grid.innerHTML = '<div class="empty-state catalog-empty"><span class="action-icon">${uiIcon("refresh")}</span><h2>Tools couldn’t be loaded</h2><p>Your workspace is unchanged. Try again when you’re ready.</p><button class="btn" type="button" data-action="retry-catalog">Try again</button></div>';
|
|
1269
|
+
throw err;
|
|
1150
1270
|
} finally {
|
|
1151
|
-
grid.removeAttribute('aria-busy');
|
|
1271
|
+
if (requestId === catalogRequestId) grid.removeAttribute('aria-busy');
|
|
1152
1272
|
}
|
|
1153
1273
|
}
|
|
1274
|
+
function resetCatalog(keepLane) {
|
|
1275
|
+
byId('catalog-search').value = '';
|
|
1276
|
+
byId('clear-catalog-search').hidden = true;
|
|
1277
|
+
if (!keepLane) setLane('all');
|
|
1278
|
+
byId('catalog-search').focus();
|
|
1279
|
+
return loadCatalog();
|
|
1280
|
+
}
|
|
1154
1281
|
|
|
1155
1282
|
async function openExecuteModal(slug) {
|
|
1156
1283
|
var tool = await api('/api/v1/tools/' + encodeURIComponent(slug));
|
|
@@ -1248,7 +1375,7 @@ async function submitPlanOnly() {
|
|
|
1248
1375
|
var planned = await post('/api/v1/plans', { toolSlug: currentTool.slug, input: input, reason: byId('modal-tool-reason').value });
|
|
1249
1376
|
renderModalOAuthHandoff(planned);
|
|
1250
1377
|
showModalResult(json(sanitizeForDisplay(planned)));
|
|
1251
|
-
showToast('Plan created. Review it in
|
|
1378
|
+
showToast('Plan created. Review it in Activity.');
|
|
1252
1379
|
await refreshOverview();
|
|
1253
1380
|
} catch (err) {
|
|
1254
1381
|
showModalResult('Error: ' + err.message);
|
|
@@ -1279,7 +1406,8 @@ async function loadResources() {
|
|
|
1279
1406
|
var data = await api('/api/v1/resources');
|
|
1280
1407
|
var list = data.resources || [];
|
|
1281
1408
|
setCount('nav-res-count', countActive(list));
|
|
1282
|
-
byId('resources-tbody')
|
|
1409
|
+
var tbody = byId('resources-tbody');
|
|
1410
|
+
if (tbody) tbody.innerHTML = list.length ? list.map(function (r) {
|
|
1283
1411
|
var serviceLabel = String(r.serviceSlug || 'Service').replace(/[_-]+/g, ' ');
|
|
1284
1412
|
var envCount = (r.envVarKeys || []).length;
|
|
1285
1413
|
var secretCell = envCount ? pill(envCount + (envCount === 1 ? ' secret in vault' : ' secrets in vault'), 'ok') : pill('Encrypted in vault', 'ok');
|
|
@@ -1319,7 +1447,7 @@ async function loadProvisioningOnboardingStatus() {
|
|
|
1319
1447
|
if (!res.connected || !res.account) {
|
|
1320
1448
|
badge.textContent = 'Not onboarded yet';
|
|
1321
1449
|
delete badge.dataset.tone;
|
|
1322
|
-
meta.textContent = '
|
|
1450
|
+
meta.textContent = 'Complete verification to provision managed databases and cloud resources in your workspace.';
|
|
1323
1451
|
return;
|
|
1324
1452
|
}
|
|
1325
1453
|
var acct = res.account;
|
|
@@ -1327,11 +1455,11 @@ async function loadProvisioningOnboardingStatus() {
|
|
|
1327
1455
|
? acct.configuration.developer.capabilities.projects.status
|
|
1328
1456
|
: 'active';
|
|
1329
1457
|
var dueList = (acct.requirements && (acct.requirements.currently_due || acct.requirements.entries)) || [];
|
|
1330
|
-
badge.textContent = projStatus === 'active' ? '
|
|
1458
|
+
badge.textContent = projStatus === 'active' ? 'Verified' : 'Verification (' + projStatus + ')';
|
|
1331
1459
|
badge.dataset.tone = projStatus === 'active' && dueList.length === 0 ? 'ok' : 'warn';
|
|
1332
1460
|
meta.textContent = dueList.length > 0
|
|
1333
|
-
? dueList.length + ' verification requirement(s) currently due. Complete
|
|
1334
|
-
: '
|
|
1461
|
+
? dueList.length + ' verification requirement(s) currently due. Complete onboarding below.'
|
|
1462
|
+
: 'Cloud resource provisioning is ' + projStatus + ' for this workspace.';
|
|
1335
1463
|
}
|
|
1336
1464
|
|
|
1337
1465
|
async function openEmbeddedOnboarding() {
|
|
@@ -1339,7 +1467,7 @@ async function openEmbeddedOnboarding() {
|
|
|
1339
1467
|
var mount = byId('stripe-embedded-onboarding-mount');
|
|
1340
1468
|
if (!box || !mount) return;
|
|
1341
1469
|
box.hidden = false;
|
|
1342
|
-
mount.innerHTML = '<p class="empty-note">
|
|
1470
|
+
mount.innerHTML = '<p class="empty-note">Preparing verification session…</p>';
|
|
1343
1471
|
var session = await post('/api/v1/provisioning/connected_account_sessions', {
|
|
1344
1472
|
auto_create: true,
|
|
1345
1473
|
enable_account_management: true,
|
|
@@ -1374,33 +1502,32 @@ async function openEmbeddedOnboarding() {
|
|
|
1374
1502
|
}
|
|
1375
1503
|
if (typeof onboardingEl.setOnExit === 'function') {
|
|
1376
1504
|
onboardingEl.setOnExit(function () {
|
|
1377
|
-
showToast('
|
|
1505
|
+
showToast('Verification step saved');
|
|
1378
1506
|
loadProvisioningOnboardingStatus().catch(function () {});
|
|
1379
1507
|
});
|
|
1380
1508
|
}
|
|
1381
1509
|
mount.innerHTML = '';
|
|
1382
1510
|
mount.appendChild(bannerEl);
|
|
1383
1511
|
mount.appendChild(onboardingEl);
|
|
1384
|
-
showToast('
|
|
1512
|
+
showToast('Verification form ready');
|
|
1385
1513
|
return;
|
|
1386
1514
|
} catch (err) {
|
|
1387
1515
|
console.error(err);
|
|
1388
1516
|
}
|
|
1389
1517
|
}
|
|
1390
1518
|
mount.innerHTML = '<div class="result-card">' +
|
|
1391
|
-
'<div class="result-head"><div><strong>
|
|
1392
|
-
'<div class="result-meta">
|
|
1519
|
+
'<div class="result-head"><div><strong>Account verification session ready</strong>' +
|
|
1520
|
+
'<div class="result-meta">Cloud resource provisioning verification</div></div>' +
|
|
1393
1521
|
pill('Session active', 'ok') + '</div>' +
|
|
1394
1522
|
'<div class="result-body">' +
|
|
1395
|
-
'<div class="result-kv"><span>
|
|
1396
|
-
'<div class="result-kv"><span>
|
|
1397
|
-
'<div class="result-kv"><span>Connect.js mount</span><strong>' + (session.publishable_key ? 'Ready' : 'Set STRIPE_PUBLISHABLE_KEY for live iframe, or use Hosted Link') + '</strong></div>' +
|
|
1523
|
+
'<div class="result-kv"><span>Status</span><strong>Ready for verification</strong></div>' +
|
|
1524
|
+
'<div class="result-kv"><span>Flow</span><strong>' + (session.publishable_key ? 'Embedded verification' : 'Hosted verification link') + '</strong></div>' +
|
|
1398
1525
|
'</div>' +
|
|
1399
1526
|
'<div class="result-actions" style="margin-top:14px;display:flex;gap:10px;flex-wrap:wrap">' +
|
|
1400
|
-
'<button class="btn btn-sm btn-primary" type="button" data-action="open-hosted-onboarding">Open
|
|
1401
|
-
'<button class="btn btn-sm" type="button" data-action="refresh-onboarding-status">Refresh
|
|
1527
|
+
'<button class="btn btn-sm btn-primary" type="button" data-action="open-hosted-onboarding">Open verification link</button>' +
|
|
1528
|
+
'<button class="btn btn-sm" type="button" data-action="refresh-onboarding-status">Refresh status</button>' +
|
|
1402
1529
|
'</div></div>';
|
|
1403
|
-
showToast('
|
|
1530
|
+
showToast('Verification session ready');
|
|
1404
1531
|
}
|
|
1405
1532
|
|
|
1406
1533
|
async function openHostedOnboardingLink() {
|
|
@@ -1412,13 +1539,11 @@ async function openHostedOnboardingLink() {
|
|
|
1412
1539
|
});
|
|
1413
1540
|
await loadProvisioningOnboardingStatus();
|
|
1414
1541
|
if (link && link.url) {
|
|
1415
|
-
showDetail('
|
|
1416
|
-
account: link.account,
|
|
1417
|
-
object: link.object,
|
|
1542
|
+
showDetail('Verification link', 'Complete verification to provision cloud resources', {
|
|
1418
1543
|
onboardingUrl: link.url,
|
|
1419
1544
|
expiresAt: link.expires_at
|
|
1420
1545
|
});
|
|
1421
|
-
showToast('
|
|
1546
|
+
showToast('Verification link ready');
|
|
1422
1547
|
}
|
|
1423
1548
|
}
|
|
1424
1549
|
async function rotateResource(name) {
|
|
@@ -1438,12 +1563,13 @@ async function pullWorkspaceEnv() {
|
|
|
1438
1563
|
|
|
1439
1564
|
async function loadConnections(syncLive) {
|
|
1440
1565
|
var tbody = byId('connections-tbody');
|
|
1441
|
-
if (state.view === 'connections' && syncLive) tbody.innerHTML = emptyRow(5, 'Checking each provider…');
|
|
1566
|
+
if (tbody && state.view === 'connections' && syncLive) tbody.innerHTML = emptyRow(5, 'Checking each provider…');
|
|
1442
1567
|
var data = await api('/api/v1/connections?sync=' + (syncLive ? 'true' : 'false'));
|
|
1443
1568
|
var list = data.connections || [];
|
|
1444
1569
|
var activeConns = countActive(list);
|
|
1445
1570
|
setCount('nav-conn-count', activeConns);
|
|
1446
1571
|
if (state.boot) setText('kpi-connections', fmt(activeConns + countActive(state.boot.resources)));
|
|
1572
|
+
if (!tbody) return;
|
|
1447
1573
|
tbody.innerHTML = list.length ? list.map(function (c) {
|
|
1448
1574
|
var acct = esc(c.externalAccountId || '');
|
|
1449
1575
|
var prov = esc(c.providerSlug);
|
|
@@ -1458,8 +1584,8 @@ async function loadConnections(syncLive) {
|
|
|
1458
1584
|
}
|
|
1459
1585
|
async function startCustomProviderConnection() {
|
|
1460
1586
|
var input = byId('custom-provider-input');
|
|
1461
|
-
var val = (input.value
|
|
1462
|
-
if (!val) { showToast('Enter an app name, like linear or jira'); input.focus(); return; }
|
|
1587
|
+
var val = (input && input.value ? input.value : '').trim().toLowerCase();
|
|
1588
|
+
if (!val) { showToast('Enter an app name, like linear or jira'); if (input) input.focus(); return; }
|
|
1463
1589
|
input.value = '';
|
|
1464
1590
|
await startAppConnection(val);
|
|
1465
1591
|
}
|
|
@@ -1479,7 +1605,7 @@ async function startAppConnection(provider) {
|
|
|
1479
1605
|
var conn = res.connection || {};
|
|
1480
1606
|
if (conn.redirectUrl) window.open(conn.redirectUrl, '_blank', 'noopener');
|
|
1481
1607
|
showToast(conn.redirectUrl ? 'Finish connecting ' + provider + ' in the new tab' : (conn.message || 'Started connecting ' + provider));
|
|
1482
|
-
|
|
1608
|
+
await refreshOverview();
|
|
1483
1609
|
}
|
|
1484
1610
|
|
|
1485
1611
|
function setFactsMode(mode) {
|
|
@@ -1514,7 +1640,7 @@ function renderActiveMemoryDefaults(defaults, guardrails) {
|
|
|
1514
1640
|
var keys = Object.keys(defs).filter(function (k) { return defs[k] != null && defs[k] !== ''; });
|
|
1515
1641
|
var rules = (guardrails || []).filter(Boolean);
|
|
1516
1642
|
if (!keys.length && !rules.length) {
|
|
1517
|
-
box.innerHTML = '<p class="empty-note">No
|
|
1643
|
+
box.innerHTML = '<p class="empty-note">No saved workspace defaults.</p>';
|
|
1518
1644
|
return;
|
|
1519
1645
|
}
|
|
1520
1646
|
var html = [];
|
|
@@ -1526,7 +1652,7 @@ function renderActiveMemoryDefaults(defaults, guardrails) {
|
|
|
1526
1652
|
}
|
|
1527
1653
|
if (rules.length) {
|
|
1528
1654
|
html.push('<div class="recall-group"><h3>Remembered workspace guardrails</h3><div class="rows">' + rules.map(function (r) {
|
|
1529
|
-
return '<div class="row"><div><strong>' + esc(r) + '</strong><small>
|
|
1655
|
+
return '<div class="row"><div><strong>' + esc(r) + '</strong><small>Applies to this workspace</small></div>' + pill('Active rule', 'ok', true) + '</div>';
|
|
1530
1656
|
}).join('') + '</div></div>');
|
|
1531
1657
|
}
|
|
1532
1658
|
box.innerHTML = html.join('');
|
|
@@ -1538,7 +1664,7 @@ async function teachMemoryFromUi(chipPrompt) {
|
|
|
1538
1664
|
if (input) input.value = promptText;
|
|
1539
1665
|
var res = await post('/api/v1/do', { prompt: promptText });
|
|
1540
1666
|
if (input && typeof chipPrompt !== 'string') input.value = '';
|
|
1541
|
-
showToast(res.humanMessage || 'Saved preference to
|
|
1667
|
+
showToast(res.humanMessage || 'Saved preference to workspace memory');
|
|
1542
1668
|
await loadMemory();
|
|
1543
1669
|
await refreshOverview();
|
|
1544
1670
|
}
|
|
@@ -1715,15 +1841,17 @@ async function loadPlans() {
|
|
|
1715
1841
|
var pending = plans.filter(function (p) { return p.approvalStatus === 'pending_approval'; }).length;
|
|
1716
1842
|
setText('gov-pending', fmt(pending));
|
|
1717
1843
|
setCount('nav-plan-count', pending);
|
|
1718
|
-
byId('plans-tbody')
|
|
1844
|
+
var tbody = byId('plans-tbody');
|
|
1845
|
+
if (tbody) tbody.innerHTML = plans.length ? plans.map(function (p) {
|
|
1719
1846
|
var verdict = p.decisionRecord ? p.decisionRecord.verdict : 'allow';
|
|
1720
1847
|
var verdictLabel = verdict === 'deny' ? 'Blocked' : verdict === 'require_approval' ? 'Needs approval' : 'Allowed';
|
|
1721
1848
|
var id = esc(p.id);
|
|
1849
|
+
var inspectBtn = '<button class="btn btn-sm" type="button" data-action="inspect-plan" data-id="' + id + '">Inspect</button>';
|
|
1722
1850
|
var action = p.approvalStatus === 'pending_approval'
|
|
1723
|
-
? '<button class="btn btn-sm btn-primary" data-action="approve-plan" data-id="' + id + '">Approve and run</button>'
|
|
1851
|
+
? inspectBtn + ' <button class="btn btn-sm" type="button" data-action="reject-plan" data-id="' + id + '">Reject</button> <button class="btn btn-sm btn-primary" type="button" data-action="approve-plan" data-id="' + id + '">Approve and run</button>'
|
|
1724
1852
|
: (p.approvalStatus === 'approved' || p.approvalStatus === 'auto_approved')
|
|
1725
|
-
? '<button class="btn btn-sm" data-action="execute-plan" data-id="' + id + '">Run</button>'
|
|
1726
|
-
:
|
|
1853
|
+
? inspectBtn + ' <button class="btn btn-sm btn-primary" type="button" data-action="execute-plan" data-id="' + id + '">Run</button>'
|
|
1854
|
+
: inspectBtn;
|
|
1727
1855
|
return '<tr id="plan-row-' + id + '"><td class="mono small">' + esc(shortId(p.id)) + '</td><td><strong>' + esc(formatToolLabel(p.toolSlug)) + '</strong></td>' +
|
|
1728
1856
|
'<td>' + riskBadge(p.riskLevel) + ' ' + pill(verdictLabel, verdict === 'deny' ? 'danger' : '') + '</td>' +
|
|
1729
1857
|
'<td>' + statusBadge(p.approvalStatus) + '</td><td class="cell-actions">' + action + '</td></tr>';
|
|
@@ -1734,10 +1862,23 @@ async function loadPlans() {
|
|
|
1734
1862
|
if (row) {
|
|
1735
1863
|
row.style.background = 'rgba(99, 102, 241, 0.14)';
|
|
1736
1864
|
row.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
1737
|
-
showToast('This plan is waiting for your
|
|
1865
|
+
showToast('This plan is waiting for your review.');
|
|
1738
1866
|
}
|
|
1739
1867
|
}
|
|
1740
1868
|
}
|
|
1869
|
+
async function inspectPlan(planId) {
|
|
1870
|
+
var data = await api('/api/v1/plans/' + encodeURIComponent(planId));
|
|
1871
|
+
var p = data.plan || data;
|
|
1872
|
+
showDetail('Action plan', shortId(planId), p,
|
|
1873
|
+
riskBadge(p.riskLevel) + ' ' + statusBadge(p.approvalStatus) + ' ' +
|
|
1874
|
+
pill((p.creditCost != null ? fmt(p.creditCost) : '0') + ' credits'));
|
|
1875
|
+
}
|
|
1876
|
+
async function rejectPlan(planId) {
|
|
1877
|
+
await post('/api/v1/plans/' + encodeURIComponent(planId) + '/approve', { decision: 'rejected' });
|
|
1878
|
+
showToast('Plan rejected. Nothing was executed.');
|
|
1879
|
+
await loadPlans();
|
|
1880
|
+
await refreshOverview();
|
|
1881
|
+
}
|
|
1741
1882
|
async function approveAndRun(planId) {
|
|
1742
1883
|
await post('/api/v1/plans/' + planId + '/approve');
|
|
1743
1884
|
await executeExistingPlan(planId);
|
|
@@ -1794,7 +1935,8 @@ async function loadRuns() {
|
|
|
1794
1935
|
var data = await api('/api/v1/runs');
|
|
1795
1936
|
var runs = data.runs || [];
|
|
1796
1937
|
setCount('nav-run-count', runs.length);
|
|
1797
|
-
byId('runs-tbody')
|
|
1938
|
+
var tbody = byId('runs-tbody');
|
|
1939
|
+
if (tbody) tbody.innerHTML = runs.length ? runs.map(function (r) {
|
|
1798
1940
|
return '<tr><td><span class="mono small">' + esc(shortId(r.id)) + '</span><br><span class="small muted">' + esc(timeAgo(r.createdAt || r.startedAt)) + '</span></td>' +
|
|
1799
1941
|
'<td><strong>' + esc(formatToolLabel(r.toolSlug)) + '</strong><br>' + laneBadge(r.lane) + '</td>' +
|
|
1800
1942
|
'<td>' + riskBadge(r.riskLevel) + '</td><td>' + statusBadge(r.status) + '</td>' +
|
|
@@ -1822,14 +1964,16 @@ function renderSettlement(s) {
|
|
|
1822
1964
|
var runsCount = Number(x.runsCount || 0);
|
|
1823
1965
|
return '<div class="row"><div><strong>' + label + '</strong><small>' + fmt(runsCount) + (runsCount === 1 ? ' run' : ' runs') + '</small></div>' + pill(runsCount ? 'Active' : 'No runs yet', runsCount ? 'ok' : '') + '</div>';
|
|
1824
1966
|
}
|
|
1825
|
-
byId('settlement-summary-box')
|
|
1967
|
+
var summaryBox = byId('settlement-summary-box');
|
|
1968
|
+
if (summaryBox) summaryBox.innerHTML = '<div class="rows">' + lane('composio_instant', 'Instant tools') + lane('composio_sdk', 'Connected apps') + lane('stripe_projects', 'Cloud services') + '</div>' +
|
|
1826
1969
|
'<p class="small muted" style="margin-top:12px">' + fmt(s.totalCreditsConsumed || 0) + ' total credits used across all providers.</p>';
|
|
1827
1970
|
}
|
|
1828
1971
|
async function loadLedger() {
|
|
1829
1972
|
var data = await api('/api/v1/billing/ledger');
|
|
1830
1973
|
renderSettlement(data.settlementSummary);
|
|
1831
1974
|
var entries = data.entries || [];
|
|
1832
|
-
byId('ledger-tbody')
|
|
1975
|
+
var tbody = byId('ledger-tbody');
|
|
1976
|
+
if (tbody) tbody.innerHTML = entries.length ? entries.map(function (e) {
|
|
1833
1977
|
var delta = Number(e.creditsDelta || 0);
|
|
1834
1978
|
return '<tr><td class="small muted">' + esc(new Date(e.createdAt).toLocaleString()) + '</td><td>' + esc(e.description) + '</td>' +
|
|
1835
1979
|
'<td class="mono" style="color:' + (delta >= 0 ? 'var(--color-ok)' : 'var(--color-text)') + '">' + (delta >= 0 ? '+' : '') + esc(fmt(delta)) + '</td>' +
|
|
@@ -1843,9 +1987,12 @@ async function loadByokKeys() {
|
|
|
1843
1987
|
var keys = (data.keys || []).filter(function (k) { return k.configured !== false && (k.keyPreview || k.keyHint); });
|
|
1844
1988
|
var hasSupplier = keys.some(function (k) { return k.category === 'supplier'; });
|
|
1845
1989
|
var badge = byId('byok-mode-badge');
|
|
1846
|
-
badge
|
|
1847
|
-
|
|
1848
|
-
|
|
1990
|
+
if (badge) {
|
|
1991
|
+
badge.textContent = hasSupplier ? 'Your keys · 0 credits' : 'Muxo credits';
|
|
1992
|
+
if (hasSupplier) badge.dataset.tone = 'accent'; else delete badge.dataset.tone;
|
|
1993
|
+
}
|
|
1994
|
+
var tbody = byId('byok-keys-tbody');
|
|
1995
|
+
if (tbody) tbody.innerHTML = keys.length ? keys.map(function (k) {
|
|
1849
1996
|
var slug = k.provider || k.providerSlug || '';
|
|
1850
1997
|
return '<tr><td><strong>' + esc(k.providerName || k.displayName || slug) + '</strong></td>' +
|
|
1851
1998
|
'<td>' + pill(k.category === 'llm' ? 'Language model' : 'Provider', k.category === 'llm' ? 'accent' : '') + '</td>' +
|
|
@@ -1902,7 +2049,7 @@ async function runNaturalLanguagePrompt() {
|
|
|
1902
2049
|
}
|
|
1903
2050
|
if (res.status === 'memory_saved') {
|
|
1904
2051
|
renderQuickResult({
|
|
1905
|
-
title: 'Saved to
|
|
2052
|
+
title: 'Saved to workspace memory',
|
|
1906
2053
|
subtitle: res.humanMessage || promptText,
|
|
1907
2054
|
badgeHtml: statusBadge('memory_saved'),
|
|
1908
2055
|
kv: [
|
|
@@ -1912,8 +2059,8 @@ async function runNaturalLanguagePrompt() {
|
|
|
1912
2059
|
output: { activeDefaults: res.activeDefaults, facts: res.temporalFacts },
|
|
1913
2060
|
raw: res
|
|
1914
2061
|
});
|
|
1915
|
-
setText('quick-run-status', res.humanMessage || 'Saved to
|
|
1916
|
-
showToast(res.humanMessage || 'Saved to
|
|
2062
|
+
setText('quick-run-status', res.humanMessage || 'Saved to workspace memory');
|
|
2063
|
+
showToast(res.humanMessage || 'Saved to workspace memory');
|
|
1917
2064
|
await refreshOverview();
|
|
1918
2065
|
return;
|
|
1919
2066
|
}
|
|
@@ -2091,7 +2238,9 @@ async function checkCheckoutReturn() {
|
|
|
2091
2238
|
|
|
2092
2239
|
var ACTIONS = {
|
|
2093
2240
|
'toggle-theme': toggleTheme,
|
|
2094
|
-
'
|
|
2241
|
+
'mobile-menu': openMobileMenu,
|
|
2242
|
+
'sign-out': function () { closeDialog('mobile-menu'); return signOut(); },
|
|
2243
|
+
'refresh-overview': refreshOverview,
|
|
2095
2244
|
'switch-workspace': switchExternalWorkspacePrompt,
|
|
2096
2245
|
'select-workspace': function (el) { return selectWorkspaceFromUi(el.dataset.id); },
|
|
2097
2246
|
'spawn-agent': spawnAutonomousAgent,
|
|
@@ -2099,12 +2248,22 @@ var ACTIONS = {
|
|
|
2099
2248
|
'revoke-key': function (el) { return revokeApiKey(el.dataset.id, el.dataset.name); },
|
|
2100
2249
|
'use-spawned': useLatestSpawnedKey,
|
|
2101
2250
|
'claim-link': createClaimLinkPrompt,
|
|
2102
|
-
'
|
|
2251
|
+
'workspace-create': function () { return openWorkspaceForm('create'); },
|
|
2252
|
+
'workspace-join': function () { return openWorkspaceForm('join'); },
|
|
2103
2253
|
'copy': function (el) { return copyFrom(el.dataset.target); },
|
|
2254
|
+
'dismiss-key': function () {
|
|
2255
|
+
byId('new-key-banner').hidden = true;
|
|
2256
|
+
setText('new-key-value', '');
|
|
2257
|
+
latestSpawnedKey = '';
|
|
2258
|
+
},
|
|
2104
2259
|
'run-tool': function (el) { return openExecuteModal(el.dataset.slug); },
|
|
2105
2260
|
'quick-run': function (el) { return quickRun(el.dataset.slug, JSON.parse(el.dataset.input || '{}')); },
|
|
2106
2261
|
'ask-suggest': function (el) { return fillAndRunNl(el.dataset.prompt); },
|
|
2107
2262
|
'lane': function (el) { setLane(el.dataset.lane); return loadCatalog(); },
|
|
2263
|
+
'browse-lane': function (el) { setLane(el.dataset.lane); navigate('catalog'); },
|
|
2264
|
+
'reset-catalog': function () { return resetCatalog(false); },
|
|
2265
|
+
'clear-search': function () { return resetCatalog(true); },
|
|
2266
|
+
'retry-catalog': loadCatalog,
|
|
2108
2267
|
'connect-app': function (el) { return startAppConnection(el.dataset.provider); },
|
|
2109
2268
|
'sync-connections': function () { return loadConnections(true); },
|
|
2110
2269
|
'wait-connection': function (el) { return waitConnectionInUi(el.dataset.provider, el.dataset.account); },
|
|
@@ -2123,6 +2282,8 @@ var ACTIONS = {
|
|
|
2123
2282
|
'teach-chip': function (el) { return teachMemoryFromUi(el.dataset.prompt); },
|
|
2124
2283
|
'guardrail-chip': function (el) { return applyGuardrailFromUi(el.dataset.prompt); },
|
|
2125
2284
|
'guardrail-reset': resetGuardrailsFromUi,
|
|
2285
|
+
'inspect-plan': function (el) { return inspectPlan(el.dataset.id); },
|
|
2286
|
+
'reject-plan': function (el) { return rejectPlan(el.dataset.id); },
|
|
2126
2287
|
'approve-plan': function (el) { return approveAndRun(el.dataset.id); },
|
|
2127
2288
|
'billing-interval': function (el) { setBillingInterval(el.dataset.interval); },
|
|
2128
2289
|
'change-plan': function (el) { return changePlan(el.dataset.tier); },
|
|
@@ -2130,7 +2291,7 @@ var ACTIONS = {
|
|
|
2130
2291
|
'execute-plan': function (el) { return executeExistingPlan(el.dataset.id); },
|
|
2131
2292
|
'kill-resume': resumeKillSwitch,
|
|
2132
2293
|
'refresh-governance': loadPlans,
|
|
2133
|
-
'refresh-runs': loadRuns,
|
|
2294
|
+
'refresh-runs': function () { return Promise.all([loadRuns(), loadPlans()]); },
|
|
2134
2295
|
'inspect-receipt': function (el) { return inspectReceipt(el.dataset.id); },
|
|
2135
2296
|
'checkout': function (el) { return startCheckout(el.dataset.kind); },
|
|
2136
2297
|
'delete-byok': function (el) { return deleteByokKeyFromUi(el.dataset.provider); },
|
|
@@ -2151,6 +2312,7 @@ function onClick(e) {
|
|
|
2151
2312
|
}
|
|
2152
2313
|
var el = e.target.closest('[data-action]');
|
|
2153
2314
|
if (!el) return;
|
|
2315
|
+
if (el.tagName === 'A' && (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)) return;
|
|
2154
2316
|
var fn = ACTIONS[el.dataset.action];
|
|
2155
2317
|
if (!fn) return;
|
|
2156
2318
|
e.preventDefault();
|
|
@@ -2182,14 +2344,15 @@ async function boot(initial) {
|
|
|
2182
2344
|
if (err.status === 401 || err.status === 403) return;
|
|
2183
2345
|
showError(err);
|
|
2184
2346
|
}
|
|
2185
|
-
if (initial !== 'overview' && initial !== 'setup') loadView(initial);
|
|
2347
|
+
if (initial !== 'overview' && initial !== 'setup' && initial !== 'workspaces') loadView(initial);
|
|
2186
2348
|
loadByokKeys().catch(function () {});
|
|
2187
2349
|
}
|
|
2188
2350
|
function init() {
|
|
2189
|
-
applyTheme(document.documentElement.dataset.theme === '
|
|
2351
|
+
applyTheme(document.documentElement.dataset.theme === 'light' ? 'light' : 'dark');
|
|
2190
2352
|
document.querySelectorAll('dialog.sheet').forEach(function (d) {
|
|
2191
2353
|
d.addEventListener('click', function (e) { if (e.target === d) d.close(); });
|
|
2192
2354
|
});
|
|
2355
|
+
byId('mobile-menu').addEventListener('close', function () { byId('mobile-menu-toggle').setAttribute('aria-expanded', 'false'); });
|
|
2193
2356
|
onSubmit('nl-form', runNaturalLanguagePrompt);
|
|
2194
2357
|
onSubmit('auth-form', submitAuth);
|
|
2195
2358
|
onSubmit('custom-provider-form', startCustomProviderConnection);
|
|
@@ -2209,6 +2372,7 @@ function init() {
|
|
|
2209
2372
|
var searchInput = byId('catalog-search');
|
|
2210
2373
|
if (searchInput) {
|
|
2211
2374
|
searchInput.addEventListener('input', function () {
|
|
2375
|
+
byId('clear-catalog-search').hidden = !searchInput.value.trim();
|
|
2212
2376
|
clearTimeout(searchTimer);
|
|
2213
2377
|
searchTimer = setTimeout(function () { loadCatalog().catch(showError); }, 280);
|
|
2214
2378
|
});
|
|
@@ -2221,6 +2385,23 @@ function init() {
|
|
|
2221
2385
|
navigate(next, { push: false, focus: false });
|
|
2222
2386
|
});
|
|
2223
2387
|
window.addEventListener('storage', function (e) { if (e.key === THEME_KEY && (e.newValue === 'dark' || e.newValue === 'light')) applyTheme(e.newValue); });
|
|
2388
|
+
window.addEventListener('message', function (e) {
|
|
2389
|
+
if (!e || !e.data || e.data.type !== 'muxo:oauth_complete') return;
|
|
2390
|
+
var prov = e.data.providerName || e.data.provider || 'App';
|
|
2391
|
+
if (pendingModalHandoff && pendingModalPlan) {
|
|
2392
|
+
waitAndResumeModalPlan();
|
|
2393
|
+
} else {
|
|
2394
|
+
showToast(prov + ' connected to Muxo');
|
|
2395
|
+
refreshOverview();
|
|
2396
|
+
}
|
|
2397
|
+
});
|
|
2398
|
+
try {
|
|
2399
|
+
var connectedParam = new URLSearchParams(location.search || '').get('connected');
|
|
2400
|
+
if (connectedParam) {
|
|
2401
|
+
showToast('Connected ' + connectedParam + ' to Muxo');
|
|
2402
|
+
if (history && history.replaceState) history.replaceState({}, '', location.pathname);
|
|
2403
|
+
}
|
|
2404
|
+
} catch (e) {}
|
|
2224
2405
|
var initial = viewForPath(location.pathname);
|
|
2225
2406
|
navigate(initial, { push: false, focus: false, skipLoad: true });
|
|
2226
2407
|
boot(initial);
|
|
@@ -2231,19 +2412,37 @@ function navItem(view, label, icon, countId) {
|
|
|
2231
2412
|
const path = Object.entries(CONSOLE_ROUTES).find(([, v]) => v === view)?.[0] ?? "/";
|
|
2232
2413
|
return `<a class="nav-item" href="${path}" data-nav="${view}">${uiIcon(icon)}<span>${label}</span>${countId ? `<span id="${countId}" class="count"></span>` : ""}</a>`;
|
|
2233
2414
|
}
|
|
2415
|
+
function consoleNavigation(withCounts = true) {
|
|
2416
|
+
return `<nav class="nav-group" aria-label="Console">
|
|
2417
|
+
<p>Workspace</p>
|
|
2418
|
+
${navItem("overview", "Overview", "home")}
|
|
2419
|
+
${navItem("catalog", "Tools", "grid")}
|
|
2420
|
+
${navItem("activity", "Activity", "activity", withCounts ? "nav-run-count" : undefined)}
|
|
2421
|
+
</nav>
|
|
2422
|
+
<nav class="nav-group" aria-label="Manage">
|
|
2423
|
+
<p>Manage</p>
|
|
2424
|
+
${navItem("setup", "API access", "key")}
|
|
2425
|
+
${navItem("workspaces", "Workspaces", "users")}
|
|
2426
|
+
${navItem("billing", "Billing", "wallet")}
|
|
2427
|
+
</nav>
|
|
2428
|
+
<nav class="nav-group" aria-label="Resources">
|
|
2429
|
+
<p>Resources</p>
|
|
2430
|
+
<a class="nav-item" href="${DOCS_URL}/quickstart">${uiIcon("book")}<span>Documentation</span>${uiIcon("external")}</a>
|
|
2431
|
+
</nav>`;
|
|
2432
|
+
}
|
|
2234
2433
|
export function renderConsoleHtml() {
|
|
2235
2434
|
const scriptPrelude = `var ROUTES = ${JSON.stringify(CONSOLE_ROUTES)};` +
|
|
2236
2435
|
`var THEME_KEY = ${JSON.stringify(THEME_STORAGE_KEY)};` +
|
|
2237
2436
|
`var THEME_BG = ${JSON.stringify({ light: muxoThemes.light.bg, dark: muxoThemes.dark.bg })};`;
|
|
2238
2437
|
return `<!DOCTYPE html>
|
|
2239
|
-
<html lang="en" data-theme="
|
|
2438
|
+
<html lang="en" data-theme="dark">
|
|
2240
2439
|
<head>
|
|
2241
2440
|
<meta charset="utf-8" />
|
|
2242
2441
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
2243
2442
|
<title>Muxo Console</title>
|
|
2244
2443
|
<meta name="description" content="Manage the tools, approvals, memory, and billing your agents use through Muxo." />
|
|
2245
|
-
<meta name="theme-color" content="${muxoThemes.
|
|
2246
|
-
<meta name="color-scheme" content="light
|
|
2444
|
+
<meta name="theme-color" content="${muxoThemes.dark.bg}" />
|
|
2445
|
+
<meta name="color-scheme" content="dark light" />
|
|
2247
2446
|
<meta name="robots" content="noindex" />
|
|
2248
2447
|
<link rel="icon" href="https://muxo.ai/favicon.svg" type="image/svg+xml" />
|
|
2249
2448
|
<link rel="apple-touch-icon" href="https://muxo.ai/apple-touch-icon.png" />
|
|
@@ -2254,15 +2453,14 @@ export function renderConsoleHtml() {
|
|
|
2254
2453
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
2255
2454
|
<header class="console-topbar">
|
|
2256
2455
|
<div class="topbar-in">
|
|
2456
|
+
<button id="mobile-menu-toggle" class="icon-button mobile-menu-toggle" type="button" data-action="mobile-menu" aria-label="Open navigation" aria-haspopup="dialog" aria-controls="mobile-menu" aria-expanded="false">${uiIcon("menu")}</button>
|
|
2257
2457
|
<a class="brand" href="/" data-nav="overview" aria-label="Muxo console home">${muxoMark}<span>Muxo</span><span class="brand-section">Console</span></a>
|
|
2258
|
-
<button class="workspace-chip" type="button" data-action="switch-workspace"
|
|
2259
|
-
<span id="workspace-name">Workspace</span><span id="workspace-tier" class="tier">Free plan</span
|
|
2458
|
+
<button class="workspace-chip" type="button" data-action="switch-workspace" aria-label="Switch workspace" aria-haspopup="dialog">
|
|
2459
|
+
<span id="workspace-name">Workspace</span><span id="workspace-tier" class="tier">Free plan</span>${uiIcon("chevron")}
|
|
2260
2460
|
</button>
|
|
2261
2461
|
<nav class="topbar-links" aria-label="Muxo">
|
|
2262
2462
|
<a class="nav-link" href="${DOCS_URL}">Docs</a>
|
|
2263
|
-
<
|
|
2264
|
-
<a class="nav-link" href="${PRICING_URL}">Pricing</a>
|
|
2265
|
-
<button id="theme-toggle" class="icon-button" type="button" data-action="toggle-theme" aria-pressed="false" aria-label="Switch to dark mode">${uiIcon("sun", "theme-sun")}${uiIcon("moon", "theme-moon")}</button>
|
|
2463
|
+
<button id="theme-toggle" class="icon-button" type="button" data-action="toggle-theme" aria-pressed="true" aria-label="Switch to light mode">${uiIcon("sun", "theme-sun")}${uiIcon("moon", "theme-moon")}</button>
|
|
2266
2464
|
<a id="account-signin" class="btn btn-primary" href="/login" data-nav="login">Sign in</a>
|
|
2267
2465
|
<div id="account-signed-in" class="account" hidden>
|
|
2268
2466
|
<span id="account-label" class="account-label"></span>
|
|
@@ -2274,16 +2472,10 @@ export function renderConsoleHtml() {
|
|
|
2274
2472
|
|
|
2275
2473
|
<div id="console-shell" class="console-layout">
|
|
2276
2474
|
<aside class="console-sidebar" aria-label="Console">
|
|
2277
|
-
|
|
2278
|
-
<p>Console</p>
|
|
2279
|
-
${navItem("overview", "Harness onboarding", "terminal")}
|
|
2280
|
-
${navItem("setup", "API keys", "key")}
|
|
2281
|
-
${navItem("activity", "History & audit", "activity", "nav-run-count")}
|
|
2282
|
-
${navItem("billing", "Billing", "wallet")}
|
|
2283
|
-
</nav>
|
|
2475
|
+
${consoleNavigation()}
|
|
2284
2476
|
<div class="sidebar-usage">
|
|
2285
2477
|
<div class="usage-row"><span>Monthly actions</span><strong id="meter-actions-text">0 / 1,000</strong></div>
|
|
2286
|
-
<div class="meter" role="presentation"><span id="meter-actions-bar" style="width:
|
|
2478
|
+
<div class="meter" role="presentation"><span id="meter-actions-bar" style="width:0%"></span></div>
|
|
2287
2479
|
<div class="usage-row"><span>Credits</span><strong id="meter-credits-text">0</strong></div>
|
|
2288
2480
|
<a href="/billing" data-nav="billing">Add credits</a>
|
|
2289
2481
|
</div>
|
|
@@ -2291,86 +2483,97 @@ export function renderConsoleHtml() {
|
|
|
2291
2483
|
|
|
2292
2484
|
<main id="main" class="console-main" tabindex="-1">
|
|
2293
2485
|
<section class="page" data-view="overview" aria-labelledby="h-overview">
|
|
2294
|
-
<header class="page-header">
|
|
2295
|
-
<div>
|
|
2296
|
-
<h1 id="h-overview">
|
|
2297
|
-
<
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
<a class="btn btn-primary" href="${DOCS_URL}/quickstart">${uiIcon("book")}Quickstart</a>
|
|
2486
|
+
<header class="page-header overview-header">
|
|
2487
|
+
<div class="overview-title">
|
|
2488
|
+
<h1 id="h-overview">Overview</h1>
|
|
2489
|
+
<div class="page-actions">
|
|
2490
|
+
<button class="icon-button" type="button" data-action="refresh-overview" aria-label="Refresh overview" title="Refresh overview">${uiIcon("refresh")}</button>
|
|
2491
|
+
<a class="btn btn-primary" href="/catalog" data-nav="catalog">${uiIcon("grid")}Browse tools</a>
|
|
2492
|
+
</div>
|
|
2302
2493
|
</div>
|
|
2494
|
+
<p class="lede">Monitor agent activity and approvals.</p>
|
|
2303
2495
|
</header>
|
|
2304
2496
|
<div class="stack">
|
|
2305
2497
|
<div class="metrics">
|
|
2306
|
-
<
|
|
2307
|
-
<
|
|
2308
|
-
<
|
|
2309
|
-
<
|
|
2498
|
+
<a class="metric metric-link" href="/activity" data-nav="activity"><p class="metric-label">Monthly actions ${uiIcon("arrow")}</p><p class="metric-value" id="kpi-actions">—</p><p class="metric-sub" id="kpi-actions-sub">Monthly usage</p></a>
|
|
2499
|
+
<a class="metric metric-link" href="/activity" data-nav="activity"><p class="metric-label">Needs your review ${uiIcon("arrow")}</p><p class="metric-value" id="kpi-pending">—</p><p class="metric-sub" id="kpi-pending-sub">Waiting for your review</p></a>
|
|
2500
|
+
<a class="metric metric-link" href="/catalog" data-nav="catalog"><p class="metric-label">Connected services ${uiIcon("arrow")}</p><p class="metric-value" id="kpi-connections">—</p><p class="metric-sub">Apps & cloud resources</p></a>
|
|
2501
|
+
<a class="metric metric-link" href="/billing" data-nav="billing"><p class="metric-label">Available credits ${uiIcon("arrow")}</p><p class="metric-value" id="kpi-credits">—</p><p class="metric-sub" id="kpi-tier-badge">Workspace balance</p></a>
|
|
2310
2502
|
</div>
|
|
2311
2503
|
|
|
2312
|
-
<div class="
|
|
2313
|
-
<div
|
|
2314
|
-
|
|
2315
|
-
<button class="btn btn-quiet" type="button" data-action="copy" data-target="mcp-config-snippet">${uiIcon("copy")}Copy</button>
|
|
2316
|
-
</div>
|
|
2317
|
-
<div id="harness-tabs" class="segmented" role="group" aria-label="Agent">
|
|
2318
|
-
<button type="button" data-action="harness" data-kind="plugin" aria-pressed="true">Claude & Codex</button>
|
|
2319
|
-
<button type="button" data-action="harness" data-kind="mcp" aria-pressed="false">MCP config</button>
|
|
2320
|
-
<button type="button" data-action="harness" data-kind="oauth" aria-pressed="false">CLI</button>
|
|
2321
|
-
<button type="button" data-action="harness" data-kind="sdk" aria-pressed="false">TypeScript SDK</button>
|
|
2322
|
-
<button type="button" data-action="harness" data-kind="mastra" aria-pressed="false">Mastra</button>
|
|
2323
|
-
<button type="button" data-action="harness" data-kind="pi" aria-pressed="false">Pi</button>
|
|
2324
|
-
<button type="button" data-action="harness" data-kind="curl" aria-pressed="false">HTTPS API</button>
|
|
2325
|
-
</div>
|
|
2326
|
-
<pre id="mcp-config-snippet" class="code" style="margin-top:16px"></pre>
|
|
2504
|
+
<div id="approval-notice" class="approval-notice" hidden>
|
|
2505
|
+
<div><strong id="approval-notice-title"></strong><p>Review the plan before it runs.</p></div>
|
|
2506
|
+
<a class="btn btn-sm" href="/activity" data-nav="activity">Review ${uiIcon("arrow")}</a>
|
|
2327
2507
|
</div>
|
|
2328
2508
|
|
|
2329
|
-
<div class="
|
|
2509
|
+
<div class="dashboard-layout">
|
|
2330
2510
|
<div class="panel">
|
|
2331
2511
|
<div class="panel-header">
|
|
2332
|
-
<div><h2>
|
|
2333
|
-
<
|
|
2512
|
+
<div><h2>Recent governed actions</h2><p>Tool activity and its audit trail.</p></div>
|
|
2513
|
+
<a class="btn btn-quiet btn-sm" href="/activity" data-nav="activity">View all ${uiIcon("arrow")}</a>
|
|
2334
2514
|
</div>
|
|
2335
|
-
<div
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
<dt>Connect apps</dt>
|
|
2343
|
-
<dd>Run <code>npx @muxoai/cli link github --wait</code> or ask your agent to connect GitHub, Slack, or Gmail</dd>
|
|
2344
|
-
</dl>
|
|
2515
|
+
<div id="recent-runs" aria-live="polite"><p class="empty-note">Loading activity…</p></div>
|
|
2516
|
+
</div>
|
|
2517
|
+
<div class="dashboard-aside">
|
|
2518
|
+
<div class="panel">
|
|
2519
|
+
<div class="panel-header">
|
|
2520
|
+
<div><h2 id="recent-tools-title">Tools</h2></div>
|
|
2521
|
+
<a class="docs-link" href="/catalog" data-nav="catalog">Browse ${uiIcon("arrow")}</a>
|
|
2345
2522
|
</div>
|
|
2523
|
+
<div id="recent-tools"><p class="empty-note">Loading tools…</p></div>
|
|
2346
2524
|
</div>
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2525
|
+
<div class="panel">
|
|
2526
|
+
<div class="workspace-summary"><span class="workspace-avatar">${uiIcon("users")}</span><div><h2 id="overview-workspace-name">Workspace</h2><p id="overview-workspace-tier"></p></div></div>
|
|
2527
|
+
<div class="summary-links">
|
|
2528
|
+
<a class="summary-link" href="/workspaces" data-nav="workspaces">${uiIcon("users")}Manage workspace & team${uiIcon("chevron")}</a>
|
|
2529
|
+
<a class="summary-link" href="/keys" data-nav="setup">${uiIcon("key")}API access${uiIcon("chevron")}</a>
|
|
2530
|
+
<a class="summary-link" href="${DOCS_URL}/quickstart">${uiIcon("book")}Agent setup docs${uiIcon("external")}</a>
|
|
2531
|
+
</div>
|
|
2352
2532
|
</div>
|
|
2353
|
-
<div id="recent-runs" class="rows"></div>
|
|
2354
2533
|
</div>
|
|
2355
2534
|
</div>
|
|
2356
2535
|
</div>
|
|
2357
2536
|
</section>
|
|
2358
2537
|
|
|
2538
|
+
<section class="page" data-view="catalog" aria-labelledby="h-catalog" hidden>
|
|
2539
|
+
<header class="page-header">
|
|
2540
|
+
<div><h1 id="h-catalog">Tools</h1><p class="lede">Find tools for your agents. Every action follows your workspace guardrails.</p></div>
|
|
2541
|
+
<a class="btn" href="${DOCS_URL}">${uiIcon("book")}Documentation</a>
|
|
2542
|
+
</header>
|
|
2543
|
+
<div class="toolbar catalog-toolbar">
|
|
2544
|
+
<div class="search-field">${uiIcon("search")}<input id="catalog-search" type="search" aria-label="Search tools" placeholder="Search tools or providers…" autocomplete="off" /><button id="clear-catalog-search" class="icon-button clear-search" type="button" data-action="clear-search" aria-label="Clear tool search" hidden>${uiIcon("close")}</button></div>
|
|
2545
|
+
<div id="catalog-lanes" class="segmented" role="group" aria-label="Tool category">
|
|
2546
|
+
<button type="button" data-action="lane" data-lane="all" aria-pressed="true">All tools</button>
|
|
2547
|
+
<button type="button" data-action="lane" data-lane="composio_instant" aria-pressed="false">Instant tools</button>
|
|
2548
|
+
<button type="button" data-action="lane" data-lane="composio_sdk" aria-pressed="false">Connected apps</button>
|
|
2549
|
+
<button type="button" data-action="lane" data-lane="stripe_projects" aria-pressed="false">Cloud services</button>
|
|
2550
|
+
</div>
|
|
2551
|
+
</div>
|
|
2552
|
+
<p id="catalog-status" class="toolbar-note" role="status"></p>
|
|
2553
|
+
<div id="catalog-grid" class="tool-grid"></div>
|
|
2554
|
+
</section>
|
|
2555
|
+
|
|
2359
2556
|
<section class="page" data-view="setup" aria-labelledby="h-setup" hidden>
|
|
2360
2557
|
<header class="page-header">
|
|
2361
2558
|
<div>
|
|
2362
|
-
<h1 id="h-setup">API
|
|
2363
|
-
<p class="lede">
|
|
2559
|
+
<h1 id="h-setup">API access</h1>
|
|
2560
|
+
<p class="lede">Manage credentials for your agents and apps.</p>
|
|
2364
2561
|
</div>
|
|
2562
|
+
<a class="btn" href="${DOCS_URL}/quickstart">${uiIcon("book")}Setup docs</a>
|
|
2365
2563
|
</header>
|
|
2366
2564
|
<div class="stack">
|
|
2367
|
-
<div class="
|
|
2565
|
+
<div class="workspace-context">
|
|
2566
|
+
<div class="workspace-summary"><span class="workspace-avatar">${uiIcon("key")}</span><div><p class="section-label">Active workspace</p><h2 id="access-workspace-name">Workspace</h2></div></div>
|
|
2567
|
+
<a class="docs-link" href="/workspaces" data-nav="workspaces">Manage workspaces ${uiIcon("arrow")}</a>
|
|
2568
|
+
</div>
|
|
2569
|
+
<div class="access-layout">
|
|
2368
2570
|
<div class="panel">
|
|
2369
2571
|
<div class="panel-header">
|
|
2370
|
-
<div><h2>
|
|
2572
|
+
<div><h2>Workspace keys</h2><p>New keys are shown once. Store them securely.</p></div>
|
|
2371
2573
|
<button class="btn btn-primary" type="button" data-action="create-key">${uiIcon("plus")}Create key</button>
|
|
2372
2574
|
</div>
|
|
2373
2575
|
<div id="new-key-banner" class="callout" data-tone="ok" style="margin-bottom:12px" hidden>
|
|
2576
|
+
<button class="icon-button key-dismiss" type="button" data-action="dismiss-key" aria-label="Hide new key" title="Hide this key after saving it">${uiIcon("close")}</button>
|
|
2374
2577
|
<p id="new-key-title"><strong>Copy this key now.</strong></p>
|
|
2375
2578
|
<code id="new-key-value" class="key-value"></code>
|
|
2376
2579
|
<div class="callout-actions">
|
|
@@ -2383,48 +2586,68 @@ export function renderConsoleHtml() {
|
|
|
2383
2586
|
</div>
|
|
2384
2587
|
<div class="panel">
|
|
2385
2588
|
<div class="panel-header">
|
|
2386
|
-
<div><h2>
|
|
2387
|
-
<button class="btn btn-sm" type="button" data-action="switch-workspace">Manage workspaces</button>
|
|
2589
|
+
<div><h2>Endpoints</h2><p>Use with your workspace key.</p></div>
|
|
2388
2590
|
</div>
|
|
2389
|
-
<div class="
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
<
|
|
2393
|
-
<
|
|
2591
|
+
<div class="endpoint"><div><strong>REST API</strong><button class="btn btn-quiet btn-sm" type="button" data-action="copy" data-target="api-base-url" aria-label="Copy REST API endpoint">${uiIcon("copy")}</button></div><code id="api-base-url"></code></div>
|
|
2592
|
+
<div class="endpoint"><div><strong>MCP</strong><button class="btn btn-quiet btn-sm" type="button" data-action="copy" data-target="api-mcp-url" aria-label="Copy MCP endpoint">${uiIcon("copy")}</button></div><code id="api-mcp-url"></code></div>
|
|
2593
|
+
<div class="summary-links">
|
|
2594
|
+
<a class="summary-link" href="${DOCS_URL}/quickstart">${uiIcon("book")}Agent & SDK setup${uiIcon("external")}</a>
|
|
2595
|
+
<a class="summary-link" href="/workspaces" data-nav="workspaces">${uiIcon("users")}Team access${uiIcon("chevron")}</a>
|
|
2394
2596
|
</div>
|
|
2395
|
-
<div id="setup-workspaces-list" class="rows" style="margin-top:12px"></div>
|
|
2396
2597
|
</div>
|
|
2397
2598
|
</div>
|
|
2599
|
+
</div>
|
|
2600
|
+
</section>
|
|
2601
|
+
|
|
2602
|
+
<section class="page" data-view="workspaces" aria-labelledby="h-workspaces" hidden>
|
|
2603
|
+
<header class="page-header">
|
|
2604
|
+
<div><h1 id="h-workspaces">Workspaces</h1><p class="lede">Manage your workspaces and give your team access.</p></div>
|
|
2605
|
+
<div class="page-actions">
|
|
2606
|
+
<button class="btn" type="button" data-action="workspace-join">${uiIcon("link")}Join workspace</button>
|
|
2607
|
+
<button class="btn btn-primary" type="button" data-action="workspace-create">${uiIcon("plus")}New workspace</button>
|
|
2608
|
+
</div>
|
|
2609
|
+
</header>
|
|
2610
|
+
<div class="stack">
|
|
2611
|
+
<div class="workspace-context">
|
|
2612
|
+
<div class="workspace-summary"><span class="workspace-avatar">${uiIcon("users")}</span><div><p class="section-label">Active workspace</p><h2 id="workspace-slug">Workspace</h2></div></div>
|
|
2613
|
+
<span id="workspace-auth-badge" class="pill">Signed in</span>
|
|
2614
|
+
</div>
|
|
2615
|
+
<div class="panel">
|
|
2616
|
+
<div class="panel-header"><div><h2>Your workspaces</h2><p id="workspace-count"></p></div></div>
|
|
2617
|
+
<div id="workspaces-list" class="rows"><p class="empty-note">Loading workspaces…</p></div>
|
|
2618
|
+
<div class="row" id="reset-workspace-row" hidden><div><strong>Using an API key</strong><small>Remove this key from your browser when you’re finished.</small></div><button id="reset-workspace-btn" class="btn btn-sm" type="button" data-action="sign-out">Forget key</button></div>
|
|
2619
|
+
</div>
|
|
2398
2620
|
<div class="panel">
|
|
2399
2621
|
<div class="panel-header">
|
|
2400
|
-
<div><h2>Onboard a team
|
|
2401
|
-
<span class="pill" data-tone="accent">Team Onboarding</span>
|
|
2622
|
+
<div><h2>Onboard a new team</h2><p>Create a team key for this workspace or a separate workspace.</p></div>
|
|
2402
2623
|
</div>
|
|
2403
|
-
<form id="team-onboard-form" class="form
|
|
2404
|
-
<label class="field"><span>Team name</span><input id="team-onboard-name" type="text" placeholder="Platform Engineering
|
|
2405
|
-
<label class="field"><span>Workspace
|
|
2406
|
-
<select id="team-onboard-mode">
|
|
2407
|
-
<option value="shared_workspace">
|
|
2408
|
-
<option value="dedicated_workspace">
|
|
2624
|
+
<form id="team-onboard-form" class="team-form">
|
|
2625
|
+
<label class="field"><span>Team name</span><input id="team-onboard-name" type="text" placeholder="e.g. Platform Engineering" autocomplete="off" required /></label>
|
|
2626
|
+
<label class="field"><span>Workspace</span>
|
|
2627
|
+
<select id="team-onboard-mode" aria-describedby="team-workspace-help">
|
|
2628
|
+
<option value="shared_workspace">Use this workspace</option>
|
|
2629
|
+
<option value="dedicated_workspace">Create a separate workspace</option>
|
|
2409
2630
|
</select>
|
|
2631
|
+
<small id="team-workspace-help" class="field-help">A separate workspace keeps tools, connections, and memory isolated.</small>
|
|
2410
2632
|
</label>
|
|
2411
2633
|
<label class="field"><span>Role</span>
|
|
2412
2634
|
<select id="team-onboard-role">
|
|
2413
|
-
<option value="operator">Operator
|
|
2414
|
-
<option value="admin">Admin
|
|
2415
|
-
<option value="member">Member
|
|
2635
|
+
<option value="operator">Operator</option>
|
|
2636
|
+
<option value="admin">Admin</option>
|
|
2637
|
+
<option value="member">Member</option>
|
|
2416
2638
|
</select>
|
|
2639
|
+
<small class="field-help">Operators run tools. Admins also manage keys and guardrails.</small>
|
|
2417
2640
|
</label>
|
|
2418
|
-
<button class="btn btn-primary" type="submit"
|
|
2641
|
+
<div class="team-form-footer"><p>Share the key privately. You can revoke it in API access.</p><button class="btn btn-primary" type="submit">${uiIcon("plus")}Create team access</button></div>
|
|
2419
2642
|
</form>
|
|
2420
2643
|
<div id="team-kit-box" class="callout" data-tone="ok" style="margin-top:16px" hidden>
|
|
2421
|
-
<p><strong id="team-kit-title">Team
|
|
2422
|
-
<
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
</div>
|
|
2644
|
+
<p><strong id="team-kit-title">Team access is ready</strong></p>
|
|
2645
|
+
<p id="team-kit-workspace" class="small muted"></p>
|
|
2646
|
+
<p class="small muted" style="margin-top:8px">Copy this key now. It won’t be shown again.</p>
|
|
2647
|
+
<div class="team-kit-secret"><code id="team-kit-key" class="mono"></code><button class="btn btn-sm" type="button" data-action="copy" data-target="team-kit-key">${uiIcon("copy")}Copy key</button></div>
|
|
2426
2648
|
<details class="recall-raw" style="margin-top:10px">
|
|
2427
|
-
<summary>
|
|
2649
|
+
<summary>Share setup details</summary>
|
|
2650
|
+
<div class="team-kit-secret"><code id="team-kit-cli" class="mono"></code><button class="btn btn-sm" type="button" data-action="copy" data-target="team-kit-cli">${uiIcon("copy")}Copy command</button></div>
|
|
2428
2651
|
<pre id="team-kit-instructions" class="code" style="margin-top:8px"></pre>
|
|
2429
2652
|
<div class="callout-actions" style="margin-top:8px">
|
|
2430
2653
|
<button class="btn btn-sm" type="button" data-action="copy" data-target="team-kit-instructions">${uiIcon("copy")}Copy instructions</button>
|
|
@@ -2438,8 +2661,8 @@ export function renderConsoleHtml() {
|
|
|
2438
2661
|
<section class="page" data-view="activity" aria-labelledby="h-activity" hidden>
|
|
2439
2662
|
<header class="page-header">
|
|
2440
2663
|
<div>
|
|
2441
|
-
<h1 id="h-activity">
|
|
2442
|
-
<p class="lede">
|
|
2664
|
+
<h1 id="h-activity">Activity</h1>
|
|
2665
|
+
<p class="lede">Review actions, approvals, and signed audit records.</p>
|
|
2443
2666
|
</div>
|
|
2444
2667
|
<div class="page-actions"><button class="btn" type="button" data-action="refresh-runs">${uiIcon("refresh")}Refresh</button></div>
|
|
2445
2668
|
</header>
|
|
@@ -2448,7 +2671,7 @@ export function renderConsoleHtml() {
|
|
|
2448
2671
|
<div class="metric"><p class="metric-label">Agents</p><p class="metric-value" id="gov-kill-status" data-tone="ok">Running</p><p class="metric-sub" id="gov-kill-sub">Agents can act within policy</p></div>
|
|
2449
2672
|
<div class="metric"><p class="metric-label">Trust score</p><p class="metric-value" id="gov-trust">—</p><p class="metric-sub" id="gov-trust-sub">of 1,000</p></div>
|
|
2450
2673
|
<div class="metric"><p class="metric-label">Audit log</p><p class="metric-value" id="gov-chain-badge" data-tone="ok">Verified</p><p class="metric-sub" id="gov-chain-sub">Signed entries</p></div>
|
|
2451
|
-
<div class="metric"><p class="metric-label">
|
|
2674
|
+
<div class="metric"><p class="metric-label">Needs your review</p><p class="metric-value" id="gov-pending">0</p><p class="metric-sub">Plans held by guardrails</p></div>
|
|
2452
2675
|
</div>
|
|
2453
2676
|
|
|
2454
2677
|
<div class="table-wrap">
|
|
@@ -2470,7 +2693,7 @@ export function renderConsoleHtml() {
|
|
|
2470
2693
|
</div>
|
|
2471
2694
|
<div class="panel">
|
|
2472
2695
|
<div class="panel-header">
|
|
2473
|
-
<div><h2>
|
|
2696
|
+
<div><h2>Guardrails & memory</h2><p>Rules and defaults for this workspace.</p></div>
|
|
2474
2697
|
<span id="guardrail-posture-pill" class="pill dot" data-tone="ok">Safe default</span>
|
|
2475
2698
|
</div>
|
|
2476
2699
|
<div id="guardrails-plain-box" class="recall-box" style="min-height:0" aria-live="polite"><p class="empty-note">Loading active guardrails…</p></div>
|
|
@@ -2478,13 +2701,6 @@ export function renderConsoleHtml() {
|
|
|
2478
2701
|
<div class="rows" style="margin-top:12px">
|
|
2479
2702
|
<div class="row"><div><strong>Safety modules on every run</strong><div id="gov-modules" class="module-list" style="margin-top:8px"></div></div></div>
|
|
2480
2703
|
</div>
|
|
2481
|
-
<details class="recall-raw">
|
|
2482
|
-
<summary>Cryptographic verification keys</summary>
|
|
2483
|
-
<div class="rows" style="margin-top:10px">
|
|
2484
|
-
<div class="row"><div><strong>Signing identity</strong><small id="gov-did" class="mono"></small></div></div>
|
|
2485
|
-
<div class="row"><div><strong>Public verification key</strong><small id="gov-pubkey" class="mono"></small></div></div>
|
|
2486
|
-
</div>
|
|
2487
|
-
</details>
|
|
2488
2704
|
</div>
|
|
2489
2705
|
</div>
|
|
2490
2706
|
</div>
|
|
@@ -2529,8 +2745,8 @@ export function renderConsoleHtml() {
|
|
|
2529
2745
|
</div>
|
|
2530
2746
|
</div>
|
|
2531
2747
|
<div class="panel">
|
|
2532
|
-
<div class="panel-header"><div><h2>Bring your own keys</h2><p>Use your own
|
|
2533
|
-
<form id="byok-form" class="form-row
|
|
2748
|
+
<div class="panel-header"><div><h2>Bring your own keys</h2><p>Use your own provider keys. They’re stored securely in your vault.</p></div><span id="byok-mode-badge" class="pill">Muxo credits</span></div>
|
|
2749
|
+
<form id="byok-form" class="form-row provider-key-form">
|
|
2534
2750
|
<label class="field"><span>Provider</span>
|
|
2535
2751
|
<select id="byok-provider-select">
|
|
2536
2752
|
<option value="openai">OpenAI (plain-English routing)</option>
|
|
@@ -2572,30 +2788,51 @@ export function renderConsoleHtml() {
|
|
|
2572
2788
|
</div>
|
|
2573
2789
|
|
|
2574
2790
|
<div id="auth-view" class="auth-view" hidden>
|
|
2575
|
-
<div class="auth-card">
|
|
2576
|
-
<div class="
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
<
|
|
2791
|
+
<div class="auth-card oauth-card">
|
|
2792
|
+
<div class="oauth-card-top">
|
|
2793
|
+
<span class="oauth-brand">${muxoMark}<span>Muxo</span></span>
|
|
2794
|
+
<span class="oauth-step-tag">Workspace access</span>
|
|
2795
|
+
</div>
|
|
2796
|
+
<div class="oauth-card-body">
|
|
2797
|
+
<h1 id="auth-title">Sign in to Muxo</h1>
|
|
2798
|
+
<p id="auth-lede" class="lede">Manage tools, approvals, memory, and billing for your agents.</p>
|
|
2799
|
+
<div id="auth-tabs" class="segmented" role="group" aria-label="Account">
|
|
2800
|
+
<button type="button" data-action="auth-mode" data-mode="login" aria-pressed="true">Sign in</button>
|
|
2801
|
+
<button type="button" data-action="auth-mode" data-mode="signup" aria-pressed="false">Create account</button>
|
|
2802
|
+
</div>
|
|
2803
|
+
<form id="auth-form" class="auth-form" novalidate>
|
|
2804
|
+
<label id="auth-name-field" class="field" hidden><span>Name</span><input id="auth-name" type="text" autocomplete="name" /></label>
|
|
2805
|
+
<label class="field"><span>Email</span><input id="auth-email" type="email" autocomplete="email" required /></label>
|
|
2806
|
+
<label class="field"><span>Password</span><input id="auth-password" type="password" autocomplete="current-password" minlength="6" required /></label>
|
|
2807
|
+
<label id="auth-workspace-field" class="field" hidden><span>Workspace name <em>optional</em></span><input id="auth-workspace" type="text" autocomplete="organization" /></label>
|
|
2808
|
+
<p id="auth-error" class="field-error" role="alert"></p>
|
|
2809
|
+
<button id="auth-submit" class="btn btn-primary btn-lg btn-block" type="submit">Sign in</button>
|
|
2810
|
+
</form>
|
|
2811
|
+
<div id="clerk-auth" class="clerk-auth" hidden><p id="clerk-loading" class="clerk-loading" role="status"><span class="spinner" aria-hidden="true"></span>Loading sign-in…</p></div>
|
|
2812
|
+
<p class="auth-switch"><button id="auth-switch-link" class="btn btn-quiet btn-sm" type="button" data-action="auth-mode" data-mode="signup" hidden>New to Muxo? Create an account</button></p>
|
|
2813
|
+
<div class="auth-alt">
|
|
2814
|
+
<button class="btn btn-quiet btn-sm" type="button" data-action="switch-workspace">${uiIcon("key")}Use an API key instead</button>
|
|
2815
|
+
<a class="docs-link" href="${DOCS_URL}/quickstart">Setup guide ${uiIcon("external")}</a>
|
|
2816
|
+
</div>
|
|
2817
|
+
</div>
|
|
2818
|
+
<div class="oauth-card-foot">
|
|
2819
|
+
<span>Secured by <strong>Muxo</strong></span>
|
|
2820
|
+
<a href="/" data-nav="overview">Back to console</a>
|
|
2582
2821
|
</div>
|
|
2583
|
-
<form id="auth-form" class="auth-form" novalidate>
|
|
2584
|
-
<label id="auth-name-field" class="field" hidden><span>Name</span><input id="auth-name" type="text" autocomplete="name" /></label>
|
|
2585
|
-
<label class="field"><span>Email</span><input id="auth-email" type="email" autocomplete="email" required /></label>
|
|
2586
|
-
<label class="field"><span>Password</span><input id="auth-password" type="password" autocomplete="current-password" minlength="6" required /></label>
|
|
2587
|
-
<label id="auth-workspace-field" class="field" hidden><span>Workspace name <em>optional</em></span><input id="auth-workspace" type="text" autocomplete="organization" /></label>
|
|
2588
|
-
<p id="auth-error" class="field-error" role="alert"></p>
|
|
2589
|
-
<button id="auth-submit" class="btn btn-primary btn-lg btn-block" type="submit">Sign in</button>
|
|
2590
|
-
</form>
|
|
2591
|
-
<div id="clerk-auth" class="clerk-auth" hidden><p id="clerk-loading" class="clerk-loading" role="status"><span class="spinner" aria-hidden="true"></span>Loading sign-in…</p></div>
|
|
2592
|
-
<p class="auth-switch"><button id="auth-switch-link" class="btn btn-quiet btn-sm" type="button" data-action="auth-mode" data-mode="signup" hidden>New to Muxo? Create an account</button></p>
|
|
2593
|
-
<div class="auth-alt"><button class="btn btn-quiet" type="button" data-action="switch-workspace">${uiIcon("key")}Use an API key instead</button></div>
|
|
2594
|
-
<p class="auth-foot">Setting up an agent? Run <code>npx -y @muxoai/cli@latest login --signup</code></p>
|
|
2595
|
-
<p class="auth-foot"><a href="/" data-nav="overview">Back to the console</a></p>
|
|
2596
2822
|
</div>
|
|
2597
2823
|
</div>
|
|
2598
2824
|
|
|
2825
|
+
<dialog id="mobile-menu" class="sheet mobile-menu" aria-labelledby="mobile-menu-title">
|
|
2826
|
+
<div class="mobile-menu-content">
|
|
2827
|
+
<div class="sheet-head"><h2 id="mobile-menu-title">Navigation</h2><button class="icon-button" type="button" data-action="close-dialog" aria-label="Close navigation">${uiIcon("close")}</button></div>
|
|
2828
|
+
${consoleNavigation(false)}
|
|
2829
|
+
<div id="mobile-account-actions" class="mobile-menu-account" hidden>
|
|
2830
|
+
<p id="mobile-account-label"></p>
|
|
2831
|
+
<button class="btn" type="button" data-action="sign-out">Sign out</button>
|
|
2832
|
+
</div>
|
|
2833
|
+
</div>
|
|
2834
|
+
</dialog>
|
|
2835
|
+
|
|
2599
2836
|
<dialog id="exec-modal" class="sheet" aria-labelledby="modal-tool-name">
|
|
2600
2837
|
<div class="sheet-inner">
|
|
2601
2838
|
<div class="sheet-head">
|
|
@@ -2639,7 +2876,7 @@ export function renderConsoleHtml() {
|
|
|
2639
2876
|
<dialog id="workspace-dialog" class="sheet" aria-labelledby="workspace-dialog-title">
|
|
2640
2877
|
<div class="sheet-inner">
|
|
2641
2878
|
<div class="sheet-head">
|
|
2642
|
-
<div><h2 id="workspace-dialog-title">Workspaces
|
|
2879
|
+
<div><h2 id="workspace-dialog-title">Workspaces</h2><p class="tool-slug">Switch, join, or create a workspace.</p></div>
|
|
2643
2880
|
<button class="icon-button" type="button" data-action="close-dialog" aria-label="Close">${uiIcon("close")}</button>
|
|
2644
2881
|
</div>
|
|
2645
2882
|
<div>
|
|
@@ -2648,18 +2885,18 @@ export function renderConsoleHtml() {
|
|
|
2648
2885
|
</div>
|
|
2649
2886
|
<form id="join-workspace-form" class="form-grid" style="margin-top:16px;padding-top:16px;border-top:1px solid var(--color-border)" novalidate>
|
|
2650
2887
|
<label class="field">
|
|
2651
|
-
<span>Join
|
|
2652
|
-
<span class="field-help">
|
|
2888
|
+
<span>Join with an API key</span>
|
|
2889
|
+
<span class="field-help">Use a workspace key shared by your teammate.</span>
|
|
2653
2890
|
<div class="inline-form" style="margin-top:6px">
|
|
2654
|
-
<input id="join-workspace-key-input" type="
|
|
2891
|
+
<input id="join-workspace-key-input" type="password" placeholder="mk_live_..." autocomplete="off" />
|
|
2655
2892
|
<button class="btn btn-primary" type="submit">Join workspace</button>
|
|
2656
2893
|
</div>
|
|
2657
2894
|
</label>
|
|
2658
2895
|
</form>
|
|
2659
2896
|
<form id="create-workspace-form" class="form-grid" style="margin-top:14px;padding-top:14px;border-top:1px solid var(--color-border)" novalidate>
|
|
2660
2897
|
<div class="form-row">
|
|
2661
|
-
<label class="field"><span>New workspace name</span><input id="create-workspace-name-input" type="text" placeholder="Production
|
|
2662
|
-
<label class="field"><span>Team
|
|
2898
|
+
<label class="field"><span>New workspace name</span><input id="create-workspace-name-input" type="text" placeholder="e.g. Production" autocomplete="off" /></label>
|
|
2899
|
+
<label class="field"><span>Team name <em>optional</em></span><input id="create-workspace-team-input" type="text" placeholder="e.g. Engineering" autocomplete="off" /></label>
|
|
2663
2900
|
</div>
|
|
2664
2901
|
<div class="sheet-actions" style="margin-top:6px">
|
|
2665
2902
|
<button class="btn" type="button" data-action="close-dialog">Close</button>
|
|
@@ -2789,14 +3026,14 @@ export function renderLandingHtml() {
|
|
|
2789
3026
|
["Safety & audit", "Muxo guardrails and audit log", "Prompt-injection scanning, risk-based approvals, an emergency stop, and a signed record of every run."],
|
|
2790
3027
|
];
|
|
2791
3028
|
return `<!DOCTYPE html>
|
|
2792
|
-
<html lang="en" data-theme="
|
|
3029
|
+
<html lang="en" data-theme="dark">
|
|
2793
3030
|
<head>
|
|
2794
3031
|
<meta charset="utf-8" />
|
|
2795
3032
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
2796
3033
|
<title>Muxo — your tools, in your agent</title>
|
|
2797
3034
|
<meta name="description" content="Connect apps, cloud services, memory, and safety controls to the agent you already use." />
|
|
2798
|
-
<meta name="theme-color" content="${muxoThemes.
|
|
2799
|
-
<meta name="color-scheme" content="light
|
|
3035
|
+
<meta name="theme-color" content="${muxoThemes.dark.bg}" />
|
|
3036
|
+
<meta name="color-scheme" content="dark light" />
|
|
2800
3037
|
<link rel="icon" href="https://muxo.ai/favicon.svg" type="image/svg+xml" />
|
|
2801
3038
|
<script data-theme-bootstrap>${muxoThemeBootstrap}</script>
|
|
2802
3039
|
<style>${muxoBaseCss}${landingCss}</style>
|
|
@@ -2979,14 +3216,16 @@ const consentScript = String.raw `
|
|
|
2979
3216
|
export function renderOAuthConsentHtml(opts) {
|
|
2980
3217
|
const clientName = escapeHtml(opts.clientName || "An app");
|
|
2981
3218
|
const clientNameMidSentence = /^(A|An) /.test(clientName) ? clientName[0].toLowerCase() + clientName.slice(1) : clientName;
|
|
3219
|
+
const claim = opts.claim;
|
|
3220
|
+
const stepTag = opts.error ? "Connection error" : claim ? "Workspace claim" : "Agent sign-in";
|
|
2982
3221
|
const head = `<!DOCTYPE html>
|
|
2983
|
-
<html lang="en" data-theme="
|
|
3222
|
+
<html lang="en" data-theme="dark">
|
|
2984
3223
|
<head>
|
|
2985
3224
|
<meta charset="utf-8" />
|
|
2986
3225
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
2987
3226
|
<title>${opts.error ? (opts.claim ? "Claim problem" : "Connection problem") : opts.claim ? `Claim ${escapeHtml(opts.claim.workspaceName)}` : `Connect ${clientNameMidSentence}`} · Muxo</title>
|
|
2988
|
-
<meta name="theme-color" content="${muxoThemes.
|
|
2989
|
-
<meta name="color-scheme" content="light
|
|
3227
|
+
<meta name="theme-color" content="${muxoThemes.dark.bg}" />
|
|
3228
|
+
<meta name="color-scheme" content="dark light" />
|
|
2990
3229
|
<meta name="robots" content="noindex" />
|
|
2991
3230
|
<link rel="icon" href="https://muxo.ai/favicon.svg" type="image/svg+xml" />
|
|
2992
3231
|
<script data-theme-bootstrap>${muxoThemeBootstrap}</script>
|
|
@@ -2996,17 +3235,24 @@ export function renderOAuthConsentHtml(opts) {
|
|
|
2996
3235
|
if (opts.error) {
|
|
2997
3236
|
return `${head}
|
|
2998
3237
|
<main class="auth-view">
|
|
2999
|
-
<div class="auth-card">
|
|
3000
|
-
<div class="
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3238
|
+
<div class="auth-card oauth-card">
|
|
3239
|
+
<div class="oauth-card-top">
|
|
3240
|
+
<span class="oauth-brand">${muxoMark}<span>Muxo</span></span>
|
|
3241
|
+
<span class="oauth-step-tag">${stepTag}</span>
|
|
3242
|
+
</div>
|
|
3243
|
+
<div class="oauth-card-body">
|
|
3244
|
+
<h1>${opts.claim ? "This claim link isn't valid" : "This connection link isn't valid"}</h1>
|
|
3245
|
+
<p class="lede">${escapeHtml(opts.error)}</p>
|
|
3246
|
+
</div>
|
|
3247
|
+
<div class="oauth-card-foot">
|
|
3248
|
+
<span>${opts.claim ? "Ask the agent for a new claim link" : "Start the connection again from your app"}</span>
|
|
3249
|
+
<a href="${DOCS_URL}">Read the setup guide</a>
|
|
3250
|
+
</div>
|
|
3004
3251
|
</div>
|
|
3005
3252
|
</main>
|
|
3006
3253
|
</body>
|
|
3007
3254
|
</html>`;
|
|
3008
3255
|
}
|
|
3009
|
-
const claim = opts.claim;
|
|
3010
3256
|
const config = {
|
|
3011
3257
|
clerk: opts.clerk || null,
|
|
3012
3258
|
request: opts.request || {},
|
|
@@ -3032,26 +3278,33 @@ export function renderOAuthConsentHtml(opts) {
|
|
|
3032
3278
|
<p class="consent-redirect">After you decide, you'll return to <strong>${escapeHtml(opts.redirectOrigin || "")}</strong></p>`;
|
|
3033
3279
|
return `${head}
|
|
3034
3280
|
<main class="auth-view">
|
|
3035
|
-
<div class="auth-card">
|
|
3036
|
-
<div class="
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
<button id="consent-deny" class="btn btn-lg" type="button">${claim ? "Not now" : "Cancel"}</button>
|
|
3048
|
-
<button id="consent-allow" class="btn btn-primary btn-lg" type="button">${claim ? "Claim workspace" : "Allow"}</button>
|
|
3281
|
+
<div class="auth-card oauth-card">
|
|
3282
|
+
<div class="oauth-card-top">
|
|
3283
|
+
<span class="oauth-brand">${muxoMark}<span>Muxo</span></span>
|
|
3284
|
+
<span class="oauth-step-tag">${stepTag}</span>
|
|
3285
|
+
</div>
|
|
3286
|
+
<div class="oauth-card-body">
|
|
3287
|
+
${intro}
|
|
3288
|
+
<div class="consent-state">
|
|
3289
|
+
<p id="consent-loading" class="muted">Checking your sign-in…</p>
|
|
3290
|
+
<div id="consent-signin" hidden>
|
|
3291
|
+
<p class="consent-account">Sign in to Muxo to continue.</p>
|
|
3292
|
+
<div id="clerk-auth" class="clerk-auth"></div>
|
|
3049
3293
|
</div>
|
|
3050
|
-
<
|
|
3294
|
+
<div id="consent-approve" hidden>
|
|
3295
|
+
<p class="consent-account">Signed in as <strong id="consent-email"></strong></p>
|
|
3296
|
+
<div class="consent-actions">
|
|
3297
|
+
<button id="consent-deny" class="btn btn-lg" type="button">${claim ? "Not now" : "Cancel"}</button>
|
|
3298
|
+
<button id="consent-allow" class="btn btn-primary btn-lg" type="button">${claim ? "Claim workspace" : "Allow"}</button>
|
|
3299
|
+
</div>
|
|
3300
|
+
<p class="consent-switch"><button id="consent-switch" class="btn btn-quiet btn-sm" type="button">Use a different account</button></p>
|
|
3301
|
+
</div>
|
|
3302
|
+
<p id="consent-error" class="field-error" role="alert"></p>
|
|
3051
3303
|
</div>
|
|
3052
|
-
<p id="consent-error" class="field-error" role="alert"></p>
|
|
3053
3304
|
</div>
|
|
3054
|
-
<
|
|
3305
|
+
<div class="oauth-card-foot">
|
|
3306
|
+
<span>${claim ? "Only the invited email can claim this workspace, and the link works once." : "You can remove this connection anytime in the Muxo console."}</span>
|
|
3307
|
+
</div>
|
|
3055
3308
|
</div>
|
|
3056
3309
|
</main>
|
|
3057
3310
|
<script>window.MUXO_CONSENT = ${inlineJson(config)};${consentScript}</script>
|
|
@@ -3065,9 +3318,9 @@ const approvalCss = `
|
|
|
3065
3318
|
.approval-facts .v{color:var(--color-text);font-weight:500;text-align:right;overflow-wrap:anywhere}
|
|
3066
3319
|
.approval-input{margin:14px 0 0;padding:12px;border:1px solid var(--color-border);border-radius:10px;background:var(--color-bg);font-family:var(--font-mono);font-size:12px;text-align:left;white-space:pre-wrap;overflow-wrap:anywhere;max-height:180px;overflow:auto}
|
|
3067
3320
|
.approval-risk{display:inline-block;border-radius:999px;padding:3px 10px;font-size:12px;font-weight:600;text-transform:capitalize}
|
|
3068
|
-
.approval-risk[data-tone="ok"]{background:
|
|
3069
|
-
.approval-risk[data-tone="warn"]{background:
|
|
3070
|
-
.approval-risk[data-tone="strict"]{background:
|
|
3321
|
+
.approval-risk[data-tone="ok"]{background:var(--color-ok-bg);color:var(--color-ok)}
|
|
3322
|
+
.approval-risk[data-tone="warn"]{background:var(--color-warn-bg);color:var(--color-warn)}
|
|
3323
|
+
.approval-risk[data-tone="strict"]{background:var(--color-danger-bg);color:var(--color-danger)}
|
|
3071
3324
|
.approval-note{margin-top:14px;color:var(--color-muted);font-size:13px}
|
|
3072
3325
|
.approval-done{margin-top:18px;text-align:left;font-size:14px}
|
|
3073
3326
|
`;
|
|
@@ -3188,10 +3441,18 @@ const approvalScript = String.raw `
|
|
|
3188
3441
|
return;
|
|
3189
3442
|
}
|
|
3190
3443
|
if (clerk && !mounted) {
|
|
3191
|
-
clerk.mountSignIn(byId('clerk-auth'), { routing: 'hash', forceRedirectUrl: here, signUpForceRedirectUrl: here });
|
|
3444
|
+
clerk.mountSignIn(byId('clerk-auth'), { routing: 'hash', forceRedirectUrl: here, signUpForceRedirectUrl: here, appearance: appearance() });
|
|
3192
3445
|
mounted = true;
|
|
3193
3446
|
}
|
|
3194
3447
|
}
|
|
3448
|
+
function appearance() {
|
|
3449
|
+
var cs = getComputedStyle(document.documentElement);
|
|
3450
|
+
function v(n) { return cs.getPropertyValue(n).trim(); }
|
|
3451
|
+
return {
|
|
3452
|
+
variables: { colorPrimary: v('--color-button-primary'), colorText: v('--color-text'), colorTextSecondary: v('--color-muted'), colorBackground: v('--color-surface'), colorInputBackground: v('--color-bg'), colorInputText: v('--color-text'), colorDanger: v('--color-danger'), borderRadius: '12px', fontFamily: v('--font-sans'), fontSize: '15px' },
|
|
3453
|
+
elements: { rootBox: { width: '100%' }, cardBox: { width: '100%', boxShadow: 'none', border: '0' }, card: { boxShadow: 'none', background: 'transparent', padding: '4px 0 0' }, header: { display: 'none' }, footer: { background: 'transparent' } }
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3195
3456
|
var keyForm = byId('approval-key-form');
|
|
3196
3457
|
if (keyForm) {
|
|
3197
3458
|
keyForm.addEventListener('submit', async function (e) {
|
|
@@ -3231,7 +3492,7 @@ const approvalScript = String.raw `
|
|
|
3231
3492
|
s.onerror = function () { fail('Sign-in could not load. Check your connection and reload.'); };
|
|
3232
3493
|
s.onload = function () {
|
|
3233
3494
|
if (!window.Clerk) { fail('Sign-in could not load.'); return; }
|
|
3234
|
-
window.Clerk.load().then(function () {
|
|
3495
|
+
window.Clerk.load({ appearance: appearance() }).then(function () {
|
|
3235
3496
|
clerk = window.Clerk;
|
|
3236
3497
|
clerk.addListener(function () { if (clerk.session && clerk.user && !plan) load(); });
|
|
3237
3498
|
if (clerk.session && clerk.user) load(); else renderAuth();
|
|
@@ -3245,13 +3506,13 @@ export function renderApprovalPageHtml(opts) {
|
|
|
3245
3506
|
const planId = String(opts.planId || "");
|
|
3246
3507
|
const config = { planId, clerk: opts.clerk || null };
|
|
3247
3508
|
return `<!DOCTYPE html>
|
|
3248
|
-
<html lang="en" data-theme="
|
|
3509
|
+
<html lang="en" data-theme="dark">
|
|
3249
3510
|
<head>
|
|
3250
3511
|
<meta charset="utf-8" />
|
|
3251
3512
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
3252
3513
|
<title>Review action · Muxo</title>
|
|
3253
|
-
<meta name="theme-color" content="${muxoThemes.
|
|
3254
|
-
<meta name="color-scheme" content="light
|
|
3514
|
+
<meta name="theme-color" content="${muxoThemes.dark.bg}" />
|
|
3515
|
+
<meta name="color-scheme" content="dark light" />
|
|
3255
3516
|
<meta name="robots" content="noindex" />
|
|
3256
3517
|
<link rel="icon" href="https://muxo.ai/favicon.svg" type="image/svg+xml" />
|
|
3257
3518
|
<script data-theme-bootstrap>${muxoThemeBootstrap}</script>
|
|
@@ -3259,45 +3520,338 @@ export function renderApprovalPageHtml(opts) {
|
|
|
3259
3520
|
</head>
|
|
3260
3521
|
<body>
|
|
3261
3522
|
<main class="auth-view">
|
|
3262
|
-
<div class="auth-card">
|
|
3263
|
-
<div class="
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
<
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
<
|
|
3272
|
-
|
|
3273
|
-
<
|
|
3523
|
+
<div class="auth-card oauth-card">
|
|
3524
|
+
<div class="oauth-card-top">
|
|
3525
|
+
<span class="oauth-brand">${muxoMark}<span>Muxo</span></span>
|
|
3526
|
+
<span class="oauth-step-tag">Action review</span>
|
|
3527
|
+
</div>
|
|
3528
|
+
<div class="oauth-card-body">
|
|
3529
|
+
<h1>Review this action</h1>
|
|
3530
|
+
<p class="lede">Muxo held this action because your guardrails require your approval before it can run.</p>
|
|
3531
|
+
<div class="consent-state">
|
|
3532
|
+
<p id="approval-loading" class="muted">Loading plan ${escapeHtml(planId)}…</p>
|
|
3533
|
+
<div id="approval-signin" hidden>
|
|
3534
|
+
<p id="approval-signin-msg" class="consent-account">Sign in to Muxo to review this action.</p>
|
|
3535
|
+
<div id="clerk-auth" class="clerk-auth"></div>
|
|
3536
|
+
<form id="approval-key-form" class="inline-form" style="margin-top:12px" novalidate>
|
|
3537
|
+
<input id="approval-key-input" type="password" placeholder="Or paste workspace / team key (mk_live_...)" autocomplete="off" />
|
|
3538
|
+
<button class="btn btn-primary" type="submit">Continue</button>
|
|
3539
|
+
</form>
|
|
3540
|
+
<p id="approval-console-link" style="margin-top:10px" hidden><a href="/">Open the Muxo console</a></p>
|
|
3541
|
+
</div>
|
|
3542
|
+
<div id="approval-review" hidden>
|
|
3543
|
+
<ul class="approval-facts">
|
|
3544
|
+
<li><span class="k">Action</span><span class="v" id="approval-tool"></span></li>
|
|
3545
|
+
<li><span class="k">Risk</span><span class="v"><span id="approval-risk" class="approval-risk" data-tone="warn"></span></span></li>
|
|
3546
|
+
<li><span class="k">Cost</span><span class="v" id="approval-cost"></span></li>
|
|
3547
|
+
<li><span class="k">Reason</span><span class="v" id="approval-reason"></span></li>
|
|
3548
|
+
</ul>
|
|
3549
|
+
<pre id="approval-input" class="approval-input" aria-label="Tool input"></pre>
|
|
3550
|
+
<p id="approval-state-note" class="approval-note">Nothing runs until you approve.</p>
|
|
3551
|
+
<div class="consent-actions">
|
|
3552
|
+
<button id="approval-reject" class="btn btn-lg" type="button">Reject</button>
|
|
3553
|
+
<button id="approval-approve-only" class="btn btn-lg" type="button">Approve only</button>
|
|
3554
|
+
</div>
|
|
3555
|
+
<div class="consent-actions" style="grid-template-columns:1fr;margin-top:10px">
|
|
3556
|
+
<button id="approval-approve-run" class="btn btn-primary btn-lg" type="button">Approve and run</button>
|
|
3557
|
+
</div>
|
|
3558
|
+
</div>
|
|
3559
|
+
<div id="approval-done" class="approval-done" hidden></div>
|
|
3560
|
+
<p id="approval-error" class="field-error" role="alert"></p>
|
|
3561
|
+
</div>
|
|
3562
|
+
</div>
|
|
3563
|
+
<div class="oauth-card-foot">
|
|
3564
|
+
<span>Muxo checks every action against your guardrails and workspace memory before it reaches you.</span>
|
|
3565
|
+
</div>
|
|
3566
|
+
</div>
|
|
3567
|
+
</main>
|
|
3568
|
+
<script>window.MUXO_APPROVAL = ${inlineJson(config)};${approvalScript}</script>
|
|
3569
|
+
</body>
|
|
3570
|
+
</html>`;
|
|
3571
|
+
}
|
|
3572
|
+
const oauthConnectCss = `
|
|
3573
|
+
.connect-bridge{display:flex;align-items:center;justify-content:center;gap:12px;margin:0 auto 18px}
|
|
3574
|
+
.connect-node{display:inline-flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:14px;border:1px solid var(--color-border);background:var(--color-bg);box-shadow:0 2px 8px rgba(0,0,0,.04);margin:0}
|
|
3575
|
+
.connect-node svg{width:24px;height:24px}
|
|
3576
|
+
.connect-node-monogram{font-size:18px;font-weight:700;letter-spacing:-0.02em;color:var(--color-text)}
|
|
3577
|
+
.connect-connector{display:inline-flex;align-items:center;gap:6px;color:var(--color-muted)}
|
|
3578
|
+
.connect-line{width:22px;height:1px;background:var(--color-border-strong)}
|
|
3579
|
+
.connect-lock{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:999px;border:1px solid var(--color-border);background:var(--color-surface-2);color:var(--color-text)}
|
|
3580
|
+
.connect-lock svg{width:13px;height:13px}
|
|
3581
|
+
.connect-lock[data-tone="ok"]{border-color:var(--color-ok-border);background:var(--color-ok-bg);color:var(--color-ok)}
|
|
3582
|
+
.connect-badge-row{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:8px;margin-bottom:14px}
|
|
3583
|
+
.connect-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 11px;border-radius:999px;font-size:12px;font-weight:600;border:1px solid var(--color-border);background:var(--color-bg);color:var(--color-text)}
|
|
3584
|
+
.connect-pill-subtle{font-weight:500;color:var(--color-muted)}
|
|
3585
|
+
.connect-pill-status[data-tone="ok"]{border-color:var(--color-ok-border);background:var(--color-ok-bg);color:var(--color-ok)}
|
|
3586
|
+
.connect-pill-status[data-tone="warn"]{border-color:var(--color-warn-border);background:var(--color-warn-bg);color:var(--color-warn)}
|
|
3587
|
+
.connect-steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:16px 0 6px;text-align:left}
|
|
3588
|
+
.connect-step{display:flex;align-items:center;gap:8px;padding:8px 10px;border:1px solid var(--color-border);border-radius:10px;background:var(--color-bg);font-size:12px;line-height:1.3;color:var(--color-muted)}
|
|
3589
|
+
.connect-step-num{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;background:var(--color-surface-2);color:var(--color-text);font-size:11px;font-weight:700;flex:none}
|
|
3590
|
+
.connect-field{margin-top:12px;text-align:left}
|
|
3591
|
+
.connect-field label{display:block;font-size:13px;font-weight:600;margin-bottom:4px;color:var(--color-text)}
|
|
3592
|
+
.connect-field small{display:block;font-size:12px;color:var(--color-muted);margin-bottom:6px}
|
|
3593
|
+
.connect-field input{width:100%;box-sizing:border-box;padding:10px 12px;border:1px solid var(--color-border);border-radius:8px;background:var(--color-bg);color:var(--color-text);font-size:14px}
|
|
3594
|
+
@media (max-width:520px){.connect-steps{grid-template-columns:1fr}}
|
|
3595
|
+
`;
|
|
3596
|
+
function renderProviderBadge(slug, name) {
|
|
3597
|
+
const s = (slug || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
3598
|
+
if (s === "github") {
|
|
3599
|
+
return `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.58 2 12.23c0 4.52 2.87 8.35 6.84 9.7.5.09.68-.22.68-.49 0-.24-.01-.89-.01-1.74-2.78.62-3.37-1.37-3.37-1.37-.45-1.18-1.11-1.49-1.11-1.49-.91-.64.07-.63.07-.63 1 .07 1.53 1.05 1.53 1.05.9 1.57 2.35 1.12 2.92.85.09-.67.35-1.12.63-1.38-2.22-.26-4.56-1.14-4.56-5.07 0-1.12.39-2.03 1.03-2.75-.1-.26-.45-1.3.1-2.71 0 0 .84-.28 2.75 1.05A9.36 9.36 0 0 1 12 6.84c.85 0 1.71.12 2.51.35 1.91-1.33 2.75-1.05 2.75-1.05.55 1.41.2 2.45.1 2.71.64.72 1.03 1.63 1.03 2.75 0 3.94-2.34 4.81-4.57 5.06.36.32.68.94.68 1.9 0 1.37-.01 2.48-.01 2.82 0 .27.18.59.69.49A10.25 10.25 0 0 0 22 12.23C22 6.58 17.52 2 12 2Z"/></svg>`;
|
|
3600
|
+
}
|
|
3601
|
+
if (s === "slack") {
|
|
3602
|
+
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="13" y="2" width="3" height="8" rx="1.5"/><path d="M19 8.5V10h1.5A1.5 1.5 0 1 0 19 8.5"/><rect x="8" y="14" width="3" height="8" rx="1.5"/><path d="M5 15.5V14H3.5A1.5 1.5 0 1 0 5 15.5"/><rect x="14" y="13" width="8" height="3" rx="1.5"/><path d="M15.5 19H14v1.5a1.5 1.5 0 1 0 1.5-1.5"/><rect x="2" y="8" width="8" height="3" rx="1.5"/><path d="M8.5 5H10V3.5A1.5 1.5 0 1 0 8.5 5"/></svg>`;
|
|
3603
|
+
}
|
|
3604
|
+
if (s === "gmail" || s.startsWith("google")) {
|
|
3605
|
+
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></svg>`;
|
|
3606
|
+
}
|
|
3607
|
+
if (s === "notion") {
|
|
3608
|
+
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4h12l4 4v12H6l-2-2V4Z"/><path d="M9 9v7l5-7v7"/></svg>`;
|
|
3609
|
+
}
|
|
3610
|
+
if (s === "linear") {
|
|
3611
|
+
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="m5.5 15.5 7 3M4.5 11.5l8 8M7.5 6.5l10 10"/></svg>`;
|
|
3612
|
+
}
|
|
3613
|
+
const initial = escapeHtml((name || slug || "A").trim().charAt(0).toUpperCase() || "A");
|
|
3614
|
+
return `<span class="connect-node-monogram">${initial}</span>`;
|
|
3615
|
+
}
|
|
3616
|
+
const oauthConnectScript = String.raw `
|
|
3617
|
+
(function () {
|
|
3618
|
+
var C = window.MUXO_CONNECT || {};
|
|
3619
|
+
var form = document.getElementById('muxo-connect-form');
|
|
3620
|
+
var btn = document.getElementById('muxo-connect-submit');
|
|
3621
|
+
var errEl = document.getElementById('muxo-connect-error');
|
|
3622
|
+
if (!form || !btn) return;
|
|
3623
|
+
form.addEventListener('submit', async function (e) {
|
|
3624
|
+
e.preventDefault();
|
|
3625
|
+
if (errEl) errEl.textContent = '';
|
|
3626
|
+
btn.disabled = true;
|
|
3627
|
+
var originalText = btn.textContent;
|
|
3628
|
+
btn.textContent = 'Connecting to ' + (C.toolkitName || 'provider') + '…';
|
|
3629
|
+
try {
|
|
3630
|
+
var input = {};
|
|
3631
|
+
var fields = form.querySelectorAll('input[name]');
|
|
3632
|
+
for (var i = 0; i < fields.length; i++) {
|
|
3633
|
+
var f = fields[i];
|
|
3634
|
+
if (f.name && f.value !== '') input[f.name] = f.value;
|
|
3635
|
+
}
|
|
3636
|
+
var res = await fetch(form.action, {
|
|
3637
|
+
method: 'POST',
|
|
3638
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
3639
|
+
body: JSON.stringify({ input: input })
|
|
3640
|
+
});
|
|
3641
|
+
var data = await res.json().catch(function () { return {}; });
|
|
3642
|
+
var target = data.redirectUrl || data.redirect_url;
|
|
3643
|
+
if (!res.ok || data.ok === false || !target) {
|
|
3644
|
+
throw new Error(data.error || data.message || 'Could not start authorization handoff.');
|
|
3645
|
+
}
|
|
3646
|
+
window.location.href = target;
|
|
3647
|
+
} catch (err) {
|
|
3648
|
+
if (errEl) errEl.textContent = (err && err.message) ? err.message : 'Could not start authorization handoff.';
|
|
3649
|
+
btn.disabled = false;
|
|
3650
|
+
btn.textContent = originalText;
|
|
3651
|
+
}
|
|
3652
|
+
});
|
|
3653
|
+
})();
|
|
3654
|
+
`;
|
|
3655
|
+
/** Muxo-branded OAuth connection handoff screen (`/oauth/connect/:token`). */
|
|
3656
|
+
export function renderOAuthConnectPageHtml(opts) {
|
|
3657
|
+
const toolkitName = escapeHtml(opts.toolkitName || "Connected App");
|
|
3658
|
+
const toolkitSlug = escapeHtml(opts.toolkitSlug || "app");
|
|
3659
|
+
const workspaceId = opts.workspaceId ? escapeHtml(opts.workspaceId) : "";
|
|
3660
|
+
const authModeLabel = escapeHtml((opts.authMode || "OAUTH2").toUpperCase());
|
|
3661
|
+
const fields = Array.isArray(opts.expectedInputFields) ? opts.expectedInputFields : [];
|
|
3662
|
+
const querySuffix = (() => {
|
|
3663
|
+
const params = new URLSearchParams();
|
|
3664
|
+
if (opts.workspaceId)
|
|
3665
|
+
params.set("workspace_id", opts.workspaceId);
|
|
3666
|
+
if (opts.toolkitSlug)
|
|
3667
|
+
params.set("provider", opts.toolkitSlug);
|
|
3668
|
+
if (opts.callbackUrl)
|
|
3669
|
+
params.set("callback_url", opts.callbackUrl);
|
|
3670
|
+
const qs = params.toString();
|
|
3671
|
+
return qs ? `?${qs}` : "";
|
|
3672
|
+
})();
|
|
3673
|
+
const actionUrl = `/oauth/connect/${encodeURIComponent(opts.token)}${querySuffix}`;
|
|
3674
|
+
const fieldsHtml = fields
|
|
3675
|
+
.map((f) => {
|
|
3676
|
+
const inputType = f.type === "password" || /secret|token|key|password/i.test(f.name)
|
|
3677
|
+
? "password"
|
|
3678
|
+
: "text";
|
|
3679
|
+
return `<div class="connect-field">
|
|
3680
|
+
<label for="field-${escapeHtml(f.name)}">${escapeHtml(f.label || f.name)}</label>
|
|
3681
|
+
${f.description ? `<small>${escapeHtml(f.description)}</small>` : ""}
|
|
3682
|
+
<input id="field-${escapeHtml(f.name)}" name="${escapeHtml(f.name)}" type="${inputType}" value="${escapeHtml(f.default || "")}" ${f.required !== false ? "required" : ""} autocomplete="off" />
|
|
3683
|
+
</div>`;
|
|
3684
|
+
})
|
|
3685
|
+
.join("");
|
|
3686
|
+
const config = {
|
|
3687
|
+
token: opts.token,
|
|
3688
|
+
toolkitSlug: opts.toolkitSlug,
|
|
3689
|
+
toolkitName: opts.toolkitName,
|
|
3690
|
+
workspaceId: opts.workspaceId || null,
|
|
3691
|
+
};
|
|
3692
|
+
return `<!DOCTYPE html>
|
|
3693
|
+
<html lang="en" data-theme="dark">
|
|
3694
|
+
<head>
|
|
3695
|
+
<meta charset="utf-8" />
|
|
3696
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
3697
|
+
<title>Muxo wants to connect to your ${toolkitName} · Muxo</title>
|
|
3698
|
+
<meta name="theme-color" content="${muxoThemes.dark.bg}" />
|
|
3699
|
+
<meta name="color-scheme" content="dark light" />
|
|
3700
|
+
<meta name="robots" content="noindex" />
|
|
3701
|
+
<link rel="icon" href="https://muxo.ai/favicon.svg" type="image/svg+xml" />
|
|
3702
|
+
<script data-theme-bootstrap>${muxoThemeBootstrap}</script>
|
|
3703
|
+
<style>${muxoBaseCss}${consoleCss}${consentCss}${approvalCss}${oauthConnectCss}</style>
|
|
3704
|
+
</head>
|
|
3705
|
+
<body>
|
|
3706
|
+
<main class="auth-view">
|
|
3707
|
+
<div class="auth-card oauth-card">
|
|
3708
|
+
<div class="oauth-card-top">
|
|
3709
|
+
<span class="oauth-brand">${muxoMark}<span>Muxo</span></span>
|
|
3710
|
+
<span class="oauth-step-tag">App consent</span>
|
|
3711
|
+
</div>
|
|
3712
|
+
<div class="oauth-card-body">
|
|
3713
|
+
<div class="connect-bridge" aria-hidden="true">
|
|
3714
|
+
<div class="auth-mark connect-node" title="Muxo">${muxoMark}</div>
|
|
3715
|
+
<div class="connect-connector">
|
|
3716
|
+
<span class="connect-line"></span>
|
|
3717
|
+
<span class="connect-lock">${uiIcon("shield")}</span>
|
|
3718
|
+
<span class="connect-line"></span>
|
|
3719
|
+
</div>
|
|
3720
|
+
<div class="connect-node" title="${toolkitName}">${renderProviderBadge(opts.toolkitSlug, opts.toolkitName)}</div>
|
|
3721
|
+
</div>
|
|
3722
|
+
<div class="connect-badge-row">
|
|
3723
|
+
<span class="connect-pill">Muxo Connected Apps · ${toolkitSlug}</span>
|
|
3724
|
+
<span class="connect-pill connect-pill-subtle">${authModeLabel}</span>
|
|
3725
|
+
</div>
|
|
3726
|
+
<h1>Muxo wants to connect to your ${toolkitName}</h1>
|
|
3727
|
+
<p class="lede">Authorize ${toolkitName} so your agent can run governed actions in ${workspaceId ? `workspace <code>${workspaceId}</code>` : "your Muxo workspace"}.</p>
|
|
3728
|
+
<div class="connect-steps" aria-label="Connection steps">
|
|
3729
|
+
<div class="connect-step"><span class="connect-step-num">1</span><span>Authorize ${toolkitName}</span></div>
|
|
3730
|
+
<div class="connect-step"><span class="connect-step-num">2</span><span>Sealed in Muxo Vault</span></div>
|
|
3731
|
+
<div class="connect-step"><span class="connect-step-num">3</span><span>Resume in ChatGPT / Agent</span></div>
|
|
3732
|
+
</div>
|
|
3733
|
+
<ul class="consent-list">
|
|
3734
|
+
<li>Credentials are sealed in your isolated Muxo workspace vault</li>
|
|
3735
|
+
<li>Every action is checked against your workspace safety guardrails</li>
|
|
3736
|
+
<li>All tool runs emit a signed Ed25519 receipt and can be revoked anytime</li>
|
|
3737
|
+
</ul>
|
|
3738
|
+
<div class="consent-state">
|
|
3739
|
+
<form id="muxo-connect-form" method="POST" action="${escapeHtml(actionUrl)}">
|
|
3740
|
+
${fieldsHtml}
|
|
3741
|
+
<div class="consent-actions" style="grid-template-columns:1fr;margin-top:16px">
|
|
3742
|
+
<button id="muxo-connect-submit" data-testid="connect-button" class="btn btn-primary btn-lg" type="submit">Connect ${toolkitName} Account</button>
|
|
3743
|
+
</div>
|
|
3274
3744
|
</form>
|
|
3275
|
-
<p id="
|
|
3745
|
+
<p id="muxo-connect-error" class="field-error" role="alert">${opts.error ? escapeHtml(opts.error) : ""}</p>
|
|
3746
|
+
</div>
|
|
3747
|
+
</div>
|
|
3748
|
+
<div class="oauth-card-foot">
|
|
3749
|
+
<span>Secured by <strong>Muxo</strong> · Governed Agent Execution</span>
|
|
3750
|
+
</div>
|
|
3751
|
+
</div>
|
|
3752
|
+
</main>
|
|
3753
|
+
<script>window.MUXO_CONNECT = ${inlineJson(config)};${oauthConnectScript}</script>
|
|
3754
|
+
</body>
|
|
3755
|
+
</html>`;
|
|
3756
|
+
}
|
|
3757
|
+
const oauthCallbackScript = String.raw `
|
|
3758
|
+
(function () {
|
|
3759
|
+
var C = window.MUXO_OAUTH_CALLBACK || {};
|
|
3760
|
+
try {
|
|
3761
|
+
if (window.opener && !window.opener.closed) {
|
|
3762
|
+
window.opener.postMessage({
|
|
3763
|
+
type: 'muxo:oauth_complete',
|
|
3764
|
+
provider: C.providerSlug,
|
|
3765
|
+
providerName: C.providerName,
|
|
3766
|
+
status: C.status,
|
|
3767
|
+
workspaceId: C.workspaceId,
|
|
3768
|
+
externalAccountId: C.externalAccountId
|
|
3769
|
+
}, '*');
|
|
3770
|
+
}
|
|
3771
|
+
} catch (e) {}
|
|
3772
|
+
var closeBtn = document.getElementById('oauth-close-window');
|
|
3773
|
+
var hintEl = document.getElementById('oauth-close-hint');
|
|
3774
|
+
if (closeBtn) {
|
|
3775
|
+
closeBtn.addEventListener('click', function () {
|
|
3776
|
+
try { window.close(); } catch (e) {}
|
|
3777
|
+
if (hintEl) hintEl.hidden = false;
|
|
3778
|
+
});
|
|
3779
|
+
}
|
|
3780
|
+
})();
|
|
3781
|
+
`;
|
|
3782
|
+
/** Muxo-branded OAuth callback completion screen (`/oauth/callback`). */
|
|
3783
|
+
export function renderOAuthCallbackPageHtml(opts) {
|
|
3784
|
+
const providerSlug = escapeHtml(opts.providerSlug || "app");
|
|
3785
|
+
const providerName = escapeHtml(opts.providerName || "Connected App");
|
|
3786
|
+
const statusUpper = escapeHtml(String(opts.status || "active").toUpperCase());
|
|
3787
|
+
const isSuccess = String(opts.status || "active").toLowerCase() === "active";
|
|
3788
|
+
const workspaceId = escapeHtml(opts.workspaceId || "ws_default");
|
|
3789
|
+
const externalAccountId = opts.externalAccountId ? escapeHtml(opts.externalAccountId) : "";
|
|
3790
|
+
const consoleHref = `/?connected=${encodeURIComponent(opts.providerSlug || "app")}`;
|
|
3791
|
+
const config = {
|
|
3792
|
+
providerSlug: opts.providerSlug,
|
|
3793
|
+
providerName: opts.providerName,
|
|
3794
|
+
status: opts.status,
|
|
3795
|
+
workspaceId: opts.workspaceId,
|
|
3796
|
+
externalAccountId: opts.externalAccountId || null,
|
|
3797
|
+
};
|
|
3798
|
+
return `<!DOCTYPE html>
|
|
3799
|
+
<html lang="en" data-theme="dark">
|
|
3800
|
+
<head>
|
|
3801
|
+
<meta charset="utf-8" />
|
|
3802
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
3803
|
+
<title>Muxo OAuth Handoff Complete · Muxo</title>
|
|
3804
|
+
<meta name="theme-color" content="${muxoThemes.dark.bg}" />
|
|
3805
|
+
<meta name="color-scheme" content="dark light" />
|
|
3806
|
+
<meta name="robots" content="noindex" />
|
|
3807
|
+
<link rel="icon" href="https://muxo.ai/favicon.svg" type="image/svg+xml" />
|
|
3808
|
+
<script data-theme-bootstrap>${muxoThemeBootstrap}</script>
|
|
3809
|
+
<style>${muxoBaseCss}${consoleCss}${consentCss}${approvalCss}${oauthConnectCss}</style>
|
|
3810
|
+
</head>
|
|
3811
|
+
<body>
|
|
3812
|
+
<main class="auth-view">
|
|
3813
|
+
<div class="auth-card oauth-card">
|
|
3814
|
+
<div class="oauth-card-top">
|
|
3815
|
+
<span class="oauth-brand">${muxoMark}<span>Muxo</span></span>
|
|
3816
|
+
<span class="oauth-step-tag">${isSuccess ? "Connected" : "Connection update"}</span>
|
|
3817
|
+
</div>
|
|
3818
|
+
<div class="oauth-card-body">
|
|
3819
|
+
<div class="connect-bridge" aria-hidden="true">
|
|
3820
|
+
<div class="auth-mark connect-node" title="Muxo">${muxoMark}</div>
|
|
3821
|
+
<div class="connect-connector">
|
|
3822
|
+
<span class="connect-line"></span>
|
|
3823
|
+
<span class="connect-lock" data-tone="${isSuccess ? "ok" : "warn"}">${uiIcon("check")}</span>
|
|
3824
|
+
<span class="connect-line"></span>
|
|
3825
|
+
</div>
|
|
3826
|
+
<div class="connect-node" title="${providerName}">${renderProviderBadge(opts.providerSlug, opts.providerName)}</div>
|
|
3827
|
+
</div>
|
|
3828
|
+
<div class="connect-badge-row">
|
|
3829
|
+
<span class="connect-pill connect-pill-status" data-tone="${isSuccess ? "ok" : "warn"}">OAuth Handoff Complete (${statusUpper})</span>
|
|
3276
3830
|
</div>
|
|
3277
|
-
<
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
</
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
<div class="consent-actions">
|
|
3287
|
-
<button id="
|
|
3288
|
-
<button id="approval-approve-only" class="btn btn-lg" type="button">Approve only</button>
|
|
3831
|
+
<h1>${providerName} Connected to Muxo</h1>
|
|
3832
|
+
<p class="lede">Workspace <code>${workspaceId}</code> is now linked${externalAccountId ? ` (<code>${externalAccountId}</code>)` : ""}. You can close this window and return to ChatGPT, Codex, Claude Code, Droid, or your terminal.</p>
|
|
3833
|
+
<ul class="approval-facts">
|
|
3834
|
+
<li><span class="k">Connected app</span><span class="v">${providerName} (${providerSlug})</span></li>
|
|
3835
|
+
<li><span class="k">Vault status</span><span class="v">${isSuccess ? "Active · Sealed in Muxo Vault" : statusUpper}</span></li>
|
|
3836
|
+
<li><span class="k">Workspace</span><span class="v"><code>${workspaceId}</code></span></li>
|
|
3837
|
+
${externalAccountId ? `<li><span class="k">Connection ID</span><span class="v"><code>${externalAccountId}</code></span></li>` : ""}
|
|
3838
|
+
</ul>
|
|
3839
|
+
<div class="consent-state">
|
|
3840
|
+
<div class="consent-actions" style="grid-template-columns:1fr;margin-top:16px">
|
|
3841
|
+
<button id="oauth-close-window" class="btn btn-primary btn-lg" type="button">Done — Return to ChatGPT / Agent</button>
|
|
3289
3842
|
</div>
|
|
3290
3843
|
<div class="consent-actions" style="grid-template-columns:1fr;margin-top:10px">
|
|
3291
|
-
<
|
|
3844
|
+
<a class="btn btn-lg" href="${escapeHtml(consoleHref)}">Open Muxo Console</a>
|
|
3292
3845
|
</div>
|
|
3846
|
+
<p id="oauth-close-hint" class="approval-note" hidden>You can safely close this browser tab now and tell ChatGPT or your agent to continue.</p>
|
|
3293
3847
|
</div>
|
|
3294
|
-
<div id="approval-done" class="approval-done" hidden></div>
|
|
3295
|
-
<p id="approval-error" class="field-error" role="alert"></p>
|
|
3296
3848
|
</div>
|
|
3297
|
-
<
|
|
3849
|
+
<div class="oauth-card-foot">
|
|
3850
|
+
<span>Secured by <strong>Muxo</strong> · Governed Agent Execution</span>
|
|
3851
|
+
</div>
|
|
3298
3852
|
</div>
|
|
3299
3853
|
</main>
|
|
3300
|
-
<script>window.
|
|
3854
|
+
<script>window.MUXO_OAUTH_CALLBACK = ${inlineJson(config)};${oauthCallbackScript}</script>
|
|
3301
3855
|
</body>
|
|
3302
3856
|
</html>`;
|
|
3303
3857
|
}
|