@jamiexiongr/panda-hub 0.1.22 → 0.1.24

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.
@@ -2273,6 +2273,58 @@ var sessionGitActionResponseSchema = external_exports.object({
2273
2273
  ok: external_exports.literal(true),
2274
2274
  workspace: sessionGitWorkspaceSchema
2275
2275
  });
2276
+ var sessionTurnActionSchema = external_exports.enum([
2277
+ "rollback"
2278
+ ]);
2279
+ var sessionTurnActionResponseSchema = external_exports.object({
2280
+ ok: external_exports.literal(true),
2281
+ turn_id: external_exports.string(),
2282
+ change_set_id: external_exports.string(),
2283
+ workspace: sessionGitWorkspaceSchema
2284
+ });
2285
+ var sessionFilePreviewNodeKindSchema = external_exports.enum([
2286
+ "directory",
2287
+ "file"
2288
+ ]);
2289
+ var sessionFilePreviewFileKindSchema = external_exports.enum([
2290
+ "markdown",
2291
+ "code",
2292
+ "text",
2293
+ "image",
2294
+ "binary"
2295
+ ]);
2296
+ var sessionFilePreviewTreeNodeSchema = external_exports.object({
2297
+ path: external_exports.string(),
2298
+ name: external_exports.string(),
2299
+ kind: sessionFilePreviewNodeKindSchema,
2300
+ has_children: external_exports.boolean(),
2301
+ extension: external_exports.string().nullable().default(null),
2302
+ file_kind: sessionFilePreviewFileKindSchema.nullable().default(null),
2303
+ size_bytes: external_exports.number().int().nonnegative().nullable().default(null)
2304
+ });
2305
+ var sessionFilePreviewTreeResponseSchema = external_exports.object({
2306
+ session_id: external_exports.string(),
2307
+ project_id: external_exports.string(),
2308
+ root_path: external_exports.string(),
2309
+ parent_path: external_exports.string().nullable().default(null),
2310
+ nodes: external_exports.array(sessionFilePreviewTreeNodeSchema),
2311
+ loaded_at: external_exports.string()
2312
+ });
2313
+ var sessionFilePreviewContentResponseSchema = external_exports.object({
2314
+ session_id: external_exports.string(),
2315
+ project_id: external_exports.string(),
2316
+ path: external_exports.string(),
2317
+ name: external_exports.string(),
2318
+ extension: external_exports.string().nullable().default(null),
2319
+ file_kind: sessionFilePreviewFileKindSchema,
2320
+ mime_type: external_exports.string().nullable().default(null),
2321
+ size_bytes: external_exports.number().int().nonnegative().nullable().default(null),
2322
+ encoding: external_exports.enum(["utf8", "base64"]).nullable().default(null),
2323
+ is_truncated: external_exports.boolean(),
2324
+ content_text: external_exports.string().nullable().default(null),
2325
+ content_base64: external_exports.string().nullable().default(null),
2326
+ loaded_at: external_exports.string()
2327
+ });
2276
2328
  var sessionRunCommandShellSchema = external_exports.enum([
2277
2329
  "auto",
2278
2330
  "powershell",
@@ -3244,6 +3296,7 @@ var APP_SERVER_DIAGNOSTIC_METHODS = /* @__PURE__ */ new Set([
3244
3296
  "config/read"
3245
3297
  ]);
3246
3298
  var defaultCodexHome2 = () => path4.join(os3.homedir(), ".codex");
3299
+ var resolveCodexEnvironmentHome = () => process.env.CODEX_HOME?.trim() || process.env.PANDA_CODEX_HOME?.trim() || defaultCodexHome2();
3247
3300
  var truncateText = (value, length) => {
3248
3301
  const trimmed = value.trim();
3249
3302
  if (trimmed.length <= length) {
@@ -5694,14 +5747,20 @@ ${nextFile.diff}`.trim();
5694
5747
  const spawnAppServerChild = () => {
5695
5748
  try {
5696
5749
  const appServerArgs = ["app-server", "--enable", "default_mode_request_user_input"];
5750
+ const childEnv = {
5751
+ ...process.env,
5752
+ CODEX_HOME: resolveCodexEnvironmentHome()
5753
+ };
5697
5754
  if (process.platform === "win32") {
5698
5755
  return spawn(process.env.ComSpec || "cmd.exe", ["/d", "/c", "codex", ...appServerArgs], {
5699
5756
  stdio: ["pipe", "pipe", "pipe"],
5700
- windowsHide: true
5757
+ windowsHide: true,
5758
+ env: childEnv
5701
5759
  });
5702
5760
  }
5703
5761
  return spawn("codex", appServerArgs, {
5704
- stdio: ["pipe", "pipe", "pipe"]
5762
+ stdio: ["pipe", "pipe", "pipe"],
5763
+ env: childEnv
5705
5764
  });
5706
5765
  } catch {
5707
5766
  return null;
@@ -5715,6 +5774,7 @@ ${nextFile.diff}`.trim();
5715
5774
  logDiagnostic("info", "Starting Codex app-server bridge.", {
5716
5775
  platform: process.platform,
5717
5776
  execPath: process.execPath,
5777
+ codexHome: resolveCodexEnvironmentHome(),
5718
5778
  codexCommandFound: codexCandidates.length > 0,
5719
5779
  codexCommandCandidates: codexCandidates,
5720
5780
  bridgeExecutable: process.platform === "win32" ? `${process.env.ComSpec || "cmd.exe"} /d /c codex` : "codex"
@@ -10063,6 +10123,72 @@ var USER_OVERLAY_ENTRY_PREFIX = "overlay-user:";
10063
10123
  var USER_ENTRY_MATCH_EARLY_SKEW_MS = 5e3;
10064
10124
  var TIMELINE_TOOL_SUMMARY_LIMIT = 160;
10065
10125
  var HTTP_COMPRESSION_MIN_BYTES = 4 * 1024;
10126
+ var DEFAULT_SESSION_TITLE_GENERATION_MODEL = "gpt-5.4-mini";
10127
+ var SESSION_TITLE_GENERATION_TIMEOUT_MS = 25e3;
10128
+ var SESSION_GENERATED_TITLE_MAX_LENGTH = 30;
10129
+ var SESSION_FILE_PREVIEW_ROOT_PATH = "/";
10130
+ var SESSION_FILE_PREVIEW_TEXT_BYTE_LIMIT = 256 * 1024;
10131
+ var SESSION_FILE_PREVIEW_IMAGE_BYTE_LIMIT = 6 * 1024 * 1024;
10132
+ var SESSION_FILE_PREVIEW_MARKDOWN_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown"]);
10133
+ var SESSION_FILE_PREVIEW_CODE_EXTENSIONS = /* @__PURE__ */ new Set([
10134
+ ".ts",
10135
+ ".tsx",
10136
+ ".js",
10137
+ ".jsx",
10138
+ ".json",
10139
+ ".css",
10140
+ ".html",
10141
+ ".xml",
10142
+ ".yml",
10143
+ ".yaml",
10144
+ ".sh",
10145
+ ".java"
10146
+ ]);
10147
+ var SESSION_FILE_PREVIEW_TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
10148
+ ".txt",
10149
+ ".log"
10150
+ ]);
10151
+ var SESSION_FILE_PREVIEW_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
10152
+ ".png",
10153
+ ".jpg",
10154
+ ".jpeg",
10155
+ ".webp",
10156
+ ".gif",
10157
+ ".svg"
10158
+ ]);
10159
+ var SESSION_FILE_PREVIEW_CODE_FILENAMES = /* @__PURE__ */ new Set([
10160
+ "dockerfile",
10161
+ "makefile",
10162
+ "jenkinsfile"
10163
+ ]);
10164
+ var SESSION_FILE_PREVIEW_CODE_NAME_PATTERNS = [
10165
+ /^\.(?:env(?:\..+)?)$/i,
10166
+ /^\.(?:gitignore|gitattributes|npmrc|yarnrc|editorconfig)$/i,
10167
+ /^\.(?:prettierrc|eslintrc)(?:\..+)?$/i
10168
+ ];
10169
+ var SESSION_FILE_PREVIEW_MIME_TYPES = {
10170
+ ".css": "text/css; charset=utf-8",
10171
+ ".gif": "image/gif",
10172
+ ".html": "text/html; charset=utf-8",
10173
+ ".java": "text/x-java-source; charset=utf-8",
10174
+ ".jpeg": "image/jpeg",
10175
+ ".jpg": "image/jpeg",
10176
+ ".js": "text/javascript; charset=utf-8",
10177
+ ".json": "application/json; charset=utf-8",
10178
+ ".log": "text/plain; charset=utf-8",
10179
+ ".markdown": "text/markdown; charset=utf-8",
10180
+ ".md": "text/markdown; charset=utf-8",
10181
+ ".png": "image/png",
10182
+ ".sh": "text/x-shellscript; charset=utf-8",
10183
+ ".svg": "image/svg+xml",
10184
+ ".ts": "text/typescript; charset=utf-8",
10185
+ ".tsx": "text/typescript; charset=utf-8",
10186
+ ".txt": "text/plain; charset=utf-8",
10187
+ ".webp": "image/webp",
10188
+ ".xml": "application/xml; charset=utf-8",
10189
+ ".yaml": "text/yaml; charset=utf-8",
10190
+ ".yml": "text/yaml; charset=utf-8"
10191
+ };
10066
10192
  var WEB_UI_CONTENT_TYPES = {
10067
10193
  ".css": "text/css; charset=utf-8",
10068
10194
  ".html": "text/html; charset=utf-8",
@@ -10082,6 +10208,11 @@ Plan mode is enabled for this message only. Before doing substantial work, creat
10082
10208
  </user_instructions>
10083
10209
 
10084
10210
  `;
10211
+ var LATEST_VISIBLE_CODEX_COMMAND_CONFIG_VERSION = 2;
10212
+ var REVIEW_VISIBLE_CODEX_COMMAND_ENTRY = {
10213
+ name: "review",
10214
+ reason: "\u5FEB\u901F\u5BA1\u67E5\u5F53\u524D\u5DE5\u4F5C\u533A\u672A\u63D0\u4EA4\u6539\u52A8\uFF0C\u9002\u5408\u5728\u63D0\u4EA4\u524D\u6216\u7EE7\u7EED\u7F16\u7801\u524D\u5148\u81EA\u68C0\u4E00\u904D\u3002"
10215
+ };
10085
10216
  var FALLBACK_CODEX_COMMAND_CATALOG = [
10086
10217
  { name: "compact", description: "\u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u91CA\u653E\u7A97\u53E3\u5E76\u7EE7\u7EED\u5DE5\u4F5C\u3002", availability: "supported" },
10087
10218
  { name: "copy", description: "\u590D\u5236\u6700\u8FD1\u4E00\u6B21\u52A9\u624B\u8F93\u51FA\u3002", availability: "unsupported" },
@@ -10109,7 +10240,7 @@ var PANDA_SUPPORTED_COMMANDS = /* @__PURE__ */ new Set([
10109
10240
  "status"
10110
10241
  ]);
10111
10242
  var DEFAULT_VISIBLE_CODEX_COMMAND_CONFIG = {
10112
- version: 1,
10243
+ version: LATEST_VISIBLE_CODEX_COMMAND_CONFIG_VERSION,
10113
10244
  visible_commands: [
10114
10245
  {
10115
10246
  name: "model",
@@ -10119,6 +10250,7 @@ var DEFAULT_VISIBLE_CODEX_COMMAND_CONFIG = {
10119
10250
  name: "status",
10120
10251
  reason: "\u5FEB\u901F\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u6A21\u578B\u3001\u4E0A\u4E0B\u6587\u5360\u7528\u548C\u6C99\u7BB1\u7B49\u5173\u952E\u4FE1\u606F\uFF0C\u9002\u5408\u5148\u81EA\u68C0\u3002"
10121
10252
  },
10253
+ REVIEW_VISIBLE_CODEX_COMMAND_ENTRY,
10122
10254
  {
10123
10255
  name: "skills",
10124
10256
  reason: "\u628A\u9879\u76EE\u91CC\u53EF\u7528\u6280\u80FD\u76F4\u63A5\u66B4\u9732\u51FA\u6765\uFF0C\u80FD\u5E2E\u52A9\u7528\u6237\u53D1\u73B0 Panda \u5DF2\u63A5\u5165\u7684\u80FD\u529B\u3002"
@@ -10362,6 +10494,142 @@ var startPandaSessionService = async ({
10362
10494
  }
10363
10495
  return !relativePath.startsWith("..") && !path9.isAbsolute(relativePath);
10364
10496
  };
10497
+ const isAbsolutePathInsideProject = (projectPath, candidatePath) => {
10498
+ const resolvedProjectPath = path9.resolve(projectPath);
10499
+ const resolvedCandidatePath = path9.resolve(candidatePath);
10500
+ const relativePath = path9.relative(resolvedProjectPath, resolvedCandidatePath);
10501
+ if (!relativePath) {
10502
+ return true;
10503
+ }
10504
+ return !relativePath.startsWith("..") && !path9.isAbsolute(relativePath);
10505
+ };
10506
+ const normalizeSessionFilePreviewPath = (value) => normalizeGitWorkspacePath(value?.trim() ?? "").replace(/^\/+|\/+$/g, "");
10507
+ const isMissingPathError = (error) => error instanceof Error && "code" in error && error.code === "ENOENT";
10508
+ const resolveSessionFilePreviewPath = async (projectPath, requestedPath) => {
10509
+ const normalizedPath = normalizeSessionFilePreviewPath(requestedPath);
10510
+ const absolutePath = normalizedPath ? path9.resolve(projectPath, normalizedPath) : path9.resolve(projectPath);
10511
+ if (!isAbsolutePathInsideProject(projectPath, absolutePath)) {
10512
+ throw new Error("\u76EE\u6807\u8DEF\u5F84\u4E0D\u5728\u5F53\u524D\u9879\u76EE\u5185\u3002");
10513
+ }
10514
+ let realPath;
10515
+ try {
10516
+ realPath = await fs8.realpath(absolutePath);
10517
+ } catch (error) {
10518
+ if (isMissingPathError(error)) {
10519
+ throw new Error("File not found.");
10520
+ }
10521
+ throw error;
10522
+ }
10523
+ if (!isAbsolutePathInsideProject(projectPath, realPath)) {
10524
+ throw new Error("\u76EE\u6807\u8DEF\u5F84\u4E0D\u5728\u5F53\u524D\u9879\u76EE\u5185\u3002");
10525
+ }
10526
+ return {
10527
+ normalizedPath,
10528
+ absolutePath,
10529
+ realPath
10530
+ };
10531
+ };
10532
+ const normalizeSessionFilePreviewExtension = (value) => {
10533
+ const extension = path9.extname(value).trim().toLowerCase();
10534
+ return extension || null;
10535
+ };
10536
+ const detectSessionFilePreviewKind = (fileName, extension) => {
10537
+ const normalizedName = fileName.trim().toLowerCase();
10538
+ if (extension && SESSION_FILE_PREVIEW_MARKDOWN_EXTENSIONS.has(extension)) {
10539
+ return "markdown";
10540
+ }
10541
+ if (extension && SESSION_FILE_PREVIEW_IMAGE_EXTENSIONS.has(extension)) {
10542
+ return "image";
10543
+ }
10544
+ if (extension && SESSION_FILE_PREVIEW_TEXT_EXTENSIONS.has(extension)) {
10545
+ return "text";
10546
+ }
10547
+ if (extension && SESSION_FILE_PREVIEW_CODE_EXTENSIONS.has(extension) || SESSION_FILE_PREVIEW_CODE_FILENAMES.has(normalizedName) || SESSION_FILE_PREVIEW_CODE_NAME_PATTERNS.some((pattern) => pattern.test(normalizedName))) {
10548
+ return "code";
10549
+ }
10550
+ return null;
10551
+ };
10552
+ const getSessionFilePreviewMimeType = (extension, fileKind) => {
10553
+ if (extension && SESSION_FILE_PREVIEW_MIME_TYPES[extension]) {
10554
+ return SESSION_FILE_PREVIEW_MIME_TYPES[extension];
10555
+ }
10556
+ if (fileKind === "markdown") {
10557
+ return "text/markdown; charset=utf-8";
10558
+ }
10559
+ if (fileKind === "code" || fileKind === "text") {
10560
+ return "text/plain; charset=utf-8";
10561
+ }
10562
+ return null;
10563
+ };
10564
+ const looksLikeTextBuffer = (buffer) => {
10565
+ if (buffer.length === 0) {
10566
+ return true;
10567
+ }
10568
+ let suspiciousControlCount = 0;
10569
+ for (const byte of buffer.values()) {
10570
+ if (byte === 0) {
10571
+ return false;
10572
+ }
10573
+ const isAllowedWhitespace = byte === 9 || byte === 10 || byte === 13;
10574
+ if (!isAllowedWhitespace && byte < 32) {
10575
+ suspiciousControlCount += 1;
10576
+ }
10577
+ }
10578
+ return suspiciousControlCount / buffer.length < 0.08;
10579
+ };
10580
+ const readPreviewBuffer = async (filePath, byteLimit) => {
10581
+ const handle = await fs8.open(filePath, "r");
10582
+ try {
10583
+ const buffer = Buffer.alloc(byteLimit);
10584
+ const { bytesRead } = await handle.read(buffer, 0, byteLimit, 0);
10585
+ return buffer.subarray(0, bytesRead);
10586
+ } finally {
10587
+ await handle.close();
10588
+ }
10589
+ };
10590
+ const readDirectoryHasChildren = async (directoryPath) => {
10591
+ try {
10592
+ const entries = await fs8.readdir(directoryPath);
10593
+ return entries.length > 0;
10594
+ } catch {
10595
+ return false;
10596
+ }
10597
+ };
10598
+ const buildSessionFilePreviewTreeNode = async (projectPath, parentRelativePath, parentRealPath, entry) => {
10599
+ const nextRelativePath = normalizeGitWorkspacePath(
10600
+ parentRelativePath ? `${parentRelativePath}/${entry.name}` : entry.name
10601
+ );
10602
+ const entryPath = path9.join(parentRealPath, entry.name);
10603
+ if (entry.isSymbolicLink()) {
10604
+ try {
10605
+ const realPath = await fs8.realpath(entryPath);
10606
+ if (!isAbsolutePathInsideProject(projectPath, realPath)) {
10607
+ return null;
10608
+ }
10609
+ } catch {
10610
+ return null;
10611
+ }
10612
+ }
10613
+ const stat = await fs8.stat(entryPath).catch(() => null);
10614
+ if (!stat) {
10615
+ return null;
10616
+ }
10617
+ const kind = stat.isDirectory() ? "directory" : stat.isFile() ? "file" : null;
10618
+ if (!kind) {
10619
+ return null;
10620
+ }
10621
+ const extension = kind === "file" ? normalizeSessionFilePreviewExtension(entry.name) : null;
10622
+ const fileKind = kind === "file" ? detectSessionFilePreviewKind(entry.name, extension) ?? "binary" : null;
10623
+ return {
10624
+ path: nextRelativePath,
10625
+ name: entry.name,
10626
+ kind,
10627
+ has_children: kind === "directory" ? await readDirectoryHasChildren(entryPath) : false,
10628
+ extension,
10629
+ file_kind: fileKind,
10630
+ size_bytes: kind === "file" ? stat.size : null
10631
+ };
10632
+ };
10365
10633
  const runGitCommand = async (cwd, args, options) => new Promise((resolve, reject) => {
10366
10634
  let stdout = "";
10367
10635
  let stderr = "";
@@ -11023,17 +11291,36 @@ var startPandaSessionService = async ({
11023
11291
  return null;
11024
11292
  }
11025
11293
  const candidate = value;
11026
- if (candidate.version !== void 0 && candidate.version !== 1) {
11294
+ if (candidate.version !== void 0 && candidate.version !== 1 && candidate.version !== LATEST_VISIBLE_CODEX_COMMAND_CONFIG_VERSION) {
11027
11295
  return null;
11028
11296
  }
11029
11297
  if (!Array.isArray(candidate.visible_commands)) {
11030
11298
  return null;
11031
11299
  }
11032
11300
  return {
11033
- version: 1,
11301
+ version: candidate.version === LATEST_VISIBLE_CODEX_COMMAND_CONFIG_VERSION ? LATEST_VISIBLE_CODEX_COMMAND_CONFIG_VERSION : 1,
11034
11302
  visible_commands: candidate.visible_commands.map((entry) => normalizeVisibleCodexCommandConfigEntry(entry)).filter((entry) => Boolean(entry))
11035
11303
  };
11036
11304
  };
11305
+ const migrateVisibleCodexCommandConfig = (config) => {
11306
+ if (config.version >= LATEST_VISIBLE_CODEX_COMMAND_CONFIG_VERSION) {
11307
+ return config;
11308
+ }
11309
+ const visibleCommands = [...config.visible_commands];
11310
+ const hasReview = visibleCommands.some((entry) => entry.name === REVIEW_VISIBLE_CODEX_COMMAND_ENTRY.name);
11311
+ if (!hasReview) {
11312
+ const skillsIndex = visibleCommands.findIndex((entry) => entry.name === "skills");
11313
+ if (skillsIndex === -1) {
11314
+ visibleCommands.push(REVIEW_VISIBLE_CODEX_COMMAND_ENTRY);
11315
+ } else {
11316
+ visibleCommands.splice(skillsIndex, 0, REVIEW_VISIBLE_CODEX_COMMAND_ENTRY);
11317
+ }
11318
+ }
11319
+ return {
11320
+ version: LATEST_VISIBLE_CODEX_COMMAND_CONFIG_VERSION,
11321
+ visible_commands: visibleCommands
11322
+ };
11323
+ };
11037
11324
  const writeVisibleCodexCommandConfig = async (config) => {
11038
11325
  const configFilePath = await getCodexVisibleCommandsConfigFilePath();
11039
11326
  await fs8.writeFile(configFilePath, `${JSON.stringify(config, null, 2)}
@@ -11045,7 +11332,11 @@ var startPandaSessionService = async ({
11045
11332
  const raw = await fs8.readFile(configFilePath, "utf8");
11046
11333
  const parsed = parseVisibleCodexCommandConfig(JSON.parse(raw));
11047
11334
  if (parsed) {
11048
- return parsed;
11335
+ const migrated = migrateVisibleCodexCommandConfig(parsed);
11336
+ if (migrated !== parsed) {
11337
+ await writeVisibleCodexCommandConfig(migrated);
11338
+ }
11339
+ return migrated;
11049
11340
  }
11050
11341
  } catch {
11051
11342
  }
@@ -11302,6 +11593,36 @@ var startPandaSessionService = async ({
11302
11593
  }
11303
11594
  return `${trimmed.slice(0, maxLength - 1).trimEnd()}\u2026`;
11304
11595
  };
11596
+ const sanitizeGeneratedSessionTitle = (value, maxLength = SESSION_GENERATED_TITLE_MAX_LENGTH) => {
11597
+ const normalized = value.replace(/\r\n/g, "\n").split("\n").map((line) => line.trim()).filter(Boolean).join(" ").replace(/^["'`\[\]【】()()\s]+|["'`\[\]【】()()\s]+$/g, "").replace(/^(标题|Title)\s*[::-]\s*/i, "").replace(/\s+/g, " ").trim();
11598
+ if (!normalized) {
11599
+ return null;
11600
+ }
11601
+ if (normalized.length <= maxLength) {
11602
+ return normalized;
11603
+ }
11604
+ return normalized.slice(0, maxLength).trimEnd();
11605
+ };
11606
+ const buildSessionTitleGenerationPrompt = (input) => {
11607
+ const message = input.message.trim();
11608
+ const attachmentNames = input.attachments.map((attachment) => attachment.name.trim()).filter(Boolean).slice(0, 5);
11609
+ const contextParts = [
11610
+ message ? `\u7528\u6237\u9996\u6761\u6D88\u606F\uFF1A
11611
+ ${message}` : null,
11612
+ attachmentNames.length > 0 ? `\u9644\u4EF6\uFF1A
11613
+ ${attachmentNames.map((name) => `- ${name}`).join("\n")}` : null
11614
+ ].filter(Boolean);
11615
+ return [
11616
+ "\u8BF7\u6839\u636E\u4E0B\u9762\u7684\u65B0\u4F1A\u8BDD\u9996\u6761\u6D88\u606F\u751F\u6210\u4E00\u4E2A\u7B80\u77ED\u7684\u4E2D\u6587\u4F1A\u8BDD\u6807\u9898\u3002",
11617
+ "\u8981\u6C42\uFF1A",
11618
+ "1. \u53EA\u8F93\u51FA\u6807\u9898\u672C\u8EAB\uFF0C\u4E0D\u8981\u89E3\u91CA\uFF0C\u4E0D\u8981\u52A0\u5F15\u53F7\u3002",
11619
+ "2. \u6807\u9898\u8981\u51C6\u786E\u6982\u62EC\u4EFB\u52A1\u76EE\u6807\uFF0C\u4E0D\u8981\u7167\u6284\u539F\u53E5\u3002",
11620
+ "3. \u5C3D\u91CF\u63A7\u5236\u5728 4 \u5230 14 \u4E2A\u6C49\u5B57\uFF0C\u6216\u7B49\u4EF7\u7684\u77ED\u82F1\u6587\u957F\u5EA6\u3002",
11621
+ "4. \u907F\u514D\u7A7A\u6CDB\u8BCD\uFF0C\u6BD4\u5982\u201C\u6C42\u52A9\u201D\u201C\u95EE\u9898\u201D\u201C\u804A\u5929\u201D\u201C\u65B0\u4F1A\u8BDD\u201D\u3002",
11622
+ "",
11623
+ ...contextParts
11624
+ ].join("\n");
11625
+ };
11305
11626
  const createDiagnosticHash2 = (value) => createHash5("sha1").update(value).digest("hex").slice(0, 16);
11306
11627
  const summarizeTextForDiagnostics = (value, options) => {
11307
11628
  const normalized = typeof value === "string" ? value.trim() : "";
@@ -11339,6 +11660,7 @@ var startPandaSessionService = async ({
11339
11660
  dataHash: attachment.dataHash
11340
11661
  })),
11341
11662
  model: input.model,
11663
+ titleGenerationModel: input.titleGenerationModel ?? null,
11342
11664
  reasoningEffort: input.reasoningEffort,
11343
11665
  requestedServiceTier: input.requestedServiceTier ?? null,
11344
11666
  normalizedRequestedServiceTier: input.normalizedRequestedServiceTier,
@@ -11352,6 +11674,7 @@ var startPandaSessionService = async ({
11352
11674
  prompt: promptSummary,
11353
11675
  attachments: attachmentsSummary,
11354
11676
  model: input.model,
11677
+ titleGenerationModel: input.titleGenerationModel ?? null,
11355
11678
  reasoningEffort: input.reasoningEffort,
11356
11679
  requestedServiceTier: input.requestedServiceTier === "fast" || input.requestedServiceTier === "flex" ? input.requestedServiceTier : input.requestedServiceTier ?? null,
11357
11680
  normalizedRequestedServiceTier: input.normalizedRequestedServiceTier,
@@ -11564,7 +11887,7 @@ var startPandaSessionService = async ({
11564
11887
  return nextOverlayEntries;
11565
11888
  };
11566
11889
  const readTimelineFromRollout = async (sessionId) => {
11567
- const { readCodexTimeline } = await import("./src-M7W7LPHG.mjs");
11890
+ const { readCodexTimeline } = await import("./src-ILWWSZFE.mjs");
11568
11891
  return readCodexTimeline(sessionId, {
11569
11892
  codexHome,
11570
11893
  sessionFiles: discoveredSessionFiles
@@ -12163,6 +12486,14 @@ var startPandaSessionService = async ({
12163
12486
  }
12164
12487
  return [];
12165
12488
  };
12489
+ const readChangeSetForSession = async (sessionId, changeSetId) => {
12490
+ const changeSets = await readChangeSetsForSession(sessionId);
12491
+ return changeSets.find((entry) => entry.id === changeSetId) ?? null;
12492
+ };
12493
+ const readChangeSetForTurn = async (sessionId, turnId) => {
12494
+ const changeSets = await readChangeSetsForSession(sessionId);
12495
+ return changeSets.find((entry) => entry.turn_id === turnId) ?? null;
12496
+ };
12166
12497
  const readPlanForSession = async (sessionId) => {
12167
12498
  const existing = sessionPlans.get(sessionId);
12168
12499
  if (existing !== void 0) {
@@ -12194,8 +12525,7 @@ var startPandaSessionService = async ({
12194
12525
  return [];
12195
12526
  };
12196
12527
  const readChangeSetFileDiffForSession = async (sessionId, input) => {
12197
- const changeSets = await readChangeSetsForSession(sessionId);
12198
- const changeSet = changeSets.find((entry) => entry.id === input.changeSetId);
12528
+ const changeSet = await readChangeSetForSession(sessionId, input.changeSetId);
12199
12529
  if (!changeSet) {
12200
12530
  return null;
12201
12531
  }
@@ -12668,7 +12998,7 @@ var startPandaSessionService = async ({
12668
12998
  commands: filterCodexCommandsForDisplay(catalog.commands, visibleConfig)
12669
12999
  };
12670
13000
  };
12671
- const renameSessionFromCommand = async (sessionId, nextName) => {
13001
+ const renameSession = async (sessionId, nextName) => {
12672
13002
  if (managedSessions.has(sessionId)) {
12673
13003
  const managedSession = managedSessions.get(sessionId);
12674
13004
  managedSessions.set(sessionId, {
@@ -12693,6 +13023,37 @@ var startPandaSessionService = async ({
12693
13023
  }
12694
13024
  });
12695
13025
  };
13026
+ const generateSessionTitleInBackground = async (input) => {
13027
+ const prompt = buildSessionTitleGenerationPrompt({
13028
+ message: input.message,
13029
+ attachments: input.attachments
13030
+ });
13031
+ try {
13032
+ const generated = await liveSessionStream.runOneShotPrompt({
13033
+ cwd: input.project.path,
13034
+ prompt,
13035
+ model: input.model,
13036
+ timeoutMs: SESSION_TITLE_GENERATION_TIMEOUT_MS
13037
+ });
13038
+ const nextTitle = sanitizeGeneratedSessionTitle(generated);
13039
+ if (!nextTitle || nextTitle === input.fallbackTitle) {
13040
+ return;
13041
+ }
13042
+ const currentSession = await findSnapshotSession(input.sessionId);
13043
+ if (!currentSession || currentSession.title !== input.fallbackTitle) {
13044
+ return;
13045
+ }
13046
+ await renameSession(input.sessionId, nextTitle);
13047
+ } catch (error) {
13048
+ diagnosticLogger.warn({
13049
+ sessionId: input.sessionId,
13050
+ projectId: input.project.id,
13051
+ projectPath: input.project.path,
13052
+ model: input.model,
13053
+ error: error instanceof Error ? error.message : "Unknown error"
13054
+ }, "Failed to generate background session title.");
13055
+ }
13056
+ };
12696
13057
  const executeSessionCommand = async (session, project, rawInput) => {
12697
13058
  const parsed = parseSlashCommandInput(rawInput);
12698
13059
  if (!parsed) {
@@ -12794,7 +13155,7 @@ var startPandaSessionService = async ({
12794
13155
  }
12795
13156
  if (command.name === "rename") {
12796
13157
  if (parsed.args) {
12797
- await renameSessionFromCommand(session.id, parsed.args);
13158
+ await renameSession(session.id, parsed.args);
12798
13159
  return createCommandPanel({
12799
13160
  sessionId: session.id,
12800
13161
  commandName: command.name,
@@ -12864,7 +13225,7 @@ var startPandaSessionService = async ({
12864
13225
  if (!nextName) {
12865
13226
  throw new Error("\u8BF7\u8F93\u5165\u65B0\u7684\u4F1A\u8BDD\u540D\u79F0\u3002");
12866
13227
  }
12867
- await renameSessionFromCommand(input.sessionId, nextName);
13228
+ await renameSession(input.sessionId, nextName);
12868
13229
  clearStoredCommandPanel(input.panelId);
12869
13230
  return {
12870
13231
  ...stored.panel,
@@ -13032,7 +13393,7 @@ var startPandaSessionService = async ({
13032
13393
  lastSnapshotRefreshAt = Date.now();
13033
13394
  return snapshot;
13034
13395
  }
13035
- const { discoverLocalCodexData } = await import("./src-M7W7LPHG.mjs");
13396
+ const { discoverLocalCodexData } = await import("./src-ILWWSZFE.mjs");
13036
13397
  const discovery = await discoverLocalCodexData({
13037
13398
  agentId: localAgentId,
13038
13399
  agentName: localAgentName,
@@ -13108,6 +13469,135 @@ var startPandaSessionService = async ({
13108
13469
  return snapshot.projects.find((project) => project.id === projectId) ?? (await buildSnapshot({ force: true })).projects.find((project) => project.id === projectId) ?? null;
13109
13470
  };
13110
13471
  const readProjectForSession = async (session) => findSnapshotProject(session.project_id);
13472
+ const readSessionFilePreviewTree = async (session, project, requestedPath) => {
13473
+ const resolved = await resolveSessionFilePreviewPath(project.path, requestedPath);
13474
+ const stat = await fs8.stat(resolved.realPath).catch((error) => {
13475
+ if (isMissingPathError(error)) {
13476
+ throw new Error("File not found.");
13477
+ }
13478
+ throw error;
13479
+ });
13480
+ if (!stat.isDirectory()) {
13481
+ throw new Error("\u76EE\u6807\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\u3002");
13482
+ }
13483
+ const entries = await fs8.readdir(resolved.realPath, {
13484
+ withFileTypes: true
13485
+ });
13486
+ const nodes = (await Promise.all(
13487
+ entries.map(
13488
+ (entry) => buildSessionFilePreviewTreeNode(
13489
+ project.path,
13490
+ resolved.normalizedPath,
13491
+ resolved.realPath,
13492
+ entry
13493
+ )
13494
+ )
13495
+ )).filter((entry) => Boolean(entry)).sort((left, right) => {
13496
+ if (left.kind !== right.kind) {
13497
+ return left.kind === "directory" ? -1 : 1;
13498
+ }
13499
+ return left.name.localeCompare(right.name, "zh-CN");
13500
+ });
13501
+ return {
13502
+ session_id: session.id,
13503
+ project_id: project.id,
13504
+ root_path: SESSION_FILE_PREVIEW_ROOT_PATH,
13505
+ parent_path: resolved.normalizedPath || null,
13506
+ nodes,
13507
+ loaded_at: isoNow5()
13508
+ };
13509
+ };
13510
+ const readSessionFilePreviewContent = async (session, project, requestedPath) => {
13511
+ const resolved = await resolveSessionFilePreviewPath(project.path, requestedPath);
13512
+ const stat = await fs8.stat(resolved.realPath).catch((error) => {
13513
+ if (isMissingPathError(error)) {
13514
+ throw new Error("File not found.");
13515
+ }
13516
+ throw error;
13517
+ });
13518
+ if (!stat.isFile()) {
13519
+ throw new Error("\u76EE\u6807\u8DEF\u5F84\u4E0D\u662F\u6587\u4EF6\u3002");
13520
+ }
13521
+ const fileName = path9.basename(resolved.normalizedPath || resolved.realPath);
13522
+ const extension = normalizeSessionFilePreviewExtension(fileName);
13523
+ let fileKind = detectSessionFilePreviewKind(fileName, extension) ?? null;
13524
+ let previewBuffer = null;
13525
+ if (!fileKind || fileKind === "binary") {
13526
+ previewBuffer = await readPreviewBuffer(
13527
+ resolved.realPath,
13528
+ Math.min(SESSION_FILE_PREVIEW_TEXT_BYTE_LIMIT, Math.max(1024, stat.size))
13529
+ );
13530
+ fileKind = looksLikeTextBuffer(previewBuffer) ? "text" : "binary";
13531
+ }
13532
+ if (fileKind === "image") {
13533
+ if (stat.size > SESSION_FILE_PREVIEW_IMAGE_BYTE_LIMIT) {
13534
+ return {
13535
+ session_id: session.id,
13536
+ project_id: project.id,
13537
+ path: resolved.normalizedPath,
13538
+ name: fileName,
13539
+ extension,
13540
+ file_kind: fileKind,
13541
+ mime_type: getSessionFilePreviewMimeType(extension, fileKind),
13542
+ size_bytes: stat.size,
13543
+ encoding: null,
13544
+ is_truncated: true,
13545
+ content_text: null,
13546
+ content_base64: null,
13547
+ loaded_at: isoNow5()
13548
+ };
13549
+ }
13550
+ const buffer2 = await fs8.readFile(resolved.realPath);
13551
+ return {
13552
+ session_id: session.id,
13553
+ project_id: project.id,
13554
+ path: resolved.normalizedPath,
13555
+ name: fileName,
13556
+ extension,
13557
+ file_kind: fileKind,
13558
+ mime_type: getSessionFilePreviewMimeType(extension, fileKind),
13559
+ size_bytes: stat.size,
13560
+ encoding: "base64",
13561
+ is_truncated: false,
13562
+ content_text: null,
13563
+ content_base64: buffer2.toString("base64"),
13564
+ loaded_at: isoNow5()
13565
+ };
13566
+ }
13567
+ if (fileKind === "binary") {
13568
+ return {
13569
+ session_id: session.id,
13570
+ project_id: project.id,
13571
+ path: resolved.normalizedPath,
13572
+ name: fileName,
13573
+ extension,
13574
+ file_kind: fileKind,
13575
+ mime_type: getSessionFilePreviewMimeType(extension, fileKind),
13576
+ size_bytes: stat.size,
13577
+ encoding: null,
13578
+ is_truncated: false,
13579
+ content_text: null,
13580
+ content_base64: null,
13581
+ loaded_at: isoNow5()
13582
+ };
13583
+ }
13584
+ const buffer = previewBuffer ?? await readPreviewBuffer(resolved.realPath, SESSION_FILE_PREVIEW_TEXT_BYTE_LIMIT);
13585
+ return {
13586
+ session_id: session.id,
13587
+ project_id: project.id,
13588
+ path: resolved.normalizedPath,
13589
+ name: fileName,
13590
+ extension,
13591
+ file_kind: fileKind,
13592
+ mime_type: getSessionFilePreviewMimeType(extension, fileKind),
13593
+ size_bytes: stat.size,
13594
+ encoding: "utf8",
13595
+ is_truncated: stat.size > SESSION_FILE_PREVIEW_TEXT_BYTE_LIMIT,
13596
+ content_text: buffer.toString("utf8"),
13597
+ content_base64: null,
13598
+ loaded_at: isoNow5()
13599
+ };
13600
+ };
13111
13601
  const validateHubControlPlaneAuth = (request) => {
13112
13602
  const expectedApiKey = process.env.PANDA_HUB_API_KEY?.trim() ?? "";
13113
13603
  if (!expectedApiKey) {
@@ -13139,6 +13629,58 @@ var startPandaSessionService = async ({
13139
13629
  }
13140
13630
  await runGitCommand(projectPath, ["restore", "--source=HEAD", "--staged", "--worktree", "--", ...targetPaths]);
13141
13631
  };
13632
+ const normalizeRollbackPatchText = (input) => {
13633
+ const normalized = input.replace(/\r\n/g, "\n").trim();
13634
+ return normalized ? `${normalized}
13635
+ ` : "";
13636
+ };
13637
+ const buildRollbackPatchText = (changeSet) => {
13638
+ if (changeSet.aggregated_diff.trim()) {
13639
+ return normalizeRollbackPatchText(changeSet.aggregated_diff);
13640
+ }
13641
+ if (changeSet.files.some((file) => file.diff.trim().length === 0)) {
13642
+ return "";
13643
+ }
13644
+ return normalizeRollbackPatchText(
13645
+ changeSet.files.map((file) => file.diff).filter((diff) => diff.trim().length > 0).join("\n\n")
13646
+ );
13647
+ };
13648
+ const ensureChangeSetPathsAreInProject = (projectPath, changeSet) => {
13649
+ for (const file of changeSet.files) {
13650
+ const candidates = [file.path, file.move_path].filter((value) => Boolean(value?.trim()));
13651
+ for (const candidate of candidates) {
13652
+ if (!isPathInsideProject(projectPath, candidate)) {
13653
+ throw new Error("\u8FD9\u8F6E\u6539\u52A8\u5305\u542B\u8D85\u51FA\u5F53\u524D\u5DE5\u4F5C\u533A\u7684\u8DEF\u5F84\uFF0C\u65E0\u6CD5\u5B89\u5168\u56DE\u6EDA\u3002");
13654
+ }
13655
+ }
13656
+ }
13657
+ };
13658
+ const rollbackSessionChangeSet = async (projectPath, changeSet) => {
13659
+ if (changeSet.status !== "completed") {
13660
+ throw new Error("\u5F53\u524D\u8FD9\u8F6E\u6539\u52A8\u5C1A\u672A\u5B8C\u6210\uFF0C\u6682\u65F6\u4E0D\u80FD\u56DE\u6EDA\u3002");
13661
+ }
13662
+ if (changeSet.files.length === 0) {
13663
+ throw new Error("\u8FD9\u8F6E\u5BF9\u8BDD\u6CA1\u6709\u53EF\u56DE\u6EDA\u7684\u6587\u4EF6\u6539\u52A8\u3002");
13664
+ }
13665
+ ensureChangeSetPathsAreInProject(projectPath, changeSet);
13666
+ const patchText = buildRollbackPatchText(changeSet);
13667
+ if (!patchText) {
13668
+ throw new Error("\u8FD9\u8F6E\u6539\u52A8\u7F3A\u5C11\u53EF\u9006\u8865\u4E01\uFF0C\u6682\u65F6\u65E0\u6CD5\u56DE\u6EDA\u3002");
13669
+ }
13670
+ const tempDir = await fs8.mkdtemp(path9.join(os6.tmpdir(), "panda-change-set-rollback-"));
13671
+ const patchFilePath = path9.join(tempDir, "rollback.patch");
13672
+ await fs8.writeFile(patchFilePath, patchText, "utf8");
13673
+ try {
13674
+ const patchArgs = ["apply", "--reverse", "--whitespace=nowarn", "--binary", patchFilePath];
13675
+ await runGitCommand(projectPath, [...patchArgs.slice(0, 1), "--check", ...patchArgs.slice(1)]);
13676
+ await runGitCommand(projectPath, patchArgs);
13677
+ } catch (error) {
13678
+ const reason = error instanceof Error && error.message.trim() ? error.message : "Git \u65E0\u6CD5\u53CD\u5411\u5E94\u7528\u8FD9\u8F6E\u6539\u52A8\u7684\u8865\u4E01\u3002";
13679
+ throw new Error(`\u65E0\u6CD5\u5B89\u5168\u56DE\u6EDA\u8FD9\u8F6E\u6539\u52A8\uFF1A${reason}`);
13680
+ } finally {
13681
+ await fs8.rm(tempDir, { recursive: true, force: true }).catch(() => void 0);
13682
+ }
13683
+ };
13142
13684
  const discardAllGitWorkspaceChanges = async (projectPath) => {
13143
13685
  await runGitCommand(projectPath, ["restore", "--source=HEAD", "--staged", "--worktree", "--", "."]);
13144
13686
  await runGitCommand(projectPath, ["clean", "-fd", "--", "."], {
@@ -13843,6 +14385,107 @@ var startPandaSessionService = async ({
13843
14385
  }
13844
14386
  return diff;
13845
14387
  });
14388
+ app.post("/api/sessions/:sessionId/turns/:turnId/actions", async (request, reply) => {
14389
+ const { sessionId, turnId } = request.params;
14390
+ const session = await findSnapshotSession(sessionId);
14391
+ if (!session) {
14392
+ reply.code(404);
14393
+ return { error: "Session not found." };
14394
+ }
14395
+ if (!session.capability.can_show_git) {
14396
+ reply.code(409);
14397
+ return { error: "This session does not support git workspace actions." };
14398
+ }
14399
+ const project = await readProjectForSession(session);
14400
+ if (!project) {
14401
+ reply.code(404);
14402
+ return { error: "Project not found." };
14403
+ }
14404
+ if (request.body.action !== "rollback") {
14405
+ reply.code(409);
14406
+ return { error: "Unsupported turn action." };
14407
+ }
14408
+ const normalizedTurnId = turnId.trim();
14409
+ if (!normalizedTurnId) {
14410
+ reply.code(400);
14411
+ return { error: "Turn id is required." };
14412
+ }
14413
+ const changeSet = await readChangeSetForTurn(sessionId, normalizedTurnId);
14414
+ if (!changeSet) {
14415
+ reply.code(404);
14416
+ return { error: "Session turn change-set not found." };
14417
+ }
14418
+ try {
14419
+ await rollbackSessionChangeSet(project.path, changeSet);
14420
+ return {
14421
+ ok: true,
14422
+ turn_id: changeSet.turn_id,
14423
+ change_set_id: changeSet.id,
14424
+ workspace: await readSessionGitWorkspace(session, project)
14425
+ };
14426
+ } catch (error) {
14427
+ reply.code(409);
14428
+ return {
14429
+ error: error instanceof Error ? error.message : "Unable to execute turn action."
14430
+ };
14431
+ }
14432
+ });
14433
+ app.get("/api/sessions/:sessionId/file-preview/tree", async (request, reply) => {
14434
+ const { sessionId } = request.params;
14435
+ const { path: requestedPath } = request.query ?? {};
14436
+ const session = await findSnapshotSession(sessionId);
14437
+ if (!session) {
14438
+ reply.code(404);
14439
+ return { error: "Session not found." };
14440
+ }
14441
+ const project = await readProjectForSession(session);
14442
+ if (!project) {
14443
+ reply.code(404);
14444
+ return { error: "Project not found." };
14445
+ }
14446
+ try {
14447
+ return await readSessionFilePreviewTree(session, project, requestedPath ?? null);
14448
+ } catch (error) {
14449
+ if (error instanceof Error && error.message === "File not found.") {
14450
+ reply.code(404);
14451
+ return { error: error.message };
14452
+ }
14453
+ reply.code(409);
14454
+ return {
14455
+ error: error instanceof Error ? error.message : "Unable to read file preview tree."
14456
+ };
14457
+ }
14458
+ });
14459
+ app.get("/api/sessions/:sessionId/file-preview/content", async (request, reply) => {
14460
+ const { sessionId } = request.params;
14461
+ const { path: requestedPath } = request.query ?? {};
14462
+ const session = await findSnapshotSession(sessionId);
14463
+ if (!session) {
14464
+ reply.code(404);
14465
+ return { error: "Session not found." };
14466
+ }
14467
+ if (!requestedPath?.trim()) {
14468
+ reply.code(400);
14469
+ return { error: "path is required." };
14470
+ }
14471
+ const project = await readProjectForSession(session);
14472
+ if (!project) {
14473
+ reply.code(404);
14474
+ return { error: "Project not found." };
14475
+ }
14476
+ try {
14477
+ return await readSessionFilePreviewContent(session, project, requestedPath);
14478
+ } catch (error) {
14479
+ if (error instanceof Error && error.message === "File not found.") {
14480
+ reply.code(404);
14481
+ return { error: error.message };
14482
+ }
14483
+ reply.code(409);
14484
+ return {
14485
+ error: error instanceof Error ? error.message : "Unable to read file preview content."
14486
+ };
14487
+ }
14488
+ });
13846
14489
  app.get("/api/sessions/:sessionId/git-workspace", async (request, reply) => {
13847
14490
  const { sessionId } = request.params;
13848
14491
  const session = await findSnapshotSession(sessionId);
@@ -14543,6 +15186,7 @@ var startPandaSessionService = async ({
14543
15186
  const input = request.body.input?.trim() ?? "";
14544
15187
  const attachments = normalizeSessionInputAttachments(request.body.attachments);
14545
15188
  const model = request.body.model?.trim() || null;
15189
+ const titleGenerationModel = request.body.titleGenerationModel?.trim() || DEFAULT_SESSION_TITLE_GENERATION_MODEL;
14546
15190
  const reasoningEffort = request.body.reasoningEffort?.trim() || null;
14547
15191
  const requestedServiceTier = request.body.serviceTier;
14548
15192
  const normalizedRequestedServiceTier = normalizeServiceTier(requestedServiceTier);
@@ -14571,6 +15215,7 @@ var startPandaSessionService = async ({
14571
15215
  prompt,
14572
15216
  attachments,
14573
15217
  model,
15218
+ titleGenerationModel,
14574
15219
  reasoningEffort,
14575
15220
  requestedServiceTier,
14576
15221
  normalizedRequestedServiceTier,
@@ -14664,6 +15309,14 @@ var startPandaSessionService = async ({
14664
15309
  managedSessions.set(session.id, session);
14665
15310
  upsertSnapshotSession(session);
14666
15311
  broadcastSnapshotChanged();
15312
+ void generateSessionTitleInBackground({
15313
+ sessionId: session.id,
15314
+ project,
15315
+ fallbackTitle: title,
15316
+ message: input,
15317
+ attachments,
15318
+ model: titleGenerationModel
15319
+ });
14667
15320
  reply.code(201);
14668
15321
  return { session };
14669
15322
  });
@@ -14687,29 +15340,7 @@ var startPandaSessionService = async ({
14687
15340
  reply.code(400);
14688
15341
  return { error: "Session name is required." };
14689
15342
  }
14690
- if (managedSessions.has(sessionId)) {
14691
- const managedSession = managedSessions.get(sessionId);
14692
- managedSessions.set(sessionId, {
14693
- ...managedSession,
14694
- title: nextName
14695
- });
14696
- }
14697
- await liveSessionStream.setThreadName(sessionId, nextName).catch(() => {
14698
- });
14699
- await appendSessionIndexUpdate(
14700
- sessionId,
14701
- {
14702
- thread_name: nextName
14703
- },
14704
- codexHome
14705
- );
14706
- patchSnapshotSession(sessionId, { title: nextName });
14707
- broadcastEvent("session.updated", {
14708
- sessionId,
14709
- sessionPatch: {
14710
- title: nextName
14711
- }
14712
- });
15343
+ await renameSession(sessionId, nextName);
14713
15344
  return {
14714
15345
  ok: true,
14715
15346
  affectedSessionIds: [sessionId],