glad-web 1.0.21 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/bin/cli.js +1 -1
- package/lib/ai-tools/registry.js +1 -1
- package/lib/codex/structured-session.js +588 -0
- package/lib/commands/web.js +63 -2
- package/lib/session/session-manager.js +74 -11
- package/lib/web/index.html +378 -13
- package/package.json +5 -4
package/lib/web/index.html
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<link rel="apple-touch-icon" href="logo.svg">
|
|
11
11
|
<link rel="stylesheet" href="https://unpkg.com/xterm@5.3.0/css/xterm.css" />
|
|
12
12
|
<style>
|
|
13
|
-
:root { --primary: #007aff; --bg: #000; --card-bg: #1c1c1e; --text: #fff; --text-dim: #8e8e93; --terminal-controls-rest-height: 108px; }
|
|
13
|
+
:root { --primary: #007aff; --bg: #000; --card-bg: #1c1c1e; --text: #fff; --text-dim: #8e8e93; --terminal-controls-rest-height: 108px; --chat-content-max: 900px; --control-content-max: 1100px; }
|
|
14
14
|
body, html { margin: 0; padding: 0; height: 100dvh; width: 100vw; background: var(--bg); color: var(--text); overflow: hidden; overflow-anchor: none; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
|
|
15
15
|
.view { display: none; height: 100%; width: 100%; flex-direction: column; }
|
|
16
16
|
.view.active { display: flex; }
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
#session-title { flex: 1; text-align: center; font-weight: 600; font-size: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 10px; min-width: 0; }
|
|
49
49
|
#terminal-controls { position: absolute; top: 100%; left: 0; right: 0; z-index: 2200; background: linear-gradient(180deg, rgba(18,18,18,0.98) 0%, rgba(18,18,18,0.92) 78%, rgba(18,18,18,0) 100%); border-bottom: 1px solid rgba(255,255,255,0.06); }
|
|
50
50
|
#terminal-controls-spacer { flex: 0 0 var(--terminal-controls-rest-height); height: var(--terminal-controls-rest-height); background: #000; }
|
|
51
|
-
#input-row { display: flex; align-items: flex-end; padding: 10px 14px 8px 14px; }
|
|
51
|
+
#input-row { display: flex; align-items: flex-end; width: min(100%, var(--control-content-max)); margin: 0 auto; padding: 10px 14px 8px 14px; box-sizing: border-box; }
|
|
52
52
|
#cmd-input { flex: 1; min-height: 38px; max-height: 150px; background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.1); border-radius: 19px; color: #fff; padding: 9px 16px; font-size: 16px; outline: none; resize: none; overflow-y: auto; line-height: 20px; box-sizing: border-box; transition: background 0.18s ease, border-color 0.18s ease; }
|
|
53
53
|
#cmd-input::placeholder { color: rgba(255,255,255,0.45); }
|
|
54
54
|
#cmd-input:focus { background: rgba(255,255,255,0.1); border-color: rgba(0,122,255,0.42); color: #fff; }
|
|
@@ -78,6 +78,58 @@
|
|
|
78
78
|
#terminal-container { flex: 1; min-height: 0; width: 100%; background: #000; position: relative; overflow: hidden; overflow-anchor: none; }
|
|
79
79
|
#terminal { height: 100%; width: 100%; }
|
|
80
80
|
#claude-chat-container { display: none; flex: 1; min-height: 0; overflow-y: auto; background: #050505; padding: 12px 12px 24px 12px; box-sizing: border-box; -webkit-overflow-scrolling: touch; }
|
|
81
|
+
#codex-chat-container { display: none; flex: 1; min-height: 0; overflow-y: auto; background: #050505; padding: 12px 12px 24px 12px; box-sizing: border-box; -webkit-overflow-scrolling: touch; }
|
|
82
|
+
.codex-conversation { width: min(100%, var(--chat-content-max)); margin: 0 auto; }
|
|
83
|
+
.codex-message { max-width: 100%; margin: 0 0 12px; color: #f5f5f7; font-size: 14px; line-height: 1.45; overflow-wrap: anywhere; }
|
|
84
|
+
.codex-message.user { max-width: 92%; margin-left: auto; padding: 8px 12px; border: 1px solid rgba(0,122,255,.32); border-radius: 12px; background: rgba(0,122,255,.24); }
|
|
85
|
+
.codex-message.event { color: var(--text-dim); text-align: center; font-size: 12px; }
|
|
86
|
+
.codex-tool { border: 1px solid rgba(255,255,255,.1); border-radius: 8px; background: rgba(255,255,255,.045); overflow: hidden; margin: 8px 0; color: #d1d5db; }
|
|
87
|
+
.codex-tool summary { list-style: none; cursor: pointer; }
|
|
88
|
+
.codex-tool summary::-webkit-details-marker { display: none; }
|
|
89
|
+
.codex-tool-header { display: flex; align-items: center; min-width: 0; gap: 8px; min-height: 34px; padding: 6px 9px; }
|
|
90
|
+
.codex-tool-icon { width: 19px; flex: 0 0 19px; color: #c7c7cc; font: 700 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center; }
|
|
91
|
+
.codex-tool-title { flex: 0 1 auto; min-width: 0; color: #f5f5f7; font-size: 13px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
92
|
+
.codex-tool-command { flex: 1; min-width: 0; color: #a9a9b0; font: 12px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
93
|
+
.codex-tool-state { flex: 0 0 auto; color: #8e8e93; font-size: 11px; }
|
|
94
|
+
.codex-tool-state.running::before { content: ''; display: inline-block; width: 9px; height: 9px; margin-right: 5px; border: 1.5px solid #8e8e93; border-top-color: transparent; border-radius: 50%; animation: codex-spin .8s linear infinite; vertical-align: -1px; }
|
|
95
|
+
.codex-tool.error { border-color: rgba(255,59,48,.38); background: rgba(255,59,48,.07); }
|
|
96
|
+
.codex-tool-body { border-top: 1px solid rgba(255,255,255,.08); padding: 9px 10px; }
|
|
97
|
+
.codex-tool-code { margin: 0; max-height: 320px; overflow: auto; color: #c7c7cc; white-space: pre-wrap; overflow-wrap: anywhere; font: 12px/1.42 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
98
|
+
.codex-work-group { margin: 8px 0; border-left: 1px solid rgba(255,255,255,.12); padding-left: 8px; }
|
|
99
|
+
.codex-work-group > summary { list-style: none; display: flex; align-items: center; gap: 7px; min-height: 30px; color: #a9a9b0; cursor: pointer; font-size: 12px; }
|
|
100
|
+
.codex-work-group > summary::-webkit-details-marker { display: none; }
|
|
101
|
+
.codex-work-group > summary::before { content: '›'; width: 12px; color: #8e8e93; font-size: 17px; transform-origin: center; }
|
|
102
|
+
.codex-work-group[open] > summary::before { transform: rotate(90deg); }
|
|
103
|
+
.codex-work-group-body { padding-left: 2px; }
|
|
104
|
+
.codex-patch-file { border-top: 1px solid rgba(255,255,255,.08); }
|
|
105
|
+
.codex-patch-file:first-child { border-top: 0; }
|
|
106
|
+
.codex-patch-file > summary { display: flex; align-items: center; gap: 8px; padding: 8px 10px; color: #d1d5db; font: 12px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
107
|
+
.codex-patch-file .path { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
108
|
+
.codex-patch-kind { color: #8e8e93; font-family: system-ui, sans-serif; }
|
|
109
|
+
.codex-diff { overflow-x: auto; border-top: 1px solid rgba(255,255,255,.08); background: rgba(0,0,0,.24); font: 11px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
110
|
+
.codex-diff-line { min-width: max-content; padding: 0 10px; white-space: pre; color: #c7c7cc; }
|
|
111
|
+
.codex-diff-line.add { color: #b7e4c7; background: rgba(52,199,89,.1); }
|
|
112
|
+
.codex-diff-line.del { color: #ffb3ad; background: rgba(255,59,48,.1); }
|
|
113
|
+
.codex-diff-line.hunk { color: #64b5f6; background: rgba(0,122,255,.08); }
|
|
114
|
+
.codex-permission-result { color: #a9a9b0; font-size: 12px; margin-top: 7px; }
|
|
115
|
+
.codex-inline-permission { border-top: 1px solid rgba(255,204,0,.28); padding: 9px 10px 10px; background: rgba(255,204,0,.055); }
|
|
116
|
+
.codex-inline-permission-title { color: #f5f5f7; font-size: 12px; font-weight: 700; }
|
|
117
|
+
.codex-inline-permission .claude-permission-actions { margin-top: 8px; }
|
|
118
|
+
@keyframes codex-spin { to { transform: rotate(360deg); } }
|
|
119
|
+
#codex-control-panel { display: none; width: min(100%, var(--control-content-max)); margin: 0 auto; padding: 8px 14px 10px; border-bottom: 1px solid #222; background: #121212; box-sizing: border-box; }
|
|
120
|
+
.codex-control-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; align-items: center; }
|
|
121
|
+
.codex-select { appearance: none; max-width: 116px; min-width: 0; height: 32px; padding: 0 8px; border: 1px solid rgba(255,255,255,.12); border-radius: 7px; background: rgba(255,255,255,.08); color: #f5f5f7; font-weight: 700; font-size: 12px; }
|
|
122
|
+
.codex-select option { background: #1c1c1e; color: #fff; }
|
|
123
|
+
#codex-model-panel, #codex-resume-panel { display: none; margin-top: 8px; border: 1px solid rgba(255,255,255,.1); background: rgba(28,28,30,.99); border-radius: 8px; box-shadow: 0 16px 36px rgba(0,0,0,.34); overflow: hidden; }
|
|
124
|
+
#codex-model-panel.active, #codex-resume-panel.active { display: block; }
|
|
125
|
+
#codex-model-panel { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); max-height: min(300px, 42dvh); }
|
|
126
|
+
#codex-model-panel.active { display: grid; }
|
|
127
|
+
.codex-picker-column { min-width: 0; overflow-y: auto; }
|
|
128
|
+
.codex-picker-column + .codex-picker-column { border-left: 1px solid rgba(255,255,255,.08); }
|
|
129
|
+
.codex-picker-option { display: block; width: 100%; min-height: 38px; padding: 8px 10px; border: 0; border-bottom: 1px solid rgba(255,255,255,.06); background: transparent; color: #f5f5f7; text-align: left; font-size: 12px; font-weight: 700; overflow-wrap: anywhere; }
|
|
130
|
+
.codex-picker-option.selected { background: rgba(0,122,255,.18); color: #fff; }
|
|
131
|
+
#codex-state-bar { display: none; align-items: center; gap: 7px; min-height: 24px; margin-top: 8px; color: var(--text-dim); font-size: 11px; }
|
|
132
|
+
#codex-resume-panel { max-height: min(280px, 38dvh); overflow-y: auto; }
|
|
81
133
|
.claude-context-size-badge { position: sticky; top: 0; z-index: 2; width: max-content; max-width: 100%; margin: 0 0 8px auto; border: 1px solid rgba(255,255,255,0.1); background: rgba(28,28,30,0.94); border-radius: 999px; padding: 4px 9px; color: #d1d5db; font-size: 11px; font-weight: 800; box-shadow: 0 8px 18px rgba(0,0,0,0.24); }
|
|
82
134
|
.claude-message { max-width: 92%; margin: 0 0 10px 0; padding: 10px 12px; border-radius: 8px; overflow-wrap: anywhere; line-height: 1.45; font-size: 14px; }
|
|
83
135
|
.claude-message.user { margin-left: auto; background: rgba(0,122,255,0.24); border: 1px solid rgba(0,122,255,0.32); color: #fff; border-radius: 12px; padding-top: 7px; padding-bottom: 7px; }
|
|
@@ -226,6 +278,35 @@
|
|
|
226
278
|
.step-grid { grid-template-columns: 1fr; }
|
|
227
279
|
.timed-row { grid-template-columns: 1fr; }
|
|
228
280
|
}
|
|
281
|
+
@media (max-width: 480px) {
|
|
282
|
+
:root { --chat-content-max: 100%; --control-content-max: 100%; }
|
|
283
|
+
#nav-bar { padding: 8px 10px; }
|
|
284
|
+
#back-btn { font-size: 15px; }
|
|
285
|
+
#back-btn svg { width: 22px; height: 22px; }
|
|
286
|
+
#session-title { font-size: 15px; padding: 0 7px; }
|
|
287
|
+
#nav-bar > div:last-child { gap: 5px !important; }
|
|
288
|
+
#nav-bar > div:last-child .icon-btn { min-width: 34px; min-height: 30px; padding: 5px 7px !important; }
|
|
289
|
+
#input-row { padding-left: 10px; padding-right: 10px; }
|
|
290
|
+
#codex-control-panel { padding-left: 10px; padding-right: 10px; }
|
|
291
|
+
.codex-control-row { gap: 6px; }
|
|
292
|
+
#codex-chat-container { padding: 10px 10px calc(22px + env(safe-area-inset-bottom)); }
|
|
293
|
+
.codex-message.user { max-width: 94%; }
|
|
294
|
+
.claude-permission-actions { justify-content: flex-start; }
|
|
295
|
+
}
|
|
296
|
+
@media (max-width: 430px) {
|
|
297
|
+
#nav-bar > div:last-child .icon-btn:not(#codex-terminal-switch) { width: 34px; font-size: 0 !important; gap: 0 !important; }
|
|
298
|
+
#nav-bar > div:last-child .icon-btn:not(#codex-terminal-switch) svg { width: 16px; height: 16px; }
|
|
299
|
+
#codex-terminal-switch { padding-left: 8px !important; padding-right: 8px !important; }
|
|
300
|
+
}
|
|
301
|
+
@media (min-width: 768px) and (max-width: 1199px) {
|
|
302
|
+
:root { --chat-content-max: 780px; --control-content-max: 920px; }
|
|
303
|
+
#codex-chat-container { padding: 16px 18px 30px; }
|
|
304
|
+
#input-row, #codex-control-panel { padding-left: 18px; padding-right: 18px; }
|
|
305
|
+
}
|
|
306
|
+
@media (min-width: 1200px) {
|
|
307
|
+
:root { --chat-content-max: 960px; --control-content-max: 1100px; }
|
|
308
|
+
#codex-chat-container { padding: 18px 22px 34px; }
|
|
309
|
+
}
|
|
229
310
|
</style>
|
|
230
311
|
</head>
|
|
231
312
|
<body>
|
|
@@ -264,6 +345,7 @@
|
|
|
264
345
|
</button>
|
|
265
346
|
<div id="session-title">Terminal</div>
|
|
266
347
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
348
|
+
<button id="codex-terminal-switch" class="icon-btn" onclick="toggleCodexPresentation()" title="Switch Codex interface" style="display:none; color: var(--primary); font-size: 12px; font-weight: 700; background: rgba(0, 122, 255, 0.1); padding: 5px 9px; border-radius: 15px; gap: 4px;">TERM</button>
|
|
267
349
|
<button class="icon-btn" onclick="showHistory()" title="History" style="color: var(--primary); font-size: 12px; font-weight: 700; background: rgba(0, 122, 255, 0.1); padding: 5px 9px; border-radius: 15px; gap: 4px;">
|
|
268
350
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"></path><polyline points="3 3 3 9 9 9"></polyline><path d="M12 7v5l3 2"></path></svg>
|
|
269
351
|
HIS
|
|
@@ -321,6 +403,19 @@
|
|
|
321
403
|
<div id="claude-usage-panel"></div>
|
|
322
404
|
<div id="claude-resume-panel"></div>
|
|
323
405
|
</div>
|
|
406
|
+
<div id="codex-control-panel">
|
|
407
|
+
<div class="codex-control-row">
|
|
408
|
+
<select id="codex-permission-select" class="codex-select" title="Permission mode" onchange="updateCodexSettingsFromControls()">
|
|
409
|
+
<option value="untrusted">Untrusted</option><option value="on-request">On request</option><option value="never">Never ask</option>
|
|
410
|
+
</select>
|
|
411
|
+
<button id="codex-model-btn" class="claude-ctrl-btn" onclick="toggleCodexModelPanel()" title="Model and effort">Model</button>
|
|
412
|
+
<button id="codex-abort-btn" class="claude-ctrl-btn danger" onclick="abortCodexSession()" title="Abort current Codex turn">Abort</button>
|
|
413
|
+
<button id="codex-resume-btn" class="claude-ctrl-btn primary" onclick="toggleCodexResumePanel()" title="Resume a Codex thread">Resume</button>
|
|
414
|
+
</div>
|
|
415
|
+
<div id="codex-state-bar"></div>
|
|
416
|
+
<div id="codex-model-panel"></div>
|
|
417
|
+
<div id="codex-resume-panel"></div>
|
|
418
|
+
</div>
|
|
324
419
|
<div id="timed-send-panel">
|
|
325
420
|
<div class="timed-row">
|
|
326
421
|
<select id="timed-hours" onchange="updateTimedSendPreview()" title="Hours"></select>
|
|
@@ -360,6 +455,7 @@
|
|
|
360
455
|
<div id="terminal-controls-spacer"></div>
|
|
361
456
|
<div id="terminal-container"><div id="terminal"></div></div>
|
|
362
457
|
<div id="claude-chat-container"></div>
|
|
458
|
+
<div id="codex-chat-container"></div>
|
|
363
459
|
</div>
|
|
364
460
|
|
|
365
461
|
<!-- Plain Text History View -->
|
|
@@ -509,6 +605,12 @@
|
|
|
509
605
|
};
|
|
510
606
|
let claudeResumePanelOpen = false;
|
|
511
607
|
let claudeResumeItemsLoaded = false;
|
|
608
|
+
let codexMessages = [];
|
|
609
|
+
let codexPendingPermissions = [];
|
|
610
|
+
let codexState = { permissionMode: 'on-request', model: null, effort: null, status: 'idle', threadId: null, presentation: 'structured', models: [], canAbort: false, canSwitchToTerminal: false, canSwitchToStructured: false };
|
|
611
|
+
let codexModelPanelOpen = false;
|
|
612
|
+
let codexModelCandidate = null;
|
|
613
|
+
let codexResumePanelOpen = false;
|
|
512
614
|
const modifiers = { ctrl: false };
|
|
513
615
|
|
|
514
616
|
function log(msg) {
|
|
@@ -800,25 +902,30 @@
|
|
|
800
902
|
return activeToolKey === 'claude-code';
|
|
801
903
|
}
|
|
802
904
|
|
|
905
|
+
function isCodexSession() {
|
|
906
|
+
return activeToolKey === 'codex';
|
|
907
|
+
}
|
|
908
|
+
|
|
803
909
|
function setClaudeModeEnabled(enabled) {
|
|
804
|
-
|
|
910
|
+
const codexChat = isCodexSession() && codexState.presentation === 'structured';
|
|
911
|
+
const structured = enabled || codexChat;
|
|
912
|
+
document.getElementById('terminal-container').style.display = structured ? 'none' : '';
|
|
805
913
|
document.getElementById('claude-chat-container').style.display = enabled ? 'block' : 'none';
|
|
914
|
+
document.getElementById('codex-chat-container').style.display = codexChat ? 'block' : 'none';
|
|
806
915
|
document.getElementById('claude-control-panel').style.display = enabled ? 'block' : 'none';
|
|
916
|
+
document.getElementById('codex-control-panel').style.display = codexChat ? 'block' : 'none';
|
|
917
|
+
document.getElementById('codex-terminal-switch').style.display = isCodexSession() ? '' : 'none';
|
|
807
918
|
document.getElementById('timer-btn').style.display = '';
|
|
808
|
-
document.getElementById('shortcut-rail').style.display =
|
|
809
|
-
document.getElementById('scroll-controls').style.display =
|
|
810
|
-
document.getElementById('cmd-input').placeholder = enabled ? 'Message Claude...' : 'Type a message...';
|
|
919
|
+
document.getElementById('shortcut-rail').style.display = structured ? 'none' : '';
|
|
920
|
+
document.getElementById('scroll-controls').style.display = structured ? 'none' : '';
|
|
921
|
+
document.getElementById('cmd-input').placeholder = enabled ? 'Message Claude...' : codexChat ? 'Message Codex...' : 'Type a message...';
|
|
811
922
|
updateTerminalControlsHeight();
|
|
812
923
|
}
|
|
813
924
|
|
|
814
925
|
function updateTerminalControlsHeight() {
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
return;
|
|
819
|
-
}
|
|
820
|
-
const baseHeight = claudeResumePanelOpen ? 308 : ((claudePickerOpen || claudeUsagePanelOpen) ? 322 : 154);
|
|
821
|
-
document.documentElement.style.setProperty('--terminal-controls-rest-height', `${baseHeight + (timedOpen ? 144 : 0)}px`);
|
|
926
|
+
const controls = document.getElementById('terminal-controls');
|
|
927
|
+
const measuredHeight = controls ? Math.ceil(controls.getBoundingClientRect().height) : 0;
|
|
928
|
+
document.documentElement.style.setProperty('--terminal-controls-rest-height', `${Math.max(0, measuredHeight)}px`);
|
|
822
929
|
}
|
|
823
930
|
|
|
824
931
|
function shortModelLabel(value, resolved) {
|
|
@@ -1903,6 +2010,214 @@
|
|
|
1903
2010
|
}));
|
|
1904
2011
|
}
|
|
1905
2012
|
|
|
2013
|
+
function codexText(text) { return escapeHtml(text || '').replace(/\n/g, '<br>'); }
|
|
2014
|
+
function codexJson(value) {
|
|
2015
|
+
if (typeof value === 'string') return value;
|
|
2016
|
+
try { return JSON.stringify(value || {}, null, 2); } catch (_) { return String(value || ''); }
|
|
2017
|
+
}
|
|
2018
|
+
function codexToolStatus(item) {
|
|
2019
|
+
const status = item.toolStatus || 'running';
|
|
2020
|
+
if (status === 'inProgress') return 'running';
|
|
2021
|
+
if (status === 'failed' || status === 'declined') return status;
|
|
2022
|
+
if (status === 'completed') return item.exitCode && item.exitCode !== 0 ? 'failed' : 'completed';
|
|
2023
|
+
return status;
|
|
2024
|
+
}
|
|
2025
|
+
function renderCodexDiff(diff) {
|
|
2026
|
+
return `<div class="codex-diff">${String(diff || '').split('\n').map(line => {
|
|
2027
|
+
const type = line.startsWith('+++') || line.startsWith('---') ? 'hunk' : line.startsWith('+') ? 'add' : line.startsWith('-') ? 'del' : line.startsWith('@@') ? 'hunk' : '';
|
|
2028
|
+
return `<div class="codex-diff-line ${type}">${escapeHtml(line || ' ')}</div>`;
|
|
2029
|
+
}).join('')}</div>`;
|
|
2030
|
+
}
|
|
2031
|
+
function normalizeCodexChanges(changes) {
|
|
2032
|
+
if (Array.isArray(changes)) return changes.filter(Boolean).map(change => [change.path || 'File', change]);
|
|
2033
|
+
if (changes && typeof changes === 'object') return Object.entries(changes);
|
|
2034
|
+
return [];
|
|
2035
|
+
}
|
|
2036
|
+
function codexChangeDiff(change = {}) {
|
|
2037
|
+
if (typeof change.diff === 'string') return change.diff;
|
|
2038
|
+
if (typeof change.unified_diff === 'string') return change.unified_diff;
|
|
2039
|
+
const kind = change.kind && typeof change.kind === 'object' ? change.kind : {};
|
|
2040
|
+
const type = change.type || kind.type || '';
|
|
2041
|
+
const oldText = change.modify?.old_content ?? change.old_content ?? change.oldContent ?? (type === 'delete' ? change.content : change.delete?.content) ?? '';
|
|
2042
|
+
const newText = change.modify?.new_content ?? change.new_content ?? change.newContent ?? (type === 'add' ? change.content : change.add?.content) ?? '';
|
|
2043
|
+
if (!oldText && !newText) return '';
|
|
2044
|
+
return `${String(oldText).split('\n').map(line => `-${line}`).join('\n')}\n${String(newText).split('\n').map(line => `+${line}`).join('\n')}`;
|
|
2045
|
+
}
|
|
2046
|
+
function renderCodexPatch(item) {
|
|
2047
|
+
const entries = normalizeCodexChanges(item.changes || item.input?.changes);
|
|
2048
|
+
if (!entries.length) return `<div class="codex-tool-body"><pre class="codex-tool-code">${escapeHtml(codexJson(item.input))}</pre></div>`;
|
|
2049
|
+
return entries.map(([path, change]) => {
|
|
2050
|
+
const kind = change?.type || change?.kind?.type || 'edit';
|
|
2051
|
+
const move = change?.move_path || change?.kind?.move_path;
|
|
2052
|
+
const diff = codexChangeDiff(change);
|
|
2053
|
+
return `<details class="codex-patch-file"><summary><span class="path">${escapeHtml(path)}${move ? ` → ${escapeHtml(move)}` : ''}</span><span class="codex-patch-kind">${escapeHtml(kind)}</span></summary>${diff ? renderCodexDiff(diff) : ''}</details>`;
|
|
2054
|
+
}).join('');
|
|
2055
|
+
}
|
|
2056
|
+
function renderCodexPermission(request, inline = false) {
|
|
2057
|
+
if (!request) return '';
|
|
2058
|
+
const pending = request.status === 'pending';
|
|
2059
|
+
const labels = { approved: 'Allowed once', approved_for_session: 'Allowed for session', denied: 'Denied', abort: 'Stopped' };
|
|
2060
|
+
const detail = request.reason || (request.input && Object.keys(request.input).length ? codexJson(request.input) : '');
|
|
2061
|
+
const content = `${inline ? `<div class="codex-inline-permission-title">${escapeHtml(request.title || 'Permission required')}</div>` : ''}${detail ? `<div>${codexText(detail)}</div>` : ''}${pending ? `<div class="claude-permission-actions"><button class="small-btn primary" onclick="respondCodexPermission('${escapeHtml(request.id)}', 'approved')">Yes</button><button class="small-btn" onclick="respondCodexPermission('${escapeHtml(request.id)}', 'approved_for_session')">Yes, for session</button><button class="small-btn danger" onclick="respondCodexPermission('${escapeHtml(request.id)}', 'abort')">Stop and explain</button></div>` : `<div class="codex-permission-result">${escapeHtml(labels[request.decision] || request.status)}</div>`}`;
|
|
2062
|
+
if (inline) return `<div class="codex-inline-permission">${content}</div>`;
|
|
2063
|
+
return `<div class="claude-tool claude-permission"><div class="claude-tool-header"><strong>${escapeHtml(request.title || 'Permission required')}</strong></div><div class="claude-tool-body">${content}</div></div>`;
|
|
2064
|
+
}
|
|
2065
|
+
function renderCodexTool(item, permission = null) {
|
|
2066
|
+
const status = codexToolStatus(item);
|
|
2067
|
+
const isError = status === 'failed' || Boolean(item.error) || (item.exitCode != null && item.exitCode !== 0);
|
|
2068
|
+
const runningClass = status === 'running' ? ' running' : '';
|
|
2069
|
+
if (item.name === 'CodexPatch') {
|
|
2070
|
+
return `<div class="codex-tool${isError ? ' error' : ''}">${renderCodexPatch(item)}${permission ? renderCodexPermission(permission, true) : ''}</div>`;
|
|
2071
|
+
}
|
|
2072
|
+
const command = item.name === 'CodexBash' ? item.command : item.title || item.tool || '';
|
|
2073
|
+
const icon = item.name === 'CodexBash' ? '>_' : item.name === 'McpTool' ? 'MCP' : item.name === 'Agent' ? 'A' : '•';
|
|
2074
|
+
const title = item.name === 'CodexBash' ? 'Command' : item.title || item.name || 'Tool';
|
|
2075
|
+
const result = item.result || (item.name === 'McpTool' || item.name === 'Agent' ? codexJson(item.input) : '');
|
|
2076
|
+
return `<details class="codex-tool${isError ? ' error' : ''}"><summary class="codex-tool-header"><span class="codex-tool-icon">${escapeHtml(icon)}</span><span class="codex-tool-title">${escapeHtml(title)}</span>${command && command !== title ? `<span class="codex-tool-command">${escapeHtml(command)}</span>` : '<span class="codex-tool-command"></span>'}<span class="codex-tool-state${runningClass}">${escapeHtml(status === 'completed' ? '' : status)}</span></summary>${result ? `<div class="codex-tool-body"><pre class="codex-tool-code">${escapeHtml(result)}</pre></div>` : ''}${permission ? renderCodexPermission(permission, true) : ''}</details>`;
|
|
2077
|
+
}
|
|
2078
|
+
function renderCodexToolGroup(items, permissionById, usedPermissions) {
|
|
2079
|
+
const running = items.some(item => codexToolStatus(item) === 'running');
|
|
2080
|
+
const failed = items.some(item => codexToolStatus(item) === 'failed' || item.error);
|
|
2081
|
+
const startedAt = Math.min(...items.map(item => Number(item.createdAt || Date.now())));
|
|
2082
|
+
const seconds = Math.max(1, Math.round((Date.now() - startedAt) / 1000));
|
|
2083
|
+
const tools = items.map(item => {
|
|
2084
|
+
const permission = permissionById.get(String(item.providerId || ''));
|
|
2085
|
+
if (permission) usedPermissions.add(permission.id);
|
|
2086
|
+
return renderCodexTool(item, permission);
|
|
2087
|
+
}).join('');
|
|
2088
|
+
return `<details class="codex-work-group"${running ? ' open' : ''}><summary>${running ? 'Working' : failed ? 'Work finished with errors' : `Worked for ${seconds}s`} · ${items.length} tools</summary><div class="codex-work-group-body">${tools}</div></details>`;
|
|
2089
|
+
}
|
|
2090
|
+
function renderCodexChat() {
|
|
2091
|
+
const container = document.getElementById('codex-chat-container');
|
|
2092
|
+
if (!container) return;
|
|
2093
|
+
const parts = [];
|
|
2094
|
+
const permissionById = new Map(codexPendingPermissions.map(item => [String(item.id), item]));
|
|
2095
|
+
const usedPermissions = new Set();
|
|
2096
|
+
const visible = codexMessages.filter(item => !['reasoning', 'turn-start', 'turn-end'].includes(item.kind));
|
|
2097
|
+
for (let i = 0; i < visible.length;) {
|
|
2098
|
+
const item = visible[i];
|
|
2099
|
+
if (item.kind === 'tool') {
|
|
2100
|
+
const tools = [];
|
|
2101
|
+
while (i < visible.length && visible[i].kind === 'tool') tools.push(visible[i++]);
|
|
2102
|
+
if (tools.length > 1) parts.push(renderCodexToolGroup(tools, permissionById, usedPermissions));
|
|
2103
|
+
else {
|
|
2104
|
+
const permission = permissionById.get(String(tools[0].providerId || ''));
|
|
2105
|
+
if (permission) usedPermissions.add(permission.id);
|
|
2106
|
+
parts.push(renderCodexTool(tools[0], permission));
|
|
2107
|
+
}
|
|
2108
|
+
continue;
|
|
2109
|
+
}
|
|
2110
|
+
if (item.kind === 'assistant') parts.push(`<div class="codex-message assistant claude-md">${renderMarkdown(item.text || '')}</div>`);
|
|
2111
|
+
else if (item.kind === 'user') parts.push(`<div class="codex-message user claude-md">${renderMarkdown(item.text || '')}</div>`);
|
|
2112
|
+
else parts.push(`<div class="codex-message ${escapeHtml(item.level === 'error' ? 'event error' : item.kind || 'event')}">${codexText(item.text)}</div>`);
|
|
2113
|
+
i += 1;
|
|
2114
|
+
}
|
|
2115
|
+
for (const request of codexPendingPermissions) if (!usedPermissions.has(request.id)) parts.push(renderCodexPermission(request));
|
|
2116
|
+
container.innerHTML = `<div class="codex-conversation">${parts.join('') || '<div class="codex-message event">Send a message to start Codex.</div>'}</div>`;
|
|
2117
|
+
requestAnimationFrame(() => { container.scrollTop = container.scrollHeight; });
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
function applyCodexState(state = {}) {
|
|
2121
|
+
codexState = { ...codexState, ...state };
|
|
2122
|
+
const permission = document.getElementById('codex-permission-select');
|
|
2123
|
+
if (permission) permission.value = codexState.permissionMode || 'on-request';
|
|
2124
|
+
const modelButton = document.getElementById('codex-model-btn');
|
|
2125
|
+
if (modelButton) modelButton.textContent = codexState.model ? codexState.model.replace(/^gpt-/, '').slice(0, 10) : 'Model';
|
|
2126
|
+
const abort = document.getElementById('codex-abort-btn');
|
|
2127
|
+
if (abort) abort.disabled = !codexState.canAbort;
|
|
2128
|
+
const terminal = document.getElementById('codex-terminal-switch');
|
|
2129
|
+
if (terminal) { terminal.textContent = codexState.presentation === 'terminal' ? 'CHAT' : 'TERM'; terminal.disabled = codexState.presentation === 'structured' && !codexState.canSwitchToTerminal; terminal.title = codexState.presentation === 'terminal' ? 'Return to Codex chat' : 'Switch to Codex terminal'; }
|
|
2130
|
+
renderCodexStateBar();
|
|
2131
|
+
renderCodexModelPanel();
|
|
2132
|
+
setClaudeModeEnabled(isClaudeSession());
|
|
2133
|
+
renderCodexChat();
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
function renderCodexStateBar() {
|
|
2137
|
+
const el = document.getElementById('codex-state-bar');
|
|
2138
|
+
if (!el) return;
|
|
2139
|
+
const pending = Number(codexState.pendingPermissionCount || codexPendingPermissions.filter(item => item.status === 'pending').length) || 0;
|
|
2140
|
+
const parts = [];
|
|
2141
|
+
if (pending || codexState.status === 'waiting_approval') parts.push(`<span class="claude-state-pill warn">${pending || 1} approval${pending === 1 ? '' : 's'}</span>`);
|
|
2142
|
+
else if (codexState.status === 'running') parts.push('<span class="claude-state-pill">Working</span>');
|
|
2143
|
+
el.innerHTML = parts.join('');
|
|
2144
|
+
el.style.display = parts.length ? 'flex' : 'none';
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
function toggleCodexModelPanel() {
|
|
2148
|
+
codexModelPanelOpen = !codexModelPanelOpen;
|
|
2149
|
+
codexResumePanelOpen = false;
|
|
2150
|
+
codexModelCandidate = codexState.model || codexState.models?.[0]?.id || null;
|
|
2151
|
+
document.getElementById('codex-resume-panel').classList.remove('active');
|
|
2152
|
+
renderCodexModelPanel();
|
|
2153
|
+
updateTerminalControlsHeight();
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
function renderCodexModelPanel() {
|
|
2157
|
+
const panel = document.getElementById('codex-model-panel');
|
|
2158
|
+
if (!panel) return;
|
|
2159
|
+
panel.classList.toggle('active', codexModelPanelOpen);
|
|
2160
|
+
if (!codexModelPanelOpen) { panel.innerHTML = ''; return; }
|
|
2161
|
+
const models = codexState.models || [];
|
|
2162
|
+
const candidate = models.find(item => item.id === codexModelCandidate) || models.find(item => item.id === codexState.model) || models[0];
|
|
2163
|
+
if (!candidate) { panel.innerHTML = '<div class="claude-resume-meta" style="padding:12px;">Loading models...</div>'; return; }
|
|
2164
|
+
codexModelCandidate = candidate.id;
|
|
2165
|
+
const efforts = candidate.efforts?.length ? candidate.efforts : [candidate.defaultEffort || 'medium'];
|
|
2166
|
+
panel.innerHTML = `<div class="codex-picker-column">${models.map(item => `<button class="codex-picker-option${item.id === candidate.id ? ' selected' : ''}" onclick="selectCodexModelCandidate(decodePathValue('${encodePathValue(item.id)}'))">${escapeHtml(item.label || item.id)}</button>`).join('')}</div><div class="codex-picker-column">${efforts.map(effort => `<button class="codex-picker-option${candidate.id === codexState.model && effort === codexState.effort ? ' selected' : ''}" onclick="chooseCodexModelEffort(decodePathValue('${encodePathValue(candidate.id)}'), decodePathValue('${encodePathValue(effort)}'))">${escapeHtml(effort)}</button>`).join('')}</div>`;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
function selectCodexModelCandidate(model) { codexModelCandidate = model; renderCodexModelPanel(); }
|
|
2170
|
+
function chooseCodexModelEffort(model, effort) {
|
|
2171
|
+
codexModelPanelOpen = false;
|
|
2172
|
+
applyCodexState({ model, effort });
|
|
2173
|
+
sendCodexSettings({ model, effort });
|
|
2174
|
+
updateTerminalControlsHeight();
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
function applyCodexEvent(event) {
|
|
2178
|
+
if (!event) return;
|
|
2179
|
+
if (event.type === 'message' && event.message) codexMessages.push(event.message);
|
|
2180
|
+
else if (event.type === 'message-updated' && event.message) { const i = codexMessages.findIndex(item => item.id === event.message.id); if (i >= 0) codexMessages[i] = event.message; else codexMessages.push(event.message); }
|
|
2181
|
+
else if (event.type === 'history-reset') codexMessages = event.messages || [];
|
|
2182
|
+
else if (event.type === 'permission-request' && event.request) { codexPendingPermissions = [...codexPendingPermissions.filter(item => item.id !== event.request.id), event.request]; }
|
|
2183
|
+
else if (event.type === 'permission-updated' && event.request) codexPendingPermissions = codexPendingPermissions.map(item => item.id === event.request.id ? event.request : item);
|
|
2184
|
+
if (event.state) applyCodexState(event.state); else renderCodexChat();
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
function sendCodexSettings(settings) { if (currentSocket?.readyState === 1) currentSocket.send(JSON.stringify({ type: 'codex-settings', settings })); }
|
|
2188
|
+
function updateCodexSettingsFromControls() { const permissionMode = document.getElementById('codex-permission-select').value; applyCodexState({ permissionMode }); sendCodexSettings({ permissionMode }); }
|
|
2189
|
+
function abortCodexSession() { if (currentSocket?.readyState === 1) currentSocket.send(JSON.stringify({ type: 'codex-abort' })); }
|
|
2190
|
+
function respondCodexPermission(id, decision) { if (currentSocket?.readyState === 1) currentSocket.send(JSON.stringify({ type: 'codex-permission', id, decision })); }
|
|
2191
|
+
async function toggleCodexResumePanel() {
|
|
2192
|
+
codexResumePanelOpen = !codexResumePanelOpen;
|
|
2193
|
+
codexModelPanelOpen = false;
|
|
2194
|
+
document.getElementById('codex-model-panel').classList.remove('active');
|
|
2195
|
+
const panel = document.getElementById('codex-resume-panel');
|
|
2196
|
+
panel.classList.toggle('active', codexResumePanelOpen);
|
|
2197
|
+
updateTerminalControlsHeight();
|
|
2198
|
+
if (!codexResumePanelOpen) return;
|
|
2199
|
+
panel.innerHTML = '<div class="claude-resume-meta" style="padding:12px;">Loading sessions...</div>';
|
|
2200
|
+
try {
|
|
2201
|
+
const res = await fetchWithTimeout(`/api/sessions/${activeSessionId}/codex-resume-threads`, {}, 30000);
|
|
2202
|
+
const data = await res.json();
|
|
2203
|
+
if (!res.ok || !data.success) throw new Error(data.error || 'Failed to load Codex sessions');
|
|
2204
|
+
const items = data.items || [];
|
|
2205
|
+
panel.innerHTML = items.length ? items.map(item => `<button class="claude-resume-item" onclick="selectCodexResumeThread(decodePathValue('${encodePathValue(item.id)}'))"><div class="claude-resume-title"><span>${escapeHtml((item.preview || 'Codex session').slice(0, 48))}${item.current ? ' · current' : ''}</span><span>${escapeHtml(item.updatedAt ? new Date(item.updatedAt).toLocaleString() : '')}</span></div><div class="claude-resume-meta">${escapeHtml(item.id.slice(0, 12))}</div></button>`).join('') : '<div class="claude-resume-meta" style="padding:12px;">No Codex sessions found for this folder.</div>';
|
|
2206
|
+
} catch (e) { panel.innerHTML = `<div class="claude-resume-meta" style="padding:12px;color:#ff6b61;">${escapeHtml(e.message)}</div>`; }
|
|
2207
|
+
}
|
|
2208
|
+
async function selectCodexResumeThread(threadId) {
|
|
2209
|
+
const res = await fetchWithTimeout(`/api/sessions/${activeSessionId}/codex-resume`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ threadId }) }, 30000);
|
|
2210
|
+
if (!res.ok) { alert((await res.json()).error || 'Unable to resume Codex thread'); return; }
|
|
2211
|
+
codexResumePanelOpen = false;
|
|
2212
|
+
document.getElementById('codex-resume-panel').classList.remove('active');
|
|
2213
|
+
updateTerminalControlsHeight();
|
|
2214
|
+
}
|
|
2215
|
+
async function toggleCodexPresentation() {
|
|
2216
|
+
const presentation = codexState.presentation === 'terminal' ? 'structured' : 'terminal';
|
|
2217
|
+
const res = await fetchWithTimeout(`/api/sessions/${activeSessionId}/codex-presentation`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ presentation }) }, 30000);
|
|
2218
|
+
if (!res.ok) alert((await res.json()).error || 'Unable to switch Codex interface');
|
|
2219
|
+
}
|
|
2220
|
+
|
|
1906
2221
|
function joinSession(id, sessionName, toolKey = null) {
|
|
1907
2222
|
stopTimedInputTimers();
|
|
1908
2223
|
activeSessionId = id;
|
|
@@ -1926,6 +2241,10 @@
|
|
|
1926
2241
|
initClaudeSession(sessionId);
|
|
1927
2242
|
return;
|
|
1928
2243
|
}
|
|
2244
|
+
if (isCodexSession() && codexState.presentation === 'structured') {
|
|
2245
|
+
initCodexSession(sessionId);
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
1929
2248
|
if (typeof Terminal === 'undefined') {
|
|
1930
2249
|
alert('Terminal library not loaded yet.');
|
|
1931
2250
|
showLobby();
|
|
@@ -1959,6 +2278,14 @@
|
|
|
1959
2278
|
const msg = JSON.parse(e.data);
|
|
1960
2279
|
if (msg.type === 'output') term.write(msg.data);
|
|
1961
2280
|
if (msg.type === 'reset') term.reset();
|
|
2281
|
+
if (msg.type === 'codex-event' && isCodexSession()) {
|
|
2282
|
+
applyCodexEvent(msg.event);
|
|
2283
|
+
if (msg.event?.type === 'presentation' && msg.event.presentation === 'structured') {
|
|
2284
|
+
currentSocket.close();
|
|
2285
|
+
currentSocket = null;
|
|
2286
|
+
initCodexSession(sessionId);
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
1962
2289
|
if (msg.type === 'exit') showLobby();
|
|
1963
2290
|
};
|
|
1964
2291
|
}
|
|
@@ -2010,6 +2337,38 @@
|
|
|
2010
2337
|
};
|
|
2011
2338
|
}
|
|
2012
2339
|
|
|
2340
|
+
function initCodexSession(sessionId) {
|
|
2341
|
+
codexMessages = [];
|
|
2342
|
+
codexPendingPermissions = [];
|
|
2343
|
+
codexModelPanelOpen = false;
|
|
2344
|
+
codexModelCandidate = null;
|
|
2345
|
+
codexResumePanelOpen = false;
|
|
2346
|
+
document.getElementById('codex-model-panel').classList.remove('active');
|
|
2347
|
+
document.getElementById('codex-resume-panel').classList.remove('active');
|
|
2348
|
+
codexState = { permissionMode: 'on-request', model: null, effort: null, status: 'idle', threadId: null, presentation: 'structured', models: [], canAbort: false, canSwitchToTerminal: false, canSwitchToStructured: false };
|
|
2349
|
+
setClaudeModeEnabled(false);
|
|
2350
|
+
applyCodexState(codexState);
|
|
2351
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
2352
|
+
currentSocket = new WebSocket(protocol + '//' + window.location.host + '?sessionId=' + sessionId);
|
|
2353
|
+
currentSocket.onmessage = (e) => {
|
|
2354
|
+
const msg = JSON.parse(e.data);
|
|
2355
|
+
if (msg.type === 'codex-snapshot' && msg.snapshot) {
|
|
2356
|
+
codexMessages = msg.snapshot.messages || [];
|
|
2357
|
+
codexPendingPermissions = msg.snapshot.pendingPermissions || [];
|
|
2358
|
+
applyCodexState(msg.snapshot.state || {});
|
|
2359
|
+
}
|
|
2360
|
+
if (msg.type === 'codex-event') {
|
|
2361
|
+
applyCodexEvent(msg.event);
|
|
2362
|
+
if (msg.event?.type === 'presentation' && msg.event.presentation === 'terminal') {
|
|
2363
|
+
currentSocket.close();
|
|
2364
|
+
currentSocket = null;
|
|
2365
|
+
initTerminal(sessionId);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
if (msg.type === 'exit') showLobby();
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2013
2372
|
function sendWS(data) {
|
|
2014
2373
|
if (currentSocket && currentSocket.readyState === 1) currentSocket.send(JSON.stringify({ type: 'input', data }));
|
|
2015
2374
|
}
|
|
@@ -2228,6 +2587,12 @@
|
|
|
2228
2587
|
inputEl.style.height = '38px';
|
|
2229
2588
|
return;
|
|
2230
2589
|
}
|
|
2590
|
+
if (val && isCodexSession() && codexState.presentation === 'structured') {
|
|
2591
|
+
if (currentSocket && currentSocket.readyState === 1) currentSocket.send(JSON.stringify({ type: 'codex-input', text: val }));
|
|
2592
|
+
inputEl.value = '';
|
|
2593
|
+
inputEl.style.height = '38px';
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2231
2596
|
if (val) {
|
|
2232
2597
|
const formattedVal = val.replace(/\n/g, '\r');
|
|
2233
2598
|
sendWS(formattedVal);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glad-web",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Glad transforms terminal-based AI coding tools into a polished, mobile-friendly local Web interface.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
],
|
|
28
28
|
"author": "Glad Team",
|
|
29
29
|
"license": "MIT",
|
|
30
|
-
"homepage": "https://github.com/
|
|
30
|
+
"homepage": "https://github.com/Anonymous/Glad",
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|
|
33
|
-
"url": "git+https://github.com/
|
|
33
|
+
"url": "git+https://github.com/Anonymous/Glad.git"
|
|
34
34
|
},
|
|
35
35
|
"bugs": {
|
|
36
|
-
"url": "https://github.com/
|
|
36
|
+
"url": "https://github.com/Anonymous/Glad/issues"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=18.0.0"
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"files": [
|
|
42
42
|
"bin/",
|
|
43
43
|
"lib/",
|
|
44
|
+
"!lib/**/*.test.js",
|
|
44
45
|
"assets/logo.svg",
|
|
45
46
|
"README.md"
|
|
46
47
|
],
|