jinzd-ai-cli 0.4.307 → 0.4.308
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 +1 -0
- package/THIRD_PARTY_NOTICES.md +3 -0
- package/dist/{agent-client-6GX6QQDU.js → agent-client-TIEAYZXV.js} +4 -1
- package/dist/{auth-PE3Z5OHS.js → auth-QTQNZ6IX.js} +2 -2
- package/dist/{batch-HMADXNOD.js → batch-S7XLEEOH.js} +3 -3
- package/dist/{chat-index-2D5GK2DB.js → chat-index-7CLR4CBG.js} +4 -3
- package/dist/{chat-index-DGUOUUQW.js → chat-index-RLVLQRRC.js} +3 -2
- package/dist/{chunk-SJFZPS65.js → chunk-2DYQDLLF.js} +1 -1
- package/dist/{chunk-VAV2IJ3R.js → chunk-2MNUMLN4.js} +1 -1
- package/dist/chunk-2XMUCC42.js +67 -0
- package/dist/{chunk-5GQL4TSZ.js → chunk-3537CQ5M.js} +2 -2
- package/dist/{chunk-OAXLMF3U.js → chunk-3YVNDYOY.js} +1 -1
- package/dist/{chunk-RYQBBEMM.js → chunk-4PR5AVJ5.js} +115 -19
- package/dist/{chunk-GHWZVPUV.js → chunk-6JHACXB3.js} +7 -5
- package/dist/{chunk-CIM2PV2F.js → chunk-7OHXFTZO.js} +2 -2
- package/dist/{chunk-IUVDZVZ4.js → chunk-AXTLYOA7.js} +24 -17
- package/dist/{chunk-XJOK5353.js → chunk-B3MPYI4E.js} +2 -2
- package/dist/{chunk-3CKJOTVM.js → chunk-BGZN4K7Q.js} +4 -4
- package/dist/chunk-BMLQPSHP.js +69 -0
- package/dist/{chunk-NRSYBKWA.js → chunk-C7CKDFJS.js} +1 -1
- package/dist/{chunk-NQJSPMY2.js → chunk-E2PNXNKI.js} +4 -4
- package/dist/chunk-FVXNEZEW.js +161 -0
- package/dist/{chunk-YKJO3SI4.js → chunk-G6DVGQ4I.js} +1 -1
- package/dist/{chunk-YFDQIUQ3.js → chunk-HC33C4U3.js} +18 -18
- package/dist/chunk-JJFJWD35.js +162 -0
- package/dist/{chunk-KRCYR46A.js → chunk-JJNUASMJ.js} +264 -55
- package/dist/{chunk-NYNSYLFY.js → chunk-JL44HGZC.js} +1 -1
- package/dist/{chunk-NUJTNH76.js → chunk-LBWKMTT3.js} +1 -1
- package/dist/{chunk-AHL6KOGM.js → chunk-LR3TGZWQ.js} +2 -2
- package/dist/{chunk-WQ3OMEC4.js → chunk-M6HLYG33.js} +1 -1
- package/dist/{chunk-I4GQRMFV.js → chunk-M6YV5KSS.js} +6 -4
- package/dist/{chunk-3TBXHLSC.js → chunk-NLK45GUS.js} +1 -1
- package/dist/{chunk-KBDKKHXB.js → chunk-O6CGOVD4.js} +2 -2
- package/dist/chunk-QMFMST2T.js +39 -0
- package/dist/{chunk-MI4SFZGX.js → chunk-RMEJR3AW.js} +5 -2
- package/dist/{chunk-UFW4S3RU.js → chunk-RVMCY6DP.js} +1 -1
- package/dist/{chunk-LF67HWWR.js → chunk-RWRZVQCB.js} +1 -1
- package/dist/chunk-SXIJLSVF.js +41 -0
- package/dist/chunk-TDQW2YHK.js +65 -0
- package/dist/{chunk-L2RJPVHV.js → chunk-TPTFV3Y6.js} +266 -512
- package/dist/{chunk-45UVJXFQ.js → chunk-W2UOVGRC.js} +1 -1
- package/dist/{chunk-VXEF2SWG.js → chunk-WT252ZDV.js} +2 -2
- package/dist/{chunk-4W6VDVQU.js → chunk-WVEIUSXE.js} +246 -56
- package/dist/{chunk-AQF6IXSR.js → chunk-YBZM7PHI.js} +4 -4
- package/dist/{ci-QD2Q7NWY.js → ci-5HONSUAS.js} +7 -7
- package/dist/{ci-format-42XIZO5P.js → ci-format-URUH3ZZ5.js} +2 -2
- package/dist/{constants-NMASHFDL.js → constants-BLDBI7IG.js} +1 -1
- package/dist/{constants-5CMEFZQB.js → constants-FG27DQMS.js} +1 -1
- package/dist/doctor-cli-QQLMNJN7.js +18 -0
- package/dist/electron-server.js +886 -828
- package/dist/file-checkpoint-64A2AXHE.js +7 -0
- package/dist/{file-checkpoint-NKBHGC7L.js → file-checkpoint-VVPUJNCI.js} +2 -1
- package/dist/{hub-ZLF6GMQD.js → hub-GGFW3DCC.js} +3 -3
- package/dist/{hub-server-CBKCP5VD.js → hub-server-JLC7CNP7.js} +55 -17
- package/dist/index.js +42 -40
- package/dist/{indexer-P3FPRTPJ.js → indexer-GKIWSSRP.js} +3 -3
- package/dist/indexer-VRXDZ74A.js +10 -0
- package/dist/{persist-S77WRVLD.js → persist-ZZXRWFBX.js} +4 -4
- package/dist/{persistent-memory-GJE7HKVK.js → persistent-memory-UNLCXUWH.js} +3 -3
- package/dist/{persistent-memory-MBSBTBGY.js → persistent-memory-YYWIN6BG.js} +3 -3
- package/dist/{pr-SXRW24JG.js → pr-YCFGPFI7.js} +7 -7
- package/dist/{project-trust-MUG325AW.js → project-trust-6CJB5ZMX.js} +1 -1
- package/dist/{project-trust-NKYHL3VZ.js → project-trust-KGG2BWKC.js} +1 -1
- package/dist/run-tests-GHY4BYDE.js +13 -0
- package/dist/run-tests-KRNMFXAN.js +12 -0
- package/dist/{semantic-7GM5M4MU.js → semantic-N227CLSC.js} +4 -4
- package/dist/{semantic-QOBAXEQ4.js → semantic-TRQAZSRY.js} +4 -4
- package/dist/{server-MO3EU2XD.js → server-73UBHSFV.js} +16 -14
- package/dist/{server-GGEO7SA2.js → server-QRAWSG4Z.js} +231 -103
- package/dist/{store-SIKHCUYJ.js → store-2N6PPPBP.js} +2 -2
- package/dist/{store-CMSSWZF7.js → store-76VVFDXM.js} +2 -2
- package/dist/{task-orchestrator-JGEEQ2OE.js → task-orchestrator-GI3RGLZI.js} +15 -14
- package/dist/{usage-B7RIAPPT.js → usage-GWTIGZF5.js} +4 -4
- package/dist/{vector-store-JAXWDZYW.js → vector-store-T2DVUMY4.js} +2 -2
- package/dist/{vector-store-PWIOQFTP.js → vector-store-V6UGEYWK.js} +2 -2
- package/dist/web/client/app.js +7 -0
- package/dist/web/client/app.js.br +0 -0
- package/dist/web/client/app.js.gz +0 -0
- package/dist/web/client/util.js +14 -23
- package/dist/web/client/util.js.br +0 -0
- package/dist/web/client/util.js.gz +0 -0
- package/dist/web/client/vendor/DOMPurify-LICENSE.txt +202 -0
- package/dist/web/client/vendor/purify.es.mjs +2722 -0
- package/dist/web/client/vendor/purify.es.mjs.br +0 -0
- package/dist/web/client/vendor/purify.es.mjs.gz +0 -0
- package/package.json +4 -2
- package/dist/chunk-4BKXL7SM.js +0 -98
- package/dist/chunk-6BUTA5VW.js +0 -38
- package/dist/chunk-IW3Q7AE5.js +0 -40
- package/dist/chunk-SKET65WZ.js +0 -96
- package/dist/doctor-cli-IOVSHBDI.js +0 -18
- package/dist/file-checkpoint-CGH6OJVI.js +0 -6
- package/dist/indexer-FPKY7LCT.js +0 -10
- package/dist/run-tests-EQCAMFQE.js +0 -10
- package/dist/run-tests-V3N7YV3P.js +0 -9
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
AuthRateLimiter,
|
|
4
|
+
WebAccess,
|
|
5
|
+
equalToken
|
|
6
|
+
} from "./chunk-TDQW2YHK.js";
|
|
2
7
|
import {
|
|
3
8
|
DiscussionOrchestrator,
|
|
4
9
|
getPreset,
|
|
@@ -8,10 +13,10 @@ import "./chunk-C2Z77RTU.js";
|
|
|
8
13
|
import {
|
|
9
14
|
AuthManager,
|
|
10
15
|
TOKEN_EXPIRY_MS
|
|
11
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-4PR5AVJ5.js";
|
|
12
17
|
import {
|
|
13
18
|
persistDiscussion
|
|
14
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-LBWKMTT3.js";
|
|
15
20
|
import {
|
|
16
21
|
AUTO_COMPACT_INSTRUCTION,
|
|
17
22
|
McpManager,
|
|
@@ -81,7 +86,7 @@ import {
|
|
|
81
86
|
skillHistoryNote,
|
|
82
87
|
snapshotFile,
|
|
83
88
|
stripRoutingTags
|
|
84
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-HC33C4U3.js";
|
|
85
90
|
import {
|
|
86
91
|
CNY_PER_USD,
|
|
87
92
|
CostTracker,
|
|
@@ -90,7 +95,7 @@ import {
|
|
|
90
95
|
getCostCurrency,
|
|
91
96
|
getPricing,
|
|
92
97
|
setCostCurrency
|
|
93
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-G6DVGQ4I.js";
|
|
94
99
|
import {
|
|
95
100
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS,
|
|
96
101
|
ToolExecutor,
|
|
@@ -121,12 +126,11 @@ import {
|
|
|
121
126
|
resolveAgentConfig,
|
|
122
127
|
resolveWriteFileArgs,
|
|
123
128
|
runSafePhases,
|
|
124
|
-
runWithSessionKey,
|
|
125
129
|
setPreferredAgentName,
|
|
126
130
|
spawnAgentContext,
|
|
127
131
|
truncateOutput,
|
|
128
132
|
undoStack
|
|
129
|
-
} from "./chunk-
|
|
133
|
+
} from "./chunk-TPTFV3Y6.js";
|
|
130
134
|
import {
|
|
131
135
|
buildReviewPrompt,
|
|
132
136
|
buildSecurityReviewPrompt
|
|
@@ -134,7 +138,7 @@ import {
|
|
|
134
138
|
import {
|
|
135
139
|
thinkingParamsFor
|
|
136
140
|
} from "./chunk-6YZEZFX5.js";
|
|
137
|
-
import "./chunk-
|
|
141
|
+
import "./chunk-6JHACXB3.js";
|
|
138
142
|
import {
|
|
139
143
|
addMemoryEntry,
|
|
140
144
|
backupMemoryStore,
|
|
@@ -153,18 +157,18 @@ import {
|
|
|
153
157
|
restoreMemoryEntries,
|
|
154
158
|
updateMemoryApproval,
|
|
155
159
|
updateMemoryEntry
|
|
156
|
-
} from "./chunk-
|
|
157
|
-
import "./chunk-
|
|
158
|
-
import "./chunk-
|
|
159
|
-
import "./chunk-
|
|
160
|
-
import "./chunk-
|
|
160
|
+
} from "./chunk-LR3TGZWQ.js";
|
|
161
|
+
import "./chunk-RWRZVQCB.js";
|
|
162
|
+
import "./chunk-B3MPYI4E.js";
|
|
163
|
+
import "./chunk-M6HLYG33.js";
|
|
164
|
+
import "./chunk-C7CKDFJS.js";
|
|
161
165
|
import "./chunk-KHYD3WXE.js";
|
|
162
166
|
import "./chunk-5C76XDDF.js";
|
|
163
167
|
import {
|
|
164
168
|
SessionManager,
|
|
165
169
|
getContentText
|
|
166
|
-
} from "./chunk-
|
|
167
|
-
import "./chunk-
|
|
170
|
+
} from "./chunk-AXTLYOA7.js";
|
|
171
|
+
import "./chunk-JL44HGZC.js";
|
|
168
172
|
import {
|
|
169
173
|
scanString
|
|
170
174
|
} from "./chunk-3FEZSLGI.js";
|
|
@@ -172,7 +176,7 @@ import {
|
|
|
172
176
|
buildDoctorReport,
|
|
173
177
|
formatDoctorReport,
|
|
174
178
|
loadContextFiles
|
|
175
|
-
} from "./chunk-
|
|
179
|
+
} from "./chunk-E2PNXNKI.js";
|
|
176
180
|
import {
|
|
177
181
|
describePlugin,
|
|
178
182
|
getActivePluginAssets,
|
|
@@ -187,14 +191,14 @@ import {
|
|
|
187
191
|
runTool,
|
|
188
192
|
setPluginEnabled,
|
|
189
193
|
trustPlugin
|
|
190
|
-
} from "./chunk-
|
|
194
|
+
} from "./chunk-3537CQ5M.js";
|
|
191
195
|
import "./chunk-RS7SKYTS.js";
|
|
192
196
|
import {
|
|
193
197
|
ProviderRegistry
|
|
194
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-WT252ZDV.js";
|
|
195
199
|
import {
|
|
196
200
|
ConfigManager
|
|
197
|
-
} from "./chunk-
|
|
201
|
+
} from "./chunk-YBZM7PHI.js";
|
|
198
202
|
import {
|
|
199
203
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
200
204
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -210,7 +214,7 @@ import {
|
|
|
210
214
|
runAgentLoop,
|
|
211
215
|
stripToolCallReminder,
|
|
212
216
|
teeStreamErrorSummary
|
|
213
|
-
} from "./chunk-
|
|
217
|
+
} from "./chunk-RMEJR3AW.js";
|
|
214
218
|
import "./chunk-TU3L3PW7.js";
|
|
215
219
|
import {
|
|
216
220
|
formatGitContextForPrompt,
|
|
@@ -219,13 +223,15 @@ import {
|
|
|
219
223
|
} from "./chunk-HOSJZMQS.js";
|
|
220
224
|
import {
|
|
221
225
|
atomicWriteFileSync
|
|
222
|
-
} from "./chunk-
|
|
226
|
+
} from "./chunk-BMLQPSHP.js";
|
|
223
227
|
import {
|
|
224
228
|
applyConfigCommand,
|
|
225
229
|
maskConfigSecrets
|
|
226
230
|
} from "./chunk-XNFIYS7G.js";
|
|
227
|
-
import
|
|
228
|
-
|
|
231
|
+
import {
|
|
232
|
+
assertReadablePath
|
|
233
|
+
} from "./chunk-JJFJWD35.js";
|
|
234
|
+
import "./chunk-JJNUASMJ.js";
|
|
229
235
|
import {
|
|
230
236
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
231
237
|
AUTHOR,
|
|
@@ -241,7 +247,11 @@ import {
|
|
|
241
247
|
SKILLS_DIR_NAME,
|
|
242
248
|
VERSION,
|
|
243
249
|
buildUserIdentityPrompt
|
|
244
|
-
} from "./chunk-
|
|
250
|
+
} from "./chunk-2MNUMLN4.js";
|
|
251
|
+
import {
|
|
252
|
+
runWithExecutionContext,
|
|
253
|
+
runWithSessionKey
|
|
254
|
+
} from "./chunk-SXIJLSVF.js";
|
|
245
255
|
|
|
246
256
|
// src/web/server.ts
|
|
247
257
|
import express from "express";
|
|
@@ -968,7 +978,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
|
|
|
968
978
|
Cost: ${formatCost(cost)}` : "";
|
|
969
979
|
let memoryLine = "";
|
|
970
980
|
try {
|
|
971
|
-
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-
|
|
981
|
+
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-YYWIN6BG.js");
|
|
972
982
|
const pending = countPendingMemories2(ctx.config.getConfigDir());
|
|
973
983
|
if (pending > 0) memoryLine = `
|
|
974
984
|
Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
|
|
@@ -1591,7 +1601,7 @@ async function handleRewind(args, ctx) {
|
|
|
1591
1601
|
ctx.send({ type: "error", message: intent.message });
|
|
1592
1602
|
return;
|
|
1593
1603
|
}
|
|
1594
|
-
const { fileCheckpoints } = await import("./file-checkpoint-
|
|
1604
|
+
const { fileCheckpoints } = await import("./file-checkpoint-VVPUJNCI.js");
|
|
1595
1605
|
if (intent.kind === "list") {
|
|
1596
1606
|
const rows = buildRewindList(session.messages, fileCheckpoints.getMessageIndices());
|
|
1597
1607
|
ctx.send({
|
|
@@ -1897,7 +1907,7 @@ async function handleTest(args, ctx) {
|
|
|
1897
1907
|
const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
|
|
1898
1908
|
testArgs = isCommand ? { command: argStr } : { filter: argStr };
|
|
1899
1909
|
}
|
|
1900
|
-
const runTests = ctx.runTests ?? (await import("./run-tests-
|
|
1910
|
+
const runTests = ctx.runTests ?? (await import("./run-tests-GHY4BYDE.js")).executeTests;
|
|
1901
1911
|
const report = await runTests(testArgs);
|
|
1902
1912
|
ctx.send({ type: "info", message: report });
|
|
1903
1913
|
} catch (err) {
|
|
@@ -2074,9 +2084,9 @@ async function handleContext(_args, ctx) {
|
|
|
2074
2084
|
async function handleIndex(args, ctx) {
|
|
2075
2085
|
const sub = (args[0] ?? "status").toLowerCase();
|
|
2076
2086
|
const root = process.cwd();
|
|
2077
|
-
const { loadIndex, clearIndex } = await import("./store-
|
|
2078
|
-
const { indexProject } = await import("./indexer-
|
|
2079
|
-
const { loadVectorStore, clearVectorStore } = await import("./vector-store-
|
|
2087
|
+
const { loadIndex, clearIndex } = await import("./store-76VVFDXM.js");
|
|
2088
|
+
const { indexProject } = await import("./indexer-GKIWSSRP.js");
|
|
2089
|
+
const { loadVectorStore, clearVectorStore } = await import("./vector-store-V6UGEYWK.js");
|
|
2080
2090
|
if (sub === "status") {
|
|
2081
2091
|
const idx = loadIndex(root);
|
|
2082
2092
|
const vec = loadVectorStore(root);
|
|
@@ -2126,7 +2136,7 @@ async function handleIndex(args, ctx) {
|
|
|
2126
2136
|
message: `Building semantic index for ${idx.symbolCount} symbols\u2026 (first run downloads ~117 MB model)`
|
|
2127
2137
|
});
|
|
2128
2138
|
try {
|
|
2129
|
-
const { rebuildSemanticIndex } = await import("./semantic-
|
|
2139
|
+
const { rebuildSemanticIndex } = await import("./semantic-N227CLSC.js");
|
|
2130
2140
|
const stats = await rebuildSemanticIndex(root);
|
|
2131
2141
|
const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
|
|
2132
2142
|
ctx.send({
|
|
@@ -2157,7 +2167,7 @@ async function handleMemory(args, ctx) {
|
|
|
2157
2167
|
if (intent.kind === "rebuild") {
|
|
2158
2168
|
ctx.send({ type: "info", message: rebuildStartMessage(intent.full) });
|
|
2159
2169
|
try {
|
|
2160
|
-
const { buildChatIndex } = await import("./chat-index-
|
|
2170
|
+
const { buildChatIndex } = await import("./chat-index-7CLR4CBG.js");
|
|
2161
2171
|
const stats = await buildChatIndex({ full: intent.full });
|
|
2162
2172
|
ctx.send({ type: "info", message: rebuildDoneMessage(stats) });
|
|
2163
2173
|
} catch (err) {
|
|
@@ -2166,14 +2176,14 @@ async function handleMemory(args, ctx) {
|
|
|
2166
2176
|
return;
|
|
2167
2177
|
}
|
|
2168
2178
|
if (intent.kind === "index-clear") {
|
|
2169
|
-
const { clearChatIndex } = await import("./chat-index-
|
|
2179
|
+
const { clearChatIndex } = await import("./chat-index-7CLR4CBG.js");
|
|
2170
2180
|
clearChatIndex();
|
|
2171
2181
|
ctx.send({ type: "info", message: "Chat memory index cleared (persistent memory untouched)." });
|
|
2172
2182
|
return;
|
|
2173
2183
|
}
|
|
2174
2184
|
if (intent.kind === "status") {
|
|
2175
|
-
const { getChatIndexStatus } = await import("./chat-index-
|
|
2176
|
-
const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-
|
|
2185
|
+
const { getChatIndexStatus } = await import("./chat-index-7CLR4CBG.js");
|
|
2186
|
+
const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-YYWIN6BG.js");
|
|
2177
2187
|
const memories = listMemoryEntries2(configDir, { includeExpired: true, includeRejected: true });
|
|
2178
2188
|
const injected = formatMemoryForPrompt2(configDir, process.cwd(), ctx.config.get("memory")?.maxChars);
|
|
2179
2189
|
const view = buildMemoryStatusView({
|
|
@@ -2196,8 +2206,8 @@ async function handleMemory(args, ctx) {
|
|
|
2196
2206
|
return;
|
|
2197
2207
|
}
|
|
2198
2208
|
if (intent.kind === "recall") {
|
|
2199
|
-
const { searchPersistentMemories, touchMemoryReferences } = await import("./persistent-memory-
|
|
2200
|
-
const { searchChatMemory } = await import("./chat-index-
|
|
2209
|
+
const { searchPersistentMemories, touchMemoryReferences } = await import("./persistent-memory-YYWIN6BG.js");
|
|
2210
|
+
const { searchChatMemory } = await import("./chat-index-7CLR4CBG.js");
|
|
2201
2211
|
const persistentHits = searchPersistentMemories(configDir, intent.query, process.cwd(), 3);
|
|
2202
2212
|
if (persistentHits.length > 0) {
|
|
2203
2213
|
touchMemoryReferences(configDir, persistentHits.map((h) => h.entry.id));
|
|
@@ -2317,7 +2327,7 @@ async function handleMemory(args, ctx) {
|
|
|
2317
2327
|
ctx.handleMemoryManage(intent.action, args[1], intent.action === "expire" ? args[2] : void 0);
|
|
2318
2328
|
} else if (intent.kind === "export") {
|
|
2319
2329
|
if (args[1] === "md") {
|
|
2320
|
-
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-
|
|
2330
|
+
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-YYWIN6BG.js");
|
|
2321
2331
|
ctx.send({
|
|
2322
2332
|
type: "export_data",
|
|
2323
2333
|
format: "md",
|
|
@@ -2941,7 +2951,18 @@ var SessionHandler = class _SessionHandler {
|
|
|
2941
2951
|
}))
|
|
2942
2952
|
});
|
|
2943
2953
|
}
|
|
2954
|
+
executionState = /* @__PURE__ */ new Map();
|
|
2955
|
+
connectionAbort = new AbortController();
|
|
2944
2956
|
async handleMessage(raw) {
|
|
2957
|
+
if (this.connectionAbort.signal.aborted && /"type"\s*:\s*"(?:chat|command|hub_start)"/.test(raw)) this.connectionAbort = new AbortController();
|
|
2958
|
+
return runWithExecutionContext({
|
|
2959
|
+
configDir: this.config.getConfigDir(),
|
|
2960
|
+
sessionKey: this._bashSessionKey,
|
|
2961
|
+
state: this.executionState,
|
|
2962
|
+
signal: this.connectionAbort.signal
|
|
2963
|
+
}, () => this.handleMessageScoped(raw));
|
|
2964
|
+
}
|
|
2965
|
+
async handleMessageScoped(raw) {
|
|
2945
2966
|
if (this.disconnected) return;
|
|
2946
2967
|
let msg;
|
|
2947
2968
|
try {
|
|
@@ -2952,6 +2973,7 @@ var SessionHandler = class _SessionHandler {
|
|
|
2952
2973
|
}
|
|
2953
2974
|
switch (msg.type) {
|
|
2954
2975
|
case "chat": {
|
|
2976
|
+
if (this.connectionAbort.signal.aborted) this.connectionAbort = new AbortController();
|
|
2955
2977
|
if (msg.messageId) {
|
|
2956
2978
|
if (typeof msg.messageId !== "string" || msg.messageId.length > 200) throw new Error("Invalid message ID");
|
|
2957
2979
|
const scope = this.config.getConfigDir();
|
|
@@ -3012,6 +3034,7 @@ var SessionHandler = class _SessionHandler {
|
|
|
3012
3034
|
return;
|
|
3013
3035
|
}
|
|
3014
3036
|
case "abort":
|
|
3037
|
+
this.connectionAbort.abort();
|
|
3015
3038
|
if (this.abortController) {
|
|
3016
3039
|
this.abortController.abort();
|
|
3017
3040
|
}
|
|
@@ -3035,8 +3058,16 @@ var SessionHandler = class _SessionHandler {
|
|
|
3035
3058
|
}
|
|
3036
3059
|
}
|
|
3037
3060
|
onDisconnect(closeSocket = true) {
|
|
3061
|
+
runWithExecutionContext({
|
|
3062
|
+
configDir: this.config.getConfigDir(),
|
|
3063
|
+
sessionKey: this._bashSessionKey,
|
|
3064
|
+
state: this.executionState
|
|
3065
|
+
}, () => this.disconnectScoped(closeSocket));
|
|
3066
|
+
}
|
|
3067
|
+
disconnectScoped(closeSocket) {
|
|
3038
3068
|
if (this.disconnected) return;
|
|
3039
3069
|
this.disconnected = true;
|
|
3070
|
+
this.connectionAbort.abort();
|
|
3040
3071
|
if (closeSocket && this.ws.readyState === this.ws.OPEN) this.ws.close(1001, "Connection closed; reconnect to restore session");
|
|
3041
3072
|
runLifecycleHooks(mergePluginHooks(this.config.get("hooks") ?? void 0, this.config.getConfigDir()), "Stop", { sessionId: this.sessions.current?.id }, { configDir: this.config.getConfigDir() });
|
|
3042
3073
|
this.toolExecutor.cancelAll();
|
|
@@ -4138,7 +4169,7 @@ Backup saved: ${result.backupPath}` : "";
|
|
|
4138
4169
|
return;
|
|
4139
4170
|
}
|
|
4140
4171
|
try {
|
|
4141
|
-
const { searchChatMemory, loadChatIndex } = await import("./chat-index-
|
|
4172
|
+
const { searchChatMemory, loadChatIndex } = await import("./chat-index-7CLR4CBG.js");
|
|
4142
4173
|
const loaded = loadChatIndex();
|
|
4143
4174
|
if (!loaded || loaded.idx.chunks.length === 0) {
|
|
4144
4175
|
this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
|
|
@@ -4174,7 +4205,7 @@ Backup saved: ${result.backupPath}` : "";
|
|
|
4174
4205
|
}
|
|
4175
4206
|
async handleMemoryStatus() {
|
|
4176
4207
|
try {
|
|
4177
|
-
const { getChatIndexStatus } = await import("./chat-index-
|
|
4208
|
+
const { getChatIndexStatus } = await import("./chat-index-7CLR4CBG.js");
|
|
4178
4209
|
const s = getChatIndexStatus();
|
|
4179
4210
|
this.send({
|
|
4180
4211
|
type: "memory_status",
|
|
@@ -4199,7 +4230,7 @@ Backup saved: ${result.backupPath}` : "";
|
|
|
4199
4230
|
type: "info",
|
|
4200
4231
|
message: full ? "\u{1F9E0} Rebuilding chat memory index (this may take a while on first run \u2014 ~117 MB embedder)." : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
|
|
4201
4232
|
});
|
|
4202
|
-
const { buildChatIndex } = await import("./chat-index-
|
|
4233
|
+
const { buildChatIndex } = await import("./chat-index-7CLR4CBG.js");
|
|
4203
4234
|
const stats = await buildChatIndex({
|
|
4204
4235
|
full,
|
|
4205
4236
|
onProgress: (p) => {
|
|
@@ -4363,6 +4394,10 @@ async function startWebServer(options = {}) {
|
|
|
4363
4394
|
console.log(`\u{1F916} ai-cli Web UI v${VERSION}`);
|
|
4364
4395
|
console.log(` Initializing...`);
|
|
4365
4396
|
const config = new ConfigManager();
|
|
4397
|
+
const authManager = new AuthManager(config.getConfigDir());
|
|
4398
|
+
if (!authManager.isEnabled() && !["localhost", "127.0.0.1", "::1"].includes(host)) {
|
|
4399
|
+
throw new Error("Network listening requires authentication. Create a user with aicli user create first.");
|
|
4400
|
+
}
|
|
4366
4401
|
await setupProxy(config.get("proxy"));
|
|
4367
4402
|
const providers = new ProviderRegistry();
|
|
4368
4403
|
const sessions = new SessionManager(config);
|
|
@@ -4396,7 +4431,7 @@ async function startWebServer(options = {}) {
|
|
|
4396
4431
|
const projectMcpResolved = mcpEnabled ? resolveProjectMcpPath() : null;
|
|
4397
4432
|
let projectMcpServers = {};
|
|
4398
4433
|
if (projectMcpResolved) {
|
|
4399
|
-
const { checkTrust } = await import("./project-trust-
|
|
4434
|
+
const { checkTrust } = await import("./project-trust-KGG2BWKC.js");
|
|
4400
4435
|
const verdict = checkTrust(config.getConfigDir(), projectMcpResolved);
|
|
4401
4436
|
if (verdict.trusted) {
|
|
4402
4437
|
projectMcpServers = loadProjectMcpConfig() ?? {};
|
|
@@ -4443,6 +4478,16 @@ async function startWebServer(options = {}) {
|
|
|
4443
4478
|
skillManager
|
|
4444
4479
|
};
|
|
4445
4480
|
const app = express();
|
|
4481
|
+
const access = new WebAccess(host, options.externalOrigin);
|
|
4482
|
+
const authLimits = new AuthRateLimiter();
|
|
4483
|
+
app.use((req, res, next) => {
|
|
4484
|
+
if (!access.accepts(req)) {
|
|
4485
|
+
res.status(403).json({ error: "Untrusted request origin or host" });
|
|
4486
|
+
return;
|
|
4487
|
+
}
|
|
4488
|
+
res.locals.externalSecure = !!options.externalOrigin?.startsWith("https://") && req.headers.host === new URL(options.externalOrigin).host;
|
|
4489
|
+
next();
|
|
4490
|
+
});
|
|
4446
4491
|
app.use((_req, res, next) => {
|
|
4447
4492
|
res.setHeader(
|
|
4448
4493
|
"Content-Security-Policy",
|
|
@@ -4471,19 +4516,23 @@ async function startWebServer(options = {}) {
|
|
|
4471
4516
|
const WS_MSG_RATE_PER_SEC = 30;
|
|
4472
4517
|
const WS_MSG_BURST = 60;
|
|
4473
4518
|
const WS_PREAUTH_TIMEOUT_MS = 3e4;
|
|
4474
|
-
const wss = new WebSocketServer({ server, maxPayload: WS_MAX_PAYLOAD })
|
|
4475
|
-
|
|
4519
|
+
const wss = new WebSocketServer({ server, maxPayload: WS_MAX_PAYLOAD, verifyClient: ({ req }) => {
|
|
4520
|
+
if (!access.accepts(req) || wss.clients.size >= 128) return false;
|
|
4521
|
+
if (req.headers.origin) return true;
|
|
4522
|
+
const cookie = parseCookie(req.headers.cookie ?? "");
|
|
4523
|
+
return equalToken(cookie.aicli_local, access.localToken) || !!authManager.verifyToken(cookie.aicli_token ?? "");
|
|
4524
|
+
} });
|
|
4476
4525
|
if (authManager.isEnabled()) {
|
|
4477
4526
|
console.log(` Auth: ${authManager.listUsers().length} user(s) registered`);
|
|
4478
4527
|
} else {
|
|
4479
|
-
console.log(
|
|
4480
|
-
if (host === "0.0.0.0" || host === "::") {
|
|
4481
|
-
console.log(" WARNING: Web UI is reachable from the network without authentication.");
|
|
4482
|
-
console.log(" Create a user first for LAN/team use: aicli user create <name>");
|
|
4483
|
-
}
|
|
4528
|
+
console.log(" Auth: local launch token (no users registered)");
|
|
4484
4529
|
}
|
|
4485
4530
|
const requireAuth = (req, res, next) => {
|
|
4486
|
-
if (!authManager.isEnabled())
|
|
4531
|
+
if (!authManager.isEnabled()) {
|
|
4532
|
+
if (equalToken(parseCookie(req.headers.cookie ?? "").aicli_local, access.localToken)) return next();
|
|
4533
|
+
res.status(401).json({ error: "Open the launch URL printed by aicli to authorize this browser" });
|
|
4534
|
+
return;
|
|
4535
|
+
}
|
|
4487
4536
|
const authHeader = req.headers.authorization;
|
|
4488
4537
|
const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
4489
4538
|
const cookieToken = parseCookie(req.headers.cookie ?? "")["aicli_token"];
|
|
@@ -4514,6 +4563,7 @@ async function startWebServer(options = {}) {
|
|
|
4514
4563
|
console.log(` Static files: ${clientDir}`);
|
|
4515
4564
|
const PRECOMPRESSED_TYPES = {
|
|
4516
4565
|
".js": "text/javascript; charset=utf-8",
|
|
4566
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
4517
4567
|
".css": "text/css; charset=utf-8",
|
|
4518
4568
|
".html": "text/html; charset=utf-8",
|
|
4519
4569
|
".json": "application/json; charset=utf-8",
|
|
@@ -4554,9 +4604,28 @@ async function startWebServer(options = {}) {
|
|
|
4554
4604
|
}
|
|
4555
4605
|
});
|
|
4556
4606
|
});
|
|
4557
|
-
app.use(express.json());
|
|
4558
|
-
app.post("/api/auth/
|
|
4607
|
+
app.use(express.json({ limit: "16kb" }));
|
|
4608
|
+
app.post("/api/auth/bootstrap", (req, res) => {
|
|
4609
|
+
if (!equalToken(req.body?.token, access.localToken)) {
|
|
4610
|
+
res.status(403).json({ error: "Invalid launch token" });
|
|
4611
|
+
return;
|
|
4612
|
+
}
|
|
4613
|
+
res.cookie("aicli_local", access.localToken, { httpOnly: true, sameSite: "strict", secure: isHttpsRequest(req) });
|
|
4614
|
+
res.json({ success: true });
|
|
4615
|
+
});
|
|
4616
|
+
app.use("/api/auth", (req, res, next) => {
|
|
4617
|
+
if (!authLimits.take(req.socket.remoteAddress ?? "unknown")) {
|
|
4618
|
+
res.status(429).json({ error: "Too many authentication attempts; try again later" });
|
|
4619
|
+
return;
|
|
4620
|
+
}
|
|
4621
|
+
next();
|
|
4622
|
+
});
|
|
4623
|
+
app.post("/api/auth/register", async (req, res) => {
|
|
4559
4624
|
const firstRun = !authManager.hasUsers();
|
|
4625
|
+
if (firstRun && !equalToken(parseCookie(req.headers.cookie ?? "").aicli_local, access.localToken)) {
|
|
4626
|
+
res.status(403).json({ error: "Open the launch URL before enabling authentication" });
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4560
4629
|
if (!firstRun) {
|
|
4561
4630
|
const authHeader = req.headers.authorization;
|
|
4562
4631
|
const token2 = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
@@ -4572,23 +4641,24 @@ async function startWebServer(options = {}) {
|
|
|
4572
4641
|
res.status(400).json({ error: "Username and password required" });
|
|
4573
4642
|
return;
|
|
4574
4643
|
}
|
|
4575
|
-
const err = authManager.
|
|
4644
|
+
const err = await authManager.registerAsync(username, password);
|
|
4576
4645
|
if (err) {
|
|
4577
4646
|
res.status(400).json({ error: err });
|
|
4578
4647
|
return;
|
|
4579
4648
|
}
|
|
4580
|
-
const token = authManager.
|
|
4649
|
+
const token = await authManager.loginAsync(username, password);
|
|
4650
|
+
invalidateConnections();
|
|
4581
4651
|
console.log(` \u2713 User registered via API: ${username}${firstRun ? " (first-run)" : ""}`);
|
|
4582
4652
|
res.cookie("aicli_token", token, authCookieOptions(req));
|
|
4583
4653
|
res.json({ success: true, username });
|
|
4584
4654
|
});
|
|
4585
|
-
app.post("/api/auth/login", (req, res) => {
|
|
4655
|
+
app.post("/api/auth/login", async (req, res) => {
|
|
4586
4656
|
const { username, password } = req.body ?? {};
|
|
4587
4657
|
if (!username || !password) {
|
|
4588
4658
|
res.status(400).json({ error: "Username and password required" });
|
|
4589
4659
|
return;
|
|
4590
4660
|
}
|
|
4591
|
-
const token = authManager.
|
|
4661
|
+
const token = await authManager.loginAsync(username, password);
|
|
4592
4662
|
if (!token) {
|
|
4593
4663
|
res.status(401).json({ error: "Invalid username or password" });
|
|
4594
4664
|
return;
|
|
@@ -4597,6 +4667,9 @@ async function startWebServer(options = {}) {
|
|
|
4597
4667
|
res.json({ success: true, username });
|
|
4598
4668
|
});
|
|
4599
4669
|
app.post("/api/auth/logout", (req, res) => {
|
|
4670
|
+
const user = authManager.verifyToken(parseCookie(req.headers.cookie ?? "").aicli_token ?? "");
|
|
4671
|
+
if (user) authManager.logoutAll(user);
|
|
4672
|
+
invalidateConnections();
|
|
4600
4673
|
res.clearCookie("aicli_token", clearAuthCookieOptions(req));
|
|
4601
4674
|
res.json({ success: true });
|
|
4602
4675
|
});
|
|
@@ -4692,6 +4765,7 @@ async function startWebServer(options = {}) {
|
|
|
4692
4765
|
const fullPath = resolve3(join2(cwd, filePath));
|
|
4693
4766
|
try {
|
|
4694
4767
|
const canonicalFull = realpathSync(fullPath);
|
|
4768
|
+
assertReadablePath(canonicalFull);
|
|
4695
4769
|
const canonicalCwd = realpathSync(resolve3(cwd));
|
|
4696
4770
|
if (!canonicalFull.startsWith(canonicalCwd + sep2) && canonicalFull !== canonicalCwd) {
|
|
4697
4771
|
res.json({ error: "Access denied" });
|
|
@@ -4719,6 +4793,9 @@ async function startWebServer(options = {}) {
|
|
|
4719
4793
|
if (cached) return cached;
|
|
4720
4794
|
const userDataDir = authManager.getUserDataDir(username);
|
|
4721
4795
|
const userConfig = new ConfigManager(userDataDir);
|
|
4796
|
+
for (const key of ["defaultPermissionProfile", "allowedPermissionProfiles", "permissionProfiles", "permissionRules", "defaultPermission", "networkPolicy"]) {
|
|
4797
|
+
userConfig.setTransient(key, structuredClone(config.get(key)));
|
|
4798
|
+
}
|
|
4722
4799
|
if (userConfig.isFirstRun()) {
|
|
4723
4800
|
userConfig.setTransient("defaultProvider", config.get("defaultProvider"));
|
|
4724
4801
|
userConfig.setTransient("defaultModels", config.get("defaultModels"));
|
|
@@ -4729,7 +4806,7 @@ async function startWebServer(options = {}) {
|
|
|
4729
4806
|
// 每用户各自的 config 目录 → 各自的 cost-history.json
|
|
4730
4807
|
costTracker: new CostTracker(userConfig.getConfigDir()),
|
|
4731
4808
|
providers,
|
|
4732
|
-
//
|
|
4809
|
+
// Host-owned service credentials; shared explicitly, never per-user keys.
|
|
4733
4810
|
sessions: userSessions,
|
|
4734
4811
|
toolRegistry,
|
|
4735
4812
|
// Shared
|
|
@@ -4742,6 +4819,21 @@ async function startWebServer(options = {}) {
|
|
|
4742
4819
|
return userShared;
|
|
4743
4820
|
}
|
|
4744
4821
|
const handlers = /* @__PURE__ */ new Map();
|
|
4822
|
+
const validators = /* @__PURE__ */ new Set();
|
|
4823
|
+
function invalidateConnections() {
|
|
4824
|
+
for (const validate of validators) validate();
|
|
4825
|
+
}
|
|
4826
|
+
let authRefreshTimer;
|
|
4827
|
+
server.on("listening", () => {
|
|
4828
|
+
if (!authRefreshTimer) {
|
|
4829
|
+
authRefreshTimer = setInterval(invalidateConnections, 1e3);
|
|
4830
|
+
authRefreshTimer.unref();
|
|
4831
|
+
}
|
|
4832
|
+
});
|
|
4833
|
+
server.on("close", () => {
|
|
4834
|
+
clearInterval(authRefreshTimer);
|
|
4835
|
+
authRefreshTimer = void 0;
|
|
4836
|
+
});
|
|
4745
4837
|
wss.on("connection", (ws, req) => {
|
|
4746
4838
|
const urlStr = req.url ?? "";
|
|
4747
4839
|
const qMark = urlStr.indexOf("?");
|
|
@@ -4749,6 +4841,8 @@ async function startWebServer(options = {}) {
|
|
|
4749
4841
|
const tabId = params.get("tabId") || `tab-${Date.now()}`;
|
|
4750
4842
|
const cookies = parseCookie(req.headers.cookie ?? "");
|
|
4751
4843
|
const token = cookies["aicli_token"] || "";
|
|
4844
|
+
let activeToken = token;
|
|
4845
|
+
const localAuthorized = equalToken(cookies.aicli_local, access.localToken);
|
|
4752
4846
|
let tokens = WS_MSG_BURST;
|
|
4753
4847
|
let lastRefill = Date.now();
|
|
4754
4848
|
const takeToken = () => {
|
|
@@ -4808,7 +4902,7 @@ async function startWebServer(options = {}) {
|
|
|
4808
4902
|
authenticatedUser = authManager.verifyToken(token);
|
|
4809
4903
|
}
|
|
4810
4904
|
const authRequired = authManager.isEnabled();
|
|
4811
|
-
if (!authRequired) {
|
|
4905
|
+
if (!authRequired && localAuthorized) {
|
|
4812
4906
|
console.log(` \u2713 Tab connected: ${tabId.slice(0, 12)} (no auth) (total: ${handlers.size + 1})`);
|
|
4813
4907
|
handler = attachHandler(shared);
|
|
4814
4908
|
clearPreAuthTimer();
|
|
@@ -4826,7 +4920,26 @@ async function startWebServer(options = {}) {
|
|
|
4826
4920
|
}));
|
|
4827
4921
|
}
|
|
4828
4922
|
}
|
|
4923
|
+
const validate = () => {
|
|
4924
|
+
if (!handler) return;
|
|
4925
|
+
let valid = false;
|
|
4926
|
+
try {
|
|
4927
|
+
valid = authManager.isEnabled() ? !!activeToken && authManager.verifyToken(activeToken) === authenticatedUser : localAuthorized && !authenticatedUser;
|
|
4928
|
+
} catch {
|
|
4929
|
+
}
|
|
4930
|
+
if (!valid) {
|
|
4931
|
+
handler.onDisconnect(false);
|
|
4932
|
+
if (handlers.get(handlerKey) === handler) handlers.delete(handlerKey);
|
|
4933
|
+
handler = null;
|
|
4934
|
+
ws.close(1008, "Authentication changed; reconnect");
|
|
4935
|
+
}
|
|
4936
|
+
};
|
|
4937
|
+
validators.add(validate);
|
|
4938
|
+
ws.on("close", () => validators.delete(validate));
|
|
4939
|
+
let authBusy = false;
|
|
4829
4940
|
ws.on("message", async (data) => {
|
|
4941
|
+
validate();
|
|
4942
|
+
if (ws.readyState !== ws.OPEN) return;
|
|
4830
4943
|
if (!takeToken()) {
|
|
4831
4944
|
if (ws.readyState === ws.OPEN) {
|
|
4832
4945
|
try {
|
|
@@ -4846,57 +4959,73 @@ async function startWebServer(options = {}) {
|
|
|
4846
4959
|
return;
|
|
4847
4960
|
}
|
|
4848
4961
|
if (parsed.type === "auth") {
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4962
|
+
if (authBusy) return;
|
|
4963
|
+
authBusy = true;
|
|
4964
|
+
try {
|
|
4965
|
+
if (!authLimits.take(req.socket.remoteAddress ?? "unknown")) {
|
|
4966
|
+
ws.close(1008, "Authentication rate limit");
|
|
4853
4967
|
return;
|
|
4854
4968
|
}
|
|
4855
|
-
const
|
|
4856
|
-
|
|
4857
|
-
|
|
4969
|
+
const { action, password } = parsed;
|
|
4970
|
+
const username = typeof parsed.username === "string" ? parsed.username.trim().toLowerCase() : "";
|
|
4971
|
+
if (action === "register") {
|
|
4972
|
+
if (!authenticatedUser && (authManager.hasUsers() || !localAuthorized)) {
|
|
4973
|
+
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Registration is closed. Use `aicli user create` on the host to add users." }));
|
|
4974
|
+
return;
|
|
4975
|
+
}
|
|
4976
|
+
const err = await authManager.registerAsync(username, password);
|
|
4977
|
+
if (err) {
|
|
4978
|
+
ws.send(JSON.stringify({ type: "auth_result", success: false, error: err }));
|
|
4979
|
+
return;
|
|
4980
|
+
}
|
|
4981
|
+
activeToken = await authManager.loginAsync(username, password) ?? "";
|
|
4982
|
+
if (ws.readyState !== ws.OPEN || authManager.verifyToken(activeToken) !== username) return;
|
|
4983
|
+
authenticatedUser = username;
|
|
4984
|
+
const userShared = getUserShared(username);
|
|
4985
|
+
handler = attachHandler(userShared);
|
|
4986
|
+
clearPreAuthTimer();
|
|
4987
|
+
invalidateConnections();
|
|
4988
|
+
console.log(` \u2713 User registered & connected: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
4989
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, username }));
|
|
4858
4990
|
return;
|
|
4859
4991
|
}
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
ws.send(JSON.stringify({ type: "auth_result", success:
|
|
4992
|
+
if (action === "token") {
|
|
4993
|
+
const { token: clientToken } = parsed;
|
|
4994
|
+
const verifiedUser = authManager.verifyToken(clientToken);
|
|
4995
|
+
if (!verifiedUser) {
|
|
4996
|
+
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Invalid or expired token" }));
|
|
4997
|
+
return;
|
|
4998
|
+
}
|
|
4999
|
+
activeToken = clientToken;
|
|
5000
|
+
authenticatedUser = verifiedUser;
|
|
5001
|
+
const userShared = getUserShared(verifiedUser);
|
|
5002
|
+
handler = attachHandler(userShared);
|
|
5003
|
+
clearPreAuthTimer();
|
|
5004
|
+
console.log(` \u2713 Token auth: ${verifiedUser} (tab: ${tabId.slice(0, 12)})`);
|
|
5005
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, username: verifiedUser }));
|
|
4874
5006
|
return;
|
|
4875
5007
|
}
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
5008
|
+
if (action === "login") {
|
|
5009
|
+
const loginToken = await authManager.loginAsync(username, password);
|
|
5010
|
+
if (!loginToken) {
|
|
5011
|
+
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Invalid username or password" }));
|
|
5012
|
+
return;
|
|
5013
|
+
}
|
|
5014
|
+
if (ws.readyState !== ws.OPEN || authManager.verifyToken(loginToken) !== username) return;
|
|
5015
|
+
activeToken = loginToken;
|
|
5016
|
+
authenticatedUser = username;
|
|
5017
|
+
const userShared = getUserShared(username);
|
|
5018
|
+
handler = attachHandler(userShared);
|
|
5019
|
+
clearPreAuthTimer();
|
|
5020
|
+
console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
5021
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, username }));
|
|
4888
5022
|
return;
|
|
4889
5023
|
}
|
|
4890
|
-
|
|
4891
|
-
const userShared = getUserShared(username);
|
|
4892
|
-
handler = attachHandler(userShared);
|
|
4893
|
-
clearPreAuthTimer();
|
|
4894
|
-
console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
4895
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true, username }));
|
|
5024
|
+
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Unknown auth action" }));
|
|
4896
5025
|
return;
|
|
5026
|
+
} finally {
|
|
5027
|
+
authBusy = false;
|
|
4897
5028
|
}
|
|
4898
|
-
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Unknown auth action" }));
|
|
4899
|
-
return;
|
|
4900
5029
|
}
|
|
4901
5030
|
if (!handler) {
|
|
4902
5031
|
if (ws.readyState === ws.OPEN) {
|
|
@@ -4942,7 +5071,9 @@ async function startWebServer(options = {}) {
|
|
|
4942
5071
|
}
|
|
4943
5072
|
});
|
|
4944
5073
|
server.listen(actualPort, host, () => {
|
|
4945
|
-
|
|
5074
|
+
actualPort = server.address().port;
|
|
5075
|
+
const address = host.includes(":") ? `[${host}]` : host === "0.0.0.0" ? "localhost" : host;
|
|
5076
|
+
const url = `http://${address}:${actualPort}` + (!authManager.isEnabled() ? `#token=${access.localToken}` : "");
|
|
4946
5077
|
console.log(`
|
|
4947
5078
|
\u{1F310} Web UI ready: ${url}`);
|
|
4948
5079
|
if (actualPort !== port) console.log(` (port ${port} was in use, using ${actualPort})`);
|
|
@@ -4998,10 +5129,7 @@ function loadProjectMcpConfig() {
|
|
|
4998
5129
|
}
|
|
4999
5130
|
}
|
|
5000
5131
|
function isHttpsRequest(req) {
|
|
5001
|
-
|
|
5002
|
-
const forwardedProto = req.headers["x-forwarded-proto"];
|
|
5003
|
-
const proto = Array.isArray(forwardedProto) ? forwardedProto[0] : forwardedProto;
|
|
5004
|
-
return proto?.split(",")[0]?.trim().toLowerCase() === "https";
|
|
5132
|
+
return req.secure || req.res?.locals.externalSecure === true;
|
|
5005
5133
|
}
|
|
5006
5134
|
function authCookieOptions(req) {
|
|
5007
5135
|
return {
|