jinzd-ai-cli 0.4.7 → 0.4.9
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/dist/{auth-TWWF22YZ.js → auth-MSUWO6SE.js} +1 -1
- package/dist/{chunk-EIBYVUCB.js → chunk-75RK4GJP.js} +1 -1
- package/dist/{chunk-CPLT6CD3.js → chunk-BYNY5JPB.js} +18 -4
- package/dist/{chunk-N3DIEZ4F.js → chunk-DAKTIUEG.js} +1 -1
- package/dist/{chunk-2DCIW6JN.js → chunk-ETHEKIMV.js} +2 -2
- package/dist/{chunk-UQH2IHE7.js → chunk-U6TWB6UQ.js} +1 -1
- package/dist/{hub-XNIWPTZE.js → hub-JACBMIVV.js} +1 -1
- package/dist/index.js +7 -7
- package/dist/{run-tests-Q6SWSBIT.js → run-tests-KDWXX2WF.js} +1 -1
- package/dist/{run-tests-OVUM7ACD.js → run-tests-MUSKRAOS.js} +1 -1
- package/dist/{server-RFDBGC3H.js → server-FUXCHUIZ.js} +81 -24
- package/dist/{task-orchestrator-RHLP2TS7.js → task-orchestrator-V4ZQPJYI.js} +6 -2
- package/dist/web/client/app.js +13 -2
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/web/auth.ts
|
|
4
4
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, copyFileSync } from "fs";
|
|
5
5
|
import { join } from "path";
|
|
6
|
-
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
6
|
+
import { createHmac, randomBytes, timingSafeEqual, pbkdf2Sync } from "crypto";
|
|
7
7
|
var USERS_FILE = "users.json";
|
|
8
8
|
var TOKEN_EXPIRY_HOURS = 24 * 7;
|
|
9
9
|
var USERS_DIR = "users";
|
|
@@ -50,7 +50,8 @@ var AuthManager = class {
|
|
|
50
50
|
passwordHash,
|
|
51
51
|
salt,
|
|
52
52
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
53
|
-
dataDir
|
|
53
|
+
dataDir,
|
|
54
|
+
hashVersion: 2
|
|
54
55
|
};
|
|
55
56
|
this.db.users.push(user);
|
|
56
57
|
this.save();
|
|
@@ -61,12 +62,20 @@ var AuthManager = class {
|
|
|
61
62
|
username = username.trim().toLowerCase();
|
|
62
63
|
const user = this.db.users.find((u) => u.username === username);
|
|
63
64
|
if (!user) return null;
|
|
64
|
-
const
|
|
65
|
+
const isLegacy = !user.hashVersion || user.hashVersion < 2;
|
|
66
|
+
const hash = isLegacy ? this.hashPasswordLegacy(password, user.salt) : this.hashPassword(password, user.salt);
|
|
65
67
|
const a = Buffer.from(hash, "utf-8");
|
|
66
68
|
const b = Buffer.from(user.passwordHash, "utf-8");
|
|
67
69
|
if (a.length !== b.length || !timingSafeEqual(a, b)) {
|
|
68
70
|
return null;
|
|
69
71
|
}
|
|
72
|
+
if (isLegacy) {
|
|
73
|
+
const newSalt = randomBytes(16).toString("hex");
|
|
74
|
+
user.passwordHash = this.hashPassword(password, newSalt);
|
|
75
|
+
user.salt = newSalt;
|
|
76
|
+
user.hashVersion = 2;
|
|
77
|
+
this.save();
|
|
78
|
+
}
|
|
70
79
|
return this.createToken(username);
|
|
71
80
|
}
|
|
72
81
|
/** Verify a token. Returns username or null. */
|
|
@@ -117,6 +126,7 @@ var AuthManager = class {
|
|
|
117
126
|
const salt = randomBytes(16).toString("hex");
|
|
118
127
|
user.passwordHash = this.hashPassword(newPassword, salt);
|
|
119
128
|
user.salt = salt;
|
|
129
|
+
user.hashVersion = 2;
|
|
120
130
|
this.save();
|
|
121
131
|
return null;
|
|
122
132
|
}
|
|
@@ -180,9 +190,13 @@ var AuthManager = class {
|
|
|
180
190
|
mkdirSync(this.baseDir, { recursive: true });
|
|
181
191
|
writeFileSync(this.usersFile, JSON.stringify(db, null, 2), "utf-8");
|
|
182
192
|
}
|
|
183
|
-
|
|
193
|
+
/** Legacy hash — kept only for migrating old users (v0.2.x) */
|
|
194
|
+
hashPasswordLegacy(password, salt) {
|
|
184
195
|
return createHmac("sha256", salt).update(password).digest("hex");
|
|
185
196
|
}
|
|
197
|
+
hashPassword(password, salt) {
|
|
198
|
+
return pbkdf2Sync(password, salt, 1e5, 64, "sha512").toString("hex");
|
|
199
|
+
}
|
|
186
200
|
createToken(username) {
|
|
187
201
|
const payload = {
|
|
188
202
|
username,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
EnvLoader,
|
|
4
4
|
schemaToJsonSchema
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DAKTIUEG.js";
|
|
6
6
|
import {
|
|
7
7
|
APP_NAME,
|
|
8
8
|
CONFIG_DIR_NAME,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
MCP_TOOL_PREFIX,
|
|
16
16
|
PLUGINS_DIR_NAME,
|
|
17
17
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-U6TWB6UQ.js";
|
|
19
19
|
|
|
20
20
|
// src/config/config-manager.ts
|
|
21
21
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -381,7 +381,7 @@ ${content}`);
|
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
384
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
384
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-V4ZQPJYI.js");
|
|
385
385
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
386
386
|
let interrupted = false;
|
|
387
387
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
saveDevState,
|
|
24
24
|
sessionHasMeaningfulContent,
|
|
25
25
|
setupProxy
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ETHEKIMV.js";
|
|
27
27
|
import {
|
|
28
28
|
ToolRegistry,
|
|
29
29
|
askUserContext,
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
theme,
|
|
39
39
|
truncateOutput,
|
|
40
40
|
undoStack
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-DAKTIUEG.js";
|
|
42
42
|
import {
|
|
43
43
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
44
44
|
AUTHOR,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
REPO_URL,
|
|
59
59
|
SKILLS_DIR_NAME,
|
|
60
60
|
VERSION
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-U6TWB6UQ.js";
|
|
62
62
|
|
|
63
63
|
// src/index.ts
|
|
64
64
|
import { program } from "commander";
|
|
@@ -1914,7 +1914,7 @@ ${hint}` : "")
|
|
|
1914
1914
|
description: "Run project tests and show structured report",
|
|
1915
1915
|
usage: "/test [command|filter]",
|
|
1916
1916
|
async execute(args, _ctx) {
|
|
1917
|
-
const { executeTests } = await import("./run-tests-
|
|
1917
|
+
const { executeTests } = await import("./run-tests-MUSKRAOS.js");
|
|
1918
1918
|
const argStr = args.join(" ").trim();
|
|
1919
1919
|
let testArgs = {};
|
|
1920
1920
|
if (argStr) {
|
|
@@ -5524,11 +5524,11 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
5524
5524
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
5525
5525
|
process.exit(1);
|
|
5526
5526
|
}
|
|
5527
|
-
const { startWebServer } = await import("./server-
|
|
5527
|
+
const { startWebServer } = await import("./server-FUXCHUIZ.js");
|
|
5528
5528
|
await startWebServer({ port, host: options.host });
|
|
5529
5529
|
});
|
|
5530
5530
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
|
|
5531
|
-
const { AuthManager } = await import("./auth-
|
|
5531
|
+
const { AuthManager } = await import("./auth-MSUWO6SE.js");
|
|
5532
5532
|
const config = new ConfigManager();
|
|
5533
5533
|
const auth = new AuthManager(config.getConfigDir());
|
|
5534
5534
|
if (!action || action === "list") {
|
|
@@ -5757,7 +5757,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
5757
5757
|
}),
|
|
5758
5758
|
config.get("customProviders")
|
|
5759
5759
|
);
|
|
5760
|
-
const { startHub } = await import("./hub-
|
|
5760
|
+
const { startHub } = await import("./hub-JACBMIVV.js");
|
|
5761
5761
|
await startHub(
|
|
5762
5762
|
{
|
|
5763
5763
|
topic: topic ?? "",
|
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
renderDiff,
|
|
19
19
|
runHook,
|
|
20
20
|
setupProxy
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-ETHEKIMV.js";
|
|
22
22
|
import {
|
|
23
23
|
AuthManager
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-BYNY5JPB.js";
|
|
25
25
|
import {
|
|
26
26
|
ToolRegistry,
|
|
27
27
|
askUserContext,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
spawnAgentContext,
|
|
33
33
|
truncateOutput,
|
|
34
34
|
undoStack
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-DAKTIUEG.js";
|
|
36
36
|
import {
|
|
37
37
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
38
38
|
CONTEXT_FILE_CANDIDATES,
|
|
@@ -44,14 +44,14 @@ import {
|
|
|
44
44
|
PLAN_MODE_SYSTEM_ADDON,
|
|
45
45
|
SKILLS_DIR_NAME,
|
|
46
46
|
VERSION
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-U6TWB6UQ.js";
|
|
48
48
|
|
|
49
49
|
// src/web/server.ts
|
|
50
50
|
import express from "express";
|
|
51
51
|
import { createServer } from "http";
|
|
52
52
|
import { WebSocketServer } from "ws";
|
|
53
|
-
import { join as join3, dirname, resolve as resolve2, relative } from "path";
|
|
54
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
53
|
+
import { join as join3, dirname, resolve as resolve2, relative, sep } from "path";
|
|
54
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2, realpathSync } from "fs";
|
|
55
55
|
import { networkInterfaces } from "os";
|
|
56
56
|
|
|
57
57
|
// src/web/tool-executor-web.ts
|
|
@@ -1440,7 +1440,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
1440
1440
|
case "test": {
|
|
1441
1441
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
1442
1442
|
try {
|
|
1443
|
-
const { executeTests } = await import("./run-tests-
|
|
1443
|
+
const { executeTests } = await import("./run-tests-MUSKRAOS.js");
|
|
1444
1444
|
const argStr = args.join(" ").trim();
|
|
1445
1445
|
let testArgs = {};
|
|
1446
1446
|
if (argStr) {
|
|
@@ -2062,6 +2062,30 @@ async function startWebServer(options = {}) {
|
|
|
2062
2062
|
const app = express();
|
|
2063
2063
|
const server = createServer(app);
|
|
2064
2064
|
const wss = new WebSocketServer({ server });
|
|
2065
|
+
const authManager = new AuthManager(config.getConfigDir());
|
|
2066
|
+
if (authManager.isEnabled()) {
|
|
2067
|
+
console.log(` Auth: ${authManager.listUsers().length} user(s) registered`);
|
|
2068
|
+
} else {
|
|
2069
|
+
console.log(` Auth: disabled (no users registered)`);
|
|
2070
|
+
}
|
|
2071
|
+
const requireAuth = (req, res, next) => {
|
|
2072
|
+
if (!authManager.isEnabled()) return next();
|
|
2073
|
+
const authHeader = req.headers.authorization;
|
|
2074
|
+
const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
2075
|
+
const cookieToken = parseCookie(req.headers.cookie ?? "")["aicli_token"];
|
|
2076
|
+
const effectiveToken = token ?? cookieToken;
|
|
2077
|
+
if (!effectiveToken) {
|
|
2078
|
+
res.status(401).json({ error: "Authentication required" });
|
|
2079
|
+
return;
|
|
2080
|
+
}
|
|
2081
|
+
const username = authManager.verifyToken(effectiveToken);
|
|
2082
|
+
if (!username) {
|
|
2083
|
+
res.status(401).json({ error: "Invalid or expired token" });
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
req._authUser = username;
|
|
2087
|
+
next();
|
|
2088
|
+
};
|
|
2065
2089
|
const moduleDir = getModuleDir();
|
|
2066
2090
|
let clientDir = join3(moduleDir, "web", "client");
|
|
2067
2091
|
if (!existsSync4(clientDir)) {
|
|
@@ -2105,13 +2129,21 @@ async function startWebServer(options = {}) {
|
|
|
2105
2129
|
}
|
|
2106
2130
|
const token = authManager.login(username, password);
|
|
2107
2131
|
console.log(` \u2713 User registered via API: ${username}`);
|
|
2132
|
+
res.cookie("aicli_token", token, { httpOnly: true, sameSite: "strict", maxAge: 7 * 24 * 3600 * 1e3 });
|
|
2108
2133
|
res.json({ success: true, token, username });
|
|
2109
2134
|
});
|
|
2110
|
-
app.get("/api/files", (req, res) => {
|
|
2135
|
+
app.get("/api/files", requireAuth, (req, res) => {
|
|
2111
2136
|
const cwd = process.cwd();
|
|
2112
2137
|
const prefix = req.query.prefix || "";
|
|
2113
2138
|
const targetDir = join3(cwd, prefix);
|
|
2114
|
-
|
|
2139
|
+
try {
|
|
2140
|
+
const canonicalTarget = realpathSync(resolve2(targetDir));
|
|
2141
|
+
const canonicalCwd = realpathSync(resolve2(cwd));
|
|
2142
|
+
if (!canonicalTarget.startsWith(canonicalCwd + sep) && canonicalTarget !== canonicalCwd) {
|
|
2143
|
+
res.json({ files: [] });
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
} catch {
|
|
2115
2147
|
res.json({ files: [] });
|
|
2116
2148
|
return;
|
|
2117
2149
|
}
|
|
@@ -2128,7 +2160,7 @@ async function startWebServer(options = {}) {
|
|
|
2128
2160
|
res.json({ files: [] });
|
|
2129
2161
|
}
|
|
2130
2162
|
});
|
|
2131
|
-
app.get("/api/sessions", (_req, res) => {
|
|
2163
|
+
app.get("/api/sessions", requireAuth, (_req, res) => {
|
|
2132
2164
|
try {
|
|
2133
2165
|
const list = sessions.listSessions();
|
|
2134
2166
|
res.json({
|
|
@@ -2145,7 +2177,7 @@ async function startWebServer(options = {}) {
|
|
|
2145
2177
|
res.json({ sessions: [] });
|
|
2146
2178
|
}
|
|
2147
2179
|
});
|
|
2148
|
-
app.get("/api/file-content", (req, res) => {
|
|
2180
|
+
app.get("/api/file-content", requireAuth, (req, res) => {
|
|
2149
2181
|
const filePath = req.query.path;
|
|
2150
2182
|
if (!filePath) {
|
|
2151
2183
|
res.json({ error: "Missing path" });
|
|
@@ -2153,8 +2185,15 @@ async function startWebServer(options = {}) {
|
|
|
2153
2185
|
}
|
|
2154
2186
|
const cwd = process.cwd();
|
|
2155
2187
|
const fullPath = resolve2(join3(cwd, filePath));
|
|
2156
|
-
|
|
2157
|
-
|
|
2188
|
+
try {
|
|
2189
|
+
const canonicalFull = realpathSync(fullPath);
|
|
2190
|
+
const canonicalCwd = realpathSync(resolve2(cwd));
|
|
2191
|
+
if (!canonicalFull.startsWith(canonicalCwd + sep) && canonicalFull !== canonicalCwd) {
|
|
2192
|
+
res.json({ error: "Access denied" });
|
|
2193
|
+
return;
|
|
2194
|
+
}
|
|
2195
|
+
} catch {
|
|
2196
|
+
res.json({ error: "File not found" });
|
|
2158
2197
|
return;
|
|
2159
2198
|
}
|
|
2160
2199
|
try {
|
|
@@ -2165,16 +2204,10 @@ async function startWebServer(options = {}) {
|
|
|
2165
2204
|
}
|
|
2166
2205
|
const content = readFileSync4(fullPath, "utf-8");
|
|
2167
2206
|
res.json({ content, size: stat.size });
|
|
2168
|
-
} catch
|
|
2169
|
-
res.json({ error:
|
|
2207
|
+
} catch {
|
|
2208
|
+
res.json({ error: "Cannot read file" });
|
|
2170
2209
|
}
|
|
2171
2210
|
});
|
|
2172
|
-
const authManager = new AuthManager(config.getConfigDir());
|
|
2173
|
-
if (authManager.isEnabled()) {
|
|
2174
|
-
console.log(` Auth: ${authManager.listUsers().length} user(s) registered`);
|
|
2175
|
-
} else {
|
|
2176
|
-
console.log(` Auth: disabled (no users registered)`);
|
|
2177
|
-
}
|
|
2178
2211
|
const userResources = /* @__PURE__ */ new Map();
|
|
2179
2212
|
function getUserShared(username) {
|
|
2180
2213
|
const cached = userResources.get(username);
|
|
@@ -2203,7 +2236,8 @@ async function startWebServer(options = {}) {
|
|
|
2203
2236
|
const qMark = urlStr.indexOf("?");
|
|
2204
2237
|
const params = new URLSearchParams(qMark >= 0 ? urlStr.slice(qMark + 1) : "");
|
|
2205
2238
|
const tabId = params.get("tabId") || `tab-${Date.now()}`;
|
|
2206
|
-
const
|
|
2239
|
+
const cookies = parseCookie(req.headers.cookie ?? "");
|
|
2240
|
+
const token = cookies["aicli_token"] || "";
|
|
2207
2241
|
const existing = handlers.get(tabId);
|
|
2208
2242
|
if (existing) {
|
|
2209
2243
|
existing.onDisconnect();
|
|
@@ -2257,7 +2291,22 @@ async function startWebServer(options = {}) {
|
|
|
2257
2291
|
handler = new SessionHandler(ws, userShared);
|
|
2258
2292
|
handlers.set(tabId, handler);
|
|
2259
2293
|
console.log(` \u2713 User registered & connected: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
2260
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username }));
|
|
2294
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username, setCookie: true }));
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
if (action === "token") {
|
|
2298
|
+
const { token: clientToken } = parsed;
|
|
2299
|
+
const verifiedUser = authManager.verifyToken(clientToken);
|
|
2300
|
+
if (!verifiedUser) {
|
|
2301
|
+
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Invalid or expired token" }));
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
authenticatedUser = verifiedUser;
|
|
2305
|
+
const userShared = getUserShared(verifiedUser);
|
|
2306
|
+
handler = new SessionHandler(ws, userShared);
|
|
2307
|
+
handlers.set(tabId, handler);
|
|
2308
|
+
console.log(` \u2713 Token auth: ${verifiedUser} (tab: ${tabId.slice(0, 12)})`);
|
|
2309
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, token: clientToken, username: verifiedUser }));
|
|
2261
2310
|
return;
|
|
2262
2311
|
}
|
|
2263
2312
|
if (action === "login") {
|
|
@@ -2271,7 +2320,7 @@ async function startWebServer(options = {}) {
|
|
|
2271
2320
|
handler = new SessionHandler(ws, userShared);
|
|
2272
2321
|
handlers.set(tabId, handler);
|
|
2273
2322
|
console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
2274
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username }));
|
|
2323
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username, setCookie: true }));
|
|
2275
2324
|
return;
|
|
2276
2325
|
}
|
|
2277
2326
|
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Unknown auth action" }));
|
|
@@ -2366,6 +2415,14 @@ function loadProjectMcpConfig() {
|
|
|
2366
2415
|
return null;
|
|
2367
2416
|
}
|
|
2368
2417
|
}
|
|
2418
|
+
function parseCookie(cookie) {
|
|
2419
|
+
const result = {};
|
|
2420
|
+
for (const part of cookie.split(";")) {
|
|
2421
|
+
const [key, ...rest] = part.trim().split("=");
|
|
2422
|
+
if (key) result[key.trim()] = rest.join("=").trim();
|
|
2423
|
+
}
|
|
2424
|
+
return result;
|
|
2425
|
+
}
|
|
2369
2426
|
async function openBrowser(url) {
|
|
2370
2427
|
try {
|
|
2371
2428
|
const { exec } = await import("child_process");
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
googleSearchContext,
|
|
6
6
|
truncateOutput
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DAKTIUEG.js";
|
|
8
8
|
import {
|
|
9
9
|
SUBAGENT_ALLOWED_TOOLS
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-U6TWB6UQ.js";
|
|
11
11
|
|
|
12
12
|
// src/hub/task-orchestrator.ts
|
|
13
13
|
import { createInterface } from "readline";
|
|
@@ -48,6 +48,9 @@ ${role.persona}
|
|
|
48
48
|
## Your Task
|
|
49
49
|
${task}
|
|
50
50
|
|
|
51
|
+
## Working Directory
|
|
52
|
+
You MUST work in the current directory (${process.cwd()}). Do NOT create sub-directories like "my-project" or "todo-app". Place all files directly in the current directory or in logical sub-folders (e.g. public/, src/, db/).
|
|
53
|
+
|
|
51
54
|
## Rules
|
|
52
55
|
1. Focus exclusively on completing the task described above.
|
|
53
56
|
2. Use tools to read, create, and modify files as needed.
|
|
@@ -55,6 +58,7 @@ ${task}
|
|
|
55
58
|
4. Destructive operations (rm -rf, etc.) will be automatically blocked.
|
|
56
59
|
5. You cannot interact with users \u2014 work independently based on the task description.
|
|
57
60
|
6. Use the same language as the task description.
|
|
61
|
+
7. If files from a previous task already exist, build on them \u2014 do NOT recreate from scratch.
|
|
58
62
|
|
|
59
63
|
## CRITICAL \u2014 When to Stop
|
|
60
64
|
Once you have completed the task (files created/modified, code written, tests passing), you MUST immediately respond with a plain text summary. Do NOT call any more tools after the work is done. Your text summary should include:
|
package/dist/web/client/app.js
CHANGED
|
@@ -76,14 +76,19 @@ let reconnectDelay = 1000; // Start at 1s, exponential backoff
|
|
|
76
76
|
|
|
77
77
|
function connect() {
|
|
78
78
|
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
// Security: do NOT put token in URL (visible in logs/referrer). Cookie is sent automatically.
|
|
80
|
+
// For reconnection, also send token as first message in case cookie is blocked.
|
|
81
|
+
ws = new WebSocket(`${protocol}//${location.host}?tabId=${tabId}`);
|
|
81
82
|
|
|
82
83
|
ws.onopen = () => {
|
|
83
84
|
connected = true;
|
|
84
85
|
reconnectDelay = 1000; // Reset backoff on success
|
|
85
86
|
connectionStatus.textContent = '🟢 Connected';
|
|
86
87
|
connectionStatus.className = 'status-connected';
|
|
88
|
+
// Send stored token for auth (in case cookie is not available)
|
|
89
|
+
if (authToken) {
|
|
90
|
+
ws.send(JSON.stringify({ type: 'auth', action: 'token', token: authToken }));
|
|
91
|
+
}
|
|
87
92
|
requestSessionList();
|
|
88
93
|
checkAuthStatus();
|
|
89
94
|
// Start heartbeat ping every 30s
|
|
@@ -1886,6 +1891,11 @@ function handleAuthResult(msg) {
|
|
|
1886
1891
|
authUsername = msg.username;
|
|
1887
1892
|
localStorage.setItem('aicli-auth-token', msg.token);
|
|
1888
1893
|
localStorage.setItem('aicli-auth-user', msg.username);
|
|
1894
|
+
// Set cookie for secure WebSocket auth (httpOnly cookie set by server on HTTP login,
|
|
1895
|
+
// but for WS-only login, set a JS cookie as fallback)
|
|
1896
|
+
if (msg.setCookie && msg.token) {
|
|
1897
|
+
document.cookie = `aicli_token=${encodeURIComponent(msg.token)}; path=/; max-age=${7 * 24 * 3600}; SameSite=Strict`;
|
|
1898
|
+
}
|
|
1889
1899
|
hideAuthScreen();
|
|
1890
1900
|
// Request session list now that we're authenticated
|
|
1891
1901
|
requestSessionList();
|
|
@@ -1913,6 +1923,7 @@ function handleLogout() {
|
|
|
1913
1923
|
authToken = '';
|
|
1914
1924
|
authUsername = '';
|
|
1915
1925
|
localStorage.removeItem('aicli-auth-token');
|
|
1926
|
+
document.cookie = 'aicli_token=; path=/; max-age=0'; // Clear auth cookie
|
|
1916
1927
|
localStorage.removeItem('aicli-auth-user');
|
|
1917
1928
|
sessionStorage.removeItem('aicli-active-session');
|
|
1918
1929
|
// Reconnect — server will send auth_required
|