ccpanel 0.1.5 → 0.1.6

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.
Files changed (2) hide show
  1. package/dist/cli.js +101 -31
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1508,6 +1508,18 @@ function blocksFromContent(content) {
1508
1508
  }
1509
1509
  return out;
1510
1510
  }
1511
+ function outputText(output) {
1512
+ if (typeof output === "string") return output;
1513
+ return textFromContent(output);
1514
+ }
1515
+ function summaryText(summary) {
1516
+ if (!Array.isArray(summary)) return "";
1517
+ return summary.map((raw) => {
1518
+ if (!raw || typeof raw !== "object") return "";
1519
+ const s = raw;
1520
+ return typeof s.text === "string" ? s.text : "";
1521
+ }).filter(Boolean).join("\n");
1522
+ }
1511
1523
  function parseFunctionArguments(args) {
1512
1524
  if (typeof args !== "string") return JSON.stringify(args ?? {}, null, 2);
1513
1525
  try {
@@ -1523,7 +1535,9 @@ var CodexSessionService = class {
1523
1535
  this.readIndex(paths)
1524
1536
  ]);
1525
1537
  const project = normalizeProjectPath(projectPath);
1526
- return rollouts.filter((r) => normalizeProjectPath(r.cwd) === project).map((r) => {
1538
+ return rollouts.filter(
1539
+ (r) => normalizeProjectPath(r.cwd) === project && r.threadSource !== "subagent"
1540
+ ).map((r) => {
1527
1541
  const idx = index.get(r.id);
1528
1542
  const mtime = idx?.updatedAt ? Date.parse(idx.updatedAt) : r.mtime;
1529
1543
  return {
@@ -1538,12 +1552,38 @@ var CodexSessionService = class {
1538
1552
  async read(paths, projectPath, id) {
1539
1553
  assertSafeId2(id);
1540
1554
  const project = normalizeProjectPath(projectPath);
1541
- const found = (await this.scanRollouts(paths)).find(
1555
+ const rollouts = await this.scanRollouts(paths);
1556
+ const found = rollouts.find(
1542
1557
  (r) => r.id === id && normalizeProjectPath(r.cwd) === project
1543
1558
  );
1544
1559
  if (!found) throw new Error(`\u672A\u627E\u5230\u4F1A\u8BDD\uFF1A${id}`);
1545
1560
  const parsed = this.parseDetail(await readFile9(found.file, "utf8"));
1546
- return { messages: parsed.messages, subagents: [], skippedRecords: parsed.skipped };
1561
+ const subagents = await this.readSubagents(rollouts, parsed.subagentRefs);
1562
+ return { messages: parsed.messages, subagents, skippedRecords: parsed.skipped };
1563
+ }
1564
+ // 按 sub_agent_activity(started) 引用加载子会话;文件缺失或解析失败均跳过,
1565
+ // 不影响主会话展示。只嵌套一层:子会话内部的 subagentRefs 不再展开。
1566
+ async readSubagents(rollouts, refs) {
1567
+ const out = [];
1568
+ for (const ref of refs) {
1569
+ const rollout = rollouts.find((r) => r.id === ref.threadId);
1570
+ if (!rollout) continue;
1571
+ let parsed;
1572
+ try {
1573
+ parsed = this.parseDetail(await readFile9(rollout.file, "utf8"));
1574
+ } catch {
1575
+ continue;
1576
+ }
1577
+ const firstUser = parsed.messages.find((m) => m.type === "user");
1578
+ out.push({
1579
+ toolUseId: ref.toolUseId,
1580
+ agentId: ref.threadId,
1581
+ agentType: ref.agentPath.split("/").filter(Boolean).pop() ?? "subagent",
1582
+ description: (firstUser?.blocks[0]?.text ?? "").replace(/\s+/g, " ").trim().slice(0, 200),
1583
+ messages: parsed.messages
1584
+ });
1585
+ }
1586
+ return out;
1547
1587
  }
1548
1588
  async scanRollouts(paths) {
1549
1589
  const files = await this.rolloutFiles(paths.codexSessionsDir);
@@ -1580,6 +1620,7 @@ var CodexSessionService = class {
1580
1620
  let cwd = "";
1581
1621
  let firstPrompt = "";
1582
1622
  let messageCount = 0;
1623
+ let threadSource;
1583
1624
  for (const line of raw.split("\n")) {
1584
1625
  if (!line.trim()) continue;
1585
1626
  let obj;
@@ -1592,6 +1633,7 @@ var CodexSessionService = class {
1592
1633
  if (obj.type === "session_meta" || payload.type === "session_meta") {
1593
1634
  id = String(payload.id ?? id);
1594
1635
  cwd = String(payload.cwd ?? cwd);
1636
+ if (payload.thread_source) threadSource = String(payload.thread_source);
1595
1637
  continue;
1596
1638
  }
1597
1639
  if (payload.type === "message") {
@@ -1607,7 +1649,16 @@ var CodexSessionService = class {
1607
1649
  id = m?.[1] ?? "";
1608
1650
  }
1609
1651
  if (!id || !cwd) return void 0;
1610
- return { id, file, cwd, mtime: st.mtimeMs, size: st.size, firstPrompt, messageCount };
1652
+ return {
1653
+ id,
1654
+ file,
1655
+ cwd,
1656
+ mtime: st.mtimeMs,
1657
+ size: st.size,
1658
+ firstPrompt,
1659
+ messageCount,
1660
+ threadSource
1661
+ };
1611
1662
  }
1612
1663
  async readIndex(paths) {
1613
1664
  const out = /* @__PURE__ */ new Map();
@@ -1637,8 +1688,22 @@ var CodexSessionService = class {
1637
1688
  }
1638
1689
  parseDetail(raw) {
1639
1690
  const messages = [];
1691
+ const subagentRefs = [];
1640
1692
  let skipped = 0;
1641
1693
  let currentAssistant;
1694
+ let pendingReasoning = "";
1695
+ const ensureAssistant = (timestamp) => {
1696
+ if (!currentAssistant) {
1697
+ currentAssistant = {
1698
+ type: "assistant",
1699
+ role: "assistant",
1700
+ timestamp: timestamp ? String(timestamp) : void 0,
1701
+ blocks: []
1702
+ };
1703
+ messages.push(currentAssistant);
1704
+ }
1705
+ return currentAssistant;
1706
+ };
1642
1707
  for (const line of raw.split("\n")) {
1643
1708
  if (!line.trim()) continue;
1644
1709
  let obj;
@@ -1649,6 +1714,30 @@ var CodexSessionService = class {
1649
1714
  continue;
1650
1715
  }
1651
1716
  const payload = payloadOf(obj);
1717
+ if (payload.type === "agent_reasoning") {
1718
+ const text = String(payload.text ?? "").trim();
1719
+ if (text) pendingReasoning = text;
1720
+ continue;
1721
+ }
1722
+ if (payload.type === "reasoning") {
1723
+ const text = pendingReasoning || summaryText(payload.summary);
1724
+ pendingReasoning = "";
1725
+ ensureAssistant(obj.timestamp).blocks.push({
1726
+ kind: "thinking",
1727
+ text: truncate2(text)
1728
+ });
1729
+ continue;
1730
+ }
1731
+ if (payload.type === "sub_agent_activity") {
1732
+ if (payload.kind === "started" && payload.event_id && payload.agent_thread_id) {
1733
+ subagentRefs.push({
1734
+ toolUseId: String(payload.event_id),
1735
+ threadId: String(payload.agent_thread_id),
1736
+ agentPath: String(payload.agent_path ?? "")
1737
+ });
1738
+ }
1739
+ continue;
1740
+ }
1652
1741
  if (payload.type === "message") {
1653
1742
  const role = String(payload.role ?? "");
1654
1743
  if (role !== "user" && role !== "assistant") continue;
@@ -1663,45 +1752,26 @@ var CodexSessionService = class {
1663
1752
  currentAssistant = role === "assistant" ? msg : void 0;
1664
1753
  continue;
1665
1754
  }
1666
- if (payload.type === "function_call") {
1667
- const target = currentAssistant ?? {
1668
- type: "assistant",
1669
- role: "assistant",
1670
- timestamp: obj.timestamp ? String(obj.timestamp) : void 0,
1671
- blocks: []
1672
- };
1673
- if (!currentAssistant) {
1674
- messages.push(target);
1675
- currentAssistant = target;
1676
- }
1677
- target.blocks.push({
1755
+ if (payload.type === "function_call" || payload.type === "custom_tool_call") {
1756
+ const args = payload.type === "custom_tool_call" ? payload.input : payload.arguments;
1757
+ ensureAssistant(obj.timestamp).blocks.push({
1678
1758
  kind: "tool_use",
1679
1759
  name: String(payload.name ?? "tool"),
1680
- text: truncate2(parseFunctionArguments(payload.arguments)),
1760
+ text: truncate2(parseFunctionArguments(args)),
1681
1761
  toolUseId: payload.call_id ? String(payload.call_id) : void 0
1682
1762
  });
1683
1763
  continue;
1684
1764
  }
1685
- if (payload.type === "function_call_output") {
1686
- const target = currentAssistant ?? {
1687
- type: "assistant",
1688
- role: "assistant",
1689
- timestamp: obj.timestamp ? String(obj.timestamp) : void 0,
1690
- blocks: []
1691
- };
1692
- if (!currentAssistant) {
1693
- messages.push(target);
1694
- currentAssistant = target;
1695
- }
1696
- target.blocks.push({
1765
+ if (payload.type === "function_call_output" || payload.type === "custom_tool_call_output") {
1766
+ ensureAssistant(obj.timestamp).blocks.push({
1697
1767
  kind: "tool_result",
1698
- text: truncate2(String(payload.output ?? "")),
1768
+ text: truncate2(outputText(payload.output)),
1699
1769
  isError: payload.is_error === true,
1700
1770
  toolUseId: payload.call_id ? String(payload.call_id) : void 0
1701
1771
  });
1702
1772
  }
1703
1773
  }
1704
- return { messages, skipped };
1774
+ return { messages, skipped, subagentRefs };
1705
1775
  }
1706
1776
  };
1707
1777
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccpanel",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "本地图形化管理 Claude Code 配置:MCP、Skills、子 Agent、Commands、配置文件、Memory、Sessions、Plugins",
5
5
  "type": "module",
6
6
  "repository": {