@ai-setting/roy-agent-cli 1.5.111 → 1.5.113

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.
@@ -7427,7 +7427,7 @@ var require_dist = __commonJS((exports) => {
7427
7427
  var require_package = __commonJS((exports, module) => {
7428
7428
  module.exports = {
7429
7429
  name: "@ai-setting/roy-agent-cli",
7430
- version: "1.5.111",
7430
+ version: "1.5.113",
7431
7431
  type: "module",
7432
7432
  description: "CLI for roy-agent - Non-interactive command execution",
7433
7433
  main: "./dist/index.js",
@@ -9270,6 +9270,7 @@ Task #${taskId}`;
9270
9270
  message += `
9271
9271
  结果: ${truncatedResult}`;
9272
9272
  }
9273
+ message += this.appendSubSessionId(payload);
9273
9274
  return message;
9274
9275
  }
9275
9276
  formatTaskFailed(payload) {
@@ -9292,6 +9293,7 @@ Task #${taskId}`;
9292
9293
  message += `
9293
9294
  错误: ${truncatedError}`;
9294
9295
  }
9296
+ message += this.appendSubSessionId(payload);
9295
9297
  return message;
9296
9298
  }
9297
9299
  formatTaskTimeout(payload) {
@@ -9308,6 +9310,7 @@ bgprocess: ${bgProcessId}`;
9308
9310
  message += `
9309
9311
  Task #${taskId}`;
9310
9312
  }
9313
+ message += this.appendSubSessionId(payload);
9311
9314
  return message;
9312
9315
  }
9313
9316
  formatTaskStopped(payload) {
@@ -9324,8 +9327,16 @@ bgprocess: ${bgProcessId}`;
9324
9327
  message += `
9325
9328
  Task #${taskId}`;
9326
9329
  }
9330
+ message += this.appendSubSessionId(payload);
9327
9331
  return message;
9328
9332
  }
9333
+ appendSubSessionId(payload) {
9334
+ if (payload.subSessionId) {
9335
+ return `
9336
+ subSessionId: ${payload.subSessionId}`;
9337
+ }
9338
+ return "";
9339
+ }
9329
9340
  formatGeneric(event) {
9330
9341
  return `${this.prefix} 收到事件: ${event.type}`;
9331
9342
  }
@@ -10810,11 +10821,169 @@ var InteractiveCommand = createInteractiveCommand();
10810
10821
 
10811
10822
  // src/commands/sessions/list.ts
10812
10823
  import chalk6 from "chalk";
10824
+
10825
+ // src/commands/sessions/session-graph.ts
10826
+ function buildSessionTree(sessions) {
10827
+ const byId = new Map;
10828
+ const childrenByParent = new Map;
10829
+ for (const s of sessions) {
10830
+ byId.set(s.id, s);
10831
+ const pid = s.parentSessionId;
10832
+ if (pid !== null && pid !== undefined && pid !== "") {
10833
+ const bucket = childrenByParent.get(pid);
10834
+ if (bucket)
10835
+ bucket.push(s);
10836
+ else
10837
+ childrenByParent.set(pid, [s]);
10838
+ }
10839
+ }
10840
+ const cycleMembers = new Set;
10841
+ const consumed = new Set;
10842
+ function build(session, ancestorStack) {
10843
+ const node = { session, children: [] };
10844
+ const candidates = childrenByParent.get(session.id) ?? [];
10845
+ for (const candidate of candidates) {
10846
+ if (ancestorStack.has(candidate.id)) {
10847
+ cycleMembers.add(candidate.id);
10848
+ cycleMembers.add(session.id);
10849
+ continue;
10850
+ }
10851
+ if (consumed.has(candidate.id)) {
10852
+ continue;
10853
+ }
10854
+ consumed.add(candidate.id);
10855
+ const nextStack = new Set(ancestorStack);
10856
+ nextStack.add(session.id);
10857
+ const child = build(candidate, nextStack);
10858
+ node.children.push(child);
10859
+ }
10860
+ return node;
10861
+ }
10862
+ const roots = [];
10863
+ const orphans = [];
10864
+ for (const s of sessions) {
10865
+ const parentId = s.parentSessionId;
10866
+ const hasParentId = parentId !== null && parentId !== undefined && parentId !== "";
10867
+ if (!hasParentId) {
10868
+ if (consumed.has(s.id))
10869
+ continue;
10870
+ consumed.add(s.id);
10871
+ const node = build(s, new Set([s.id]));
10872
+ roots.push(node);
10873
+ } else if (!byId.has(parentId)) {
10874
+ orphans.push(s);
10875
+ }
10876
+ }
10877
+ if (consumed.size + orphans.length < sessions.length) {
10878
+ for (const s of sessions) {
10879
+ if (consumed.has(s.id))
10880
+ continue;
10881
+ if (orphans.includes(s))
10882
+ continue;
10883
+ const visited = new Set;
10884
+ let cur = s;
10885
+ while (cur) {
10886
+ if (visited.has(cur.id)) {
10887
+ for (const v of visited)
10888
+ cycleMembers.add(v);
10889
+ cycleMembers.add(s.id);
10890
+ break;
10891
+ }
10892
+ visited.add(cur.id);
10893
+ const pid = cur.parentSessionId;
10894
+ if (pid === null || pid === undefined || pid === "")
10895
+ break;
10896
+ cur = byId.get(pid);
10897
+ }
10898
+ consumed.add(s.id);
10899
+ const node = build(s, new Set([s.id]));
10900
+ roots.push(node);
10901
+ }
10902
+ }
10903
+ return { roots, orphans, cycles: cycleMembers };
10904
+ }
10905
+ var TREE_BRANCH = "├── ";
10906
+ var TREE_LAST = "└── ";
10907
+ var TREE_VERTICAL = "│ ";
10908
+ var TREE_EMPTY = " ";
10909
+ function renderSessionTree(tree, options = {}) {
10910
+ if (tree.roots.length === 0 && tree.orphans.length === 0) {
10911
+ return "No sessions.";
10912
+ }
10913
+ const lines = ["Session Tree"];
10914
+ for (let i = 0;i < tree.roots.length; i++) {
10915
+ const isLast = i === tree.roots.length - 1 && tree.orphans.length === 0;
10916
+ renderNode(tree.roots[i], "", isLast, lines, tree.cycles, options);
10917
+ }
10918
+ if (tree.orphans.length > 0) {
10919
+ for (let i = 0;i < tree.orphans.length; i++) {
10920
+ const s = tree.orphans[i];
10921
+ const isLast = i === tree.orphans.length - 1;
10922
+ const branch = isLast ? TREE_LAST : TREE_BRANCH;
10923
+ lines.push(`${branch}${formatNodeLabel(s, true, false, options)}`);
10924
+ }
10925
+ }
10926
+ return lines.join(`
10927
+ `);
10928
+ }
10929
+ function renderNode(node, prefix, isLast, lines, cycles, options) {
10930
+ const branch = isLast ? TREE_LAST : TREE_BRANCH;
10931
+ const isCycle = cycles.has(node.session.id);
10932
+ lines.push(`${prefix}${branch}${formatNodeLabel(node.session, false, isCycle, options)}`);
10933
+ const childPrefix = prefix + (isLast ? TREE_EMPTY : TREE_VERTICAL);
10934
+ for (let i = 0;i < node.children.length; i++) {
10935
+ const isChildLast = i === node.children.length - 1;
10936
+ renderNode(node.children[i], childPrefix, isChildLast, lines, cycles, options);
10937
+ }
10938
+ }
10939
+ function formatNodeLabel(session, isOrphan, isCycle = false, options = {}) {
10940
+ const idStr = options.useShortId ? shortSessionId(session.id) : session.id;
10941
+ const sourceLabel = inferSourceLabel(session);
10942
+ const status = inferStatus(session);
10943
+ const created = new Date(session.createdAt).toISOString().slice(0, 16).replace("T", " ");
10944
+ const parts = [idStr, sourceLabel];
10945
+ if (status)
10946
+ parts.push(`(${status})`);
10947
+ parts.push(created);
10948
+ let label = parts.join(" ");
10949
+ if (isOrphan)
10950
+ label = `[orphan] ${label}`;
10951
+ if (isCycle)
10952
+ label = `[cycle] ${label}`;
10953
+ return label;
10954
+ }
10955
+ function shortSessionId(id) {
10956
+ const underscoreIdx = id.indexOf("_");
10957
+ const stripped = underscoreIdx > 0 && underscoreIdx < id.length - 8 ? id.slice(underscoreIdx + 1) : id;
10958
+ return stripped.length > 8 ? stripped.slice(0, 8) : stripped;
10959
+ }
10960
+ function inferSourceLabel(session) {
10961
+ const meta = session.metadata;
10962
+ const type = meta?.type;
10963
+ if (type === "workflow") {
10964
+ const name = meta?.workflowName;
10965
+ return name ? `workflow/${name}` : "workflow";
10966
+ }
10967
+ if (type === "agent")
10968
+ return "agent";
10969
+ if (type === "subagent" || type === "sub-agent")
10970
+ return "[subagent]";
10971
+ return "chat";
10972
+ }
10973
+ function inferStatus(session) {
10974
+ const meta = session.metadata;
10975
+ const status = meta?.status;
10976
+ if (typeof status === "string" && status.length > 0)
10977
+ return status;
10978
+ return null;
10979
+ }
10980
+
10981
+ // src/commands/sessions/list.ts
10813
10982
  var ListCommand = {
10814
10983
  command: "list [options]",
10815
10984
  aliases: ["ls"],
10816
10985
  describe: "列出所有会话",
10817
- builder: (yargs) => yargs.option("limit", { alias: "n", type: "number", default: 20 }).option("offset", { type: "number", default: 0 }).option("sort", { type: "string", default: "updatedAt" }).option("order", { type: "string", default: "desc" }).option("json", { alias: "j", type: "boolean", default: false }).option("quiet", { alias: "q", type: "boolean", hidden: true }).option("id", { alias: "i", type: "boolean", default: false, description: "显示 Session ID" }).option("type", { alias: "t", type: "string", description: "按 session 类型过滤 (如 workflow)" }).option("status", { alias: "s", type: "string", description: "按状态过滤 (如 running, paused)" }),
10986
+ builder: (yargs) => yargs.option("limit", { alias: "n", type: "number", default: 20 }).option("offset", { type: "number", default: 0 }).option("sort", { type: "string", default: "updatedAt" }).option("order", { type: "string", default: "desc" }).option("json", { alias: "j", type: "boolean", default: false }).option("quiet", { alias: "q", type: "boolean", hidden: true }).option("id", { alias: "i", type: "boolean", default: false, description: "显示 Session ID" }).option("type", { alias: "t", type: "string", description: "按 session 类型过滤 (如 workflow)" }).option("status", { alias: "s", type: "string", description: "按状态过滤 (如 running, paused)" }).option("graph", { alias: "g", type: "boolean", default: false, description: "以层次化树形结构展示 session 父子关系" }).option("short-id", { type: "boolean", default: false, description: "[graph] 用 8 字符截断 id 显示(默认显示完整 sessionId)" }),
10818
10987
  async handler(args) {
10819
10988
  const isQuiet = args.quiet === true;
10820
10989
  if (isQuiet) {
@@ -10855,6 +11024,11 @@ var ListCommand = {
10855
11024
  const sessions = await sessionComponent.list(listOptions);
10856
11025
  const totalCount = await sessionComponent.getCount();
10857
11026
  const activeSessionId = sessionComponent.getActiveSessionId();
11027
+ if (args.graph) {
11028
+ const tree = buildSessionTree(sessions);
11029
+ output.log(renderSessionTree(tree, { useShortId: args.shortId === true }));
11030
+ return;
11031
+ }
10858
11032
  if (args.json) {
10859
11033
  output.json({
10860
11034
  total: sessions.length,
@@ -10869,6 +11043,8 @@ var ListCommand = {
10869
11043
  type: workflowMeta?.type || "chat",
10870
11044
  status: workflowMeta?.status,
10871
11045
  workflowName: workflowMeta?.workflowName,
11046
+ parentSessionId: s.parentSessionId ?? null,
11047
+ parentID: s.parentID ?? null,
10872
11048
  hasCheckpoint: !!s.metadata?.checkpoints?.checkpoints?.length,
10873
11049
  lastCheckpointAt: s.metadata?.checkpoints?.latestCheckpointId,
10874
11050
  createdAt: new Date(s.createdAt).toISOString(),
@@ -10886,6 +11062,7 @@ var ListCommand = {
10886
11062
  chalk6.bold("#"),
10887
11063
  chalk6.bold("Title"),
10888
11064
  chalk6.bold("ID"),
11065
+ chalk6.bold("Parent"),
10889
11066
  hasTypeFilter || hasStatusFilter ? chalk6.bold("Status") : null,
10890
11067
  chalk6.bold("Msgs"),
10891
11068
  chalk6.bold("CP")
@@ -10895,8 +11072,9 @@ var ListCommand = {
10895
11072
  const hasCp = (s.metadata?.checkpoints?.checkpoints?.length ?? 0) > 0;
10896
11073
  const title = s.title.length > 20 ? s.title.slice(0, 17) + "..." : s.title;
10897
11074
  const idStr = s.id;
11075
+ const useShortId = args.shortId === true;
11076
+ const parentStr = s.parentSessionId ? chalk6.gray(useShortId ? shortSessionId(s.parentSessionId) : s.parentSessionId) : chalk6.gray("-");
10898
11077
  const workflowMeta = s.metadata?.type === "workflow" ? s.metadata : null;
10899
- const typeStr = workflowMeta?.type || "";
10900
11078
  const statusStr = workflowMeta?.status || "";
10901
11079
  let statusDisplay = "";
10902
11080
  if (hasTypeFilter || hasStatusFilter) {
@@ -10907,7 +11085,8 @@ var ListCommand = {
10907
11085
  const cells = [
10908
11086
  marker + " " + (args.offset + i + 1),
10909
11087
  title,
10910
- chalk6.gray(idStr)
11088
+ chalk6.gray(idStr),
11089
+ parentStr
10911
11090
  ];
10912
11091
  if (hasTypeFilter || hasStatusFilter) {
10913
11092
  cells.push(statusDisplay || chalk6.gray("-"));
@@ -19310,6 +19489,7 @@ import fs5 from "fs";
19310
19489
  import path8 from "path";
19311
19490
  import { createRunWorkflowTool } from "@ai-setting/roy-agent-core/env/workflow/tools";
19312
19491
  import { getTracerProvider as getTracerProvider4, propagation, wrapFunction } from "@ai-setting/roy-agent-core";
19492
+ import { isValidSessionId } from "@ai-setting/roy-agent-core/env/session";
19313
19493
  var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
19314
19494
  const output = new OutputService2;
19315
19495
  const envService = new EnvironmentService(output);
@@ -19381,6 +19561,14 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
19381
19561
  parallelLimit: args.parallelLimit,
19382
19562
  timeout: args.timeout
19383
19563
  };
19564
+ const rawEnvParentId = process.env["ROY_PARENT_SESSION_ID"];
19565
+ if (typeof rawEnvParentId === "string" && rawEnvParentId.length > 0) {
19566
+ if (isValidSessionId(rawEnvParentId)) {
19567
+ runOptions.parentSessionId = rawEnvParentId;
19568
+ } else {
19569
+ output.warn(`Ignoring malformed ROY_PARENT_SESSION_ID env value (must match /^[A-Za-z0-9_-]{8,128}$/)`);
19570
+ }
19571
+ }
19384
19572
  if (args.session) {
19385
19573
  const sessionId = args.session;
19386
19574
  output.log(chalk69.blue(`\uD83D\uDD04 Resuming workflow from session: ${sessionId}`));
package/dist/index.js CHANGED
@@ -7426,7 +7426,7 @@ var require_dist = __commonJS((exports) => {
7426
7426
  var require_package = __commonJS((exports, module) => {
7427
7427
  module.exports = {
7428
7428
  name: "@ai-setting/roy-agent-cli",
7429
- version: "1.5.111",
7429
+ version: "1.5.113",
7430
7430
  type: "module",
7431
7431
  description: "CLI for roy-agent - Non-interactive command execution",
7432
7432
  main: "./dist/index.js",
@@ -9269,6 +9269,7 @@ Task #${taskId}`;
9269
9269
  message += `
9270
9270
  结果: ${truncatedResult}`;
9271
9271
  }
9272
+ message += this.appendSubSessionId(payload);
9272
9273
  return message;
9273
9274
  }
9274
9275
  formatTaskFailed(payload) {
@@ -9291,6 +9292,7 @@ Task #${taskId}`;
9291
9292
  message += `
9292
9293
  错误: ${truncatedError}`;
9293
9294
  }
9295
+ message += this.appendSubSessionId(payload);
9294
9296
  return message;
9295
9297
  }
9296
9298
  formatTaskTimeout(payload) {
@@ -9307,6 +9309,7 @@ bgprocess: ${bgProcessId}`;
9307
9309
  message += `
9308
9310
  Task #${taskId}`;
9309
9311
  }
9312
+ message += this.appendSubSessionId(payload);
9310
9313
  return message;
9311
9314
  }
9312
9315
  formatTaskStopped(payload) {
@@ -9323,8 +9326,16 @@ bgprocess: ${bgProcessId}`;
9323
9326
  message += `
9324
9327
  Task #${taskId}`;
9325
9328
  }
9329
+ message += this.appendSubSessionId(payload);
9326
9330
  return message;
9327
9331
  }
9332
+ appendSubSessionId(payload) {
9333
+ if (payload.subSessionId) {
9334
+ return `
9335
+ subSessionId: ${payload.subSessionId}`;
9336
+ }
9337
+ return "";
9338
+ }
9328
9339
  formatGeneric(event) {
9329
9340
  return `${this.prefix} 收到事件: ${event.type}`;
9330
9341
  }
@@ -10809,11 +10820,169 @@ var InteractiveCommand = createInteractiveCommand();
10809
10820
 
10810
10821
  // src/commands/sessions/list.ts
10811
10822
  import chalk6 from "chalk";
10823
+
10824
+ // src/commands/sessions/session-graph.ts
10825
+ function buildSessionTree(sessions) {
10826
+ const byId = new Map;
10827
+ const childrenByParent = new Map;
10828
+ for (const s of sessions) {
10829
+ byId.set(s.id, s);
10830
+ const pid = s.parentSessionId;
10831
+ if (pid !== null && pid !== undefined && pid !== "") {
10832
+ const bucket = childrenByParent.get(pid);
10833
+ if (bucket)
10834
+ bucket.push(s);
10835
+ else
10836
+ childrenByParent.set(pid, [s]);
10837
+ }
10838
+ }
10839
+ const cycleMembers = new Set;
10840
+ const consumed = new Set;
10841
+ function build(session, ancestorStack) {
10842
+ const node = { session, children: [] };
10843
+ const candidates = childrenByParent.get(session.id) ?? [];
10844
+ for (const candidate of candidates) {
10845
+ if (ancestorStack.has(candidate.id)) {
10846
+ cycleMembers.add(candidate.id);
10847
+ cycleMembers.add(session.id);
10848
+ continue;
10849
+ }
10850
+ if (consumed.has(candidate.id)) {
10851
+ continue;
10852
+ }
10853
+ consumed.add(candidate.id);
10854
+ const nextStack = new Set(ancestorStack);
10855
+ nextStack.add(session.id);
10856
+ const child = build(candidate, nextStack);
10857
+ node.children.push(child);
10858
+ }
10859
+ return node;
10860
+ }
10861
+ const roots = [];
10862
+ const orphans = [];
10863
+ for (const s of sessions) {
10864
+ const parentId = s.parentSessionId;
10865
+ const hasParentId = parentId !== null && parentId !== undefined && parentId !== "";
10866
+ if (!hasParentId) {
10867
+ if (consumed.has(s.id))
10868
+ continue;
10869
+ consumed.add(s.id);
10870
+ const node = build(s, new Set([s.id]));
10871
+ roots.push(node);
10872
+ } else if (!byId.has(parentId)) {
10873
+ orphans.push(s);
10874
+ }
10875
+ }
10876
+ if (consumed.size + orphans.length < sessions.length) {
10877
+ for (const s of sessions) {
10878
+ if (consumed.has(s.id))
10879
+ continue;
10880
+ if (orphans.includes(s))
10881
+ continue;
10882
+ const visited = new Set;
10883
+ let cur = s;
10884
+ while (cur) {
10885
+ if (visited.has(cur.id)) {
10886
+ for (const v of visited)
10887
+ cycleMembers.add(v);
10888
+ cycleMembers.add(s.id);
10889
+ break;
10890
+ }
10891
+ visited.add(cur.id);
10892
+ const pid = cur.parentSessionId;
10893
+ if (pid === null || pid === undefined || pid === "")
10894
+ break;
10895
+ cur = byId.get(pid);
10896
+ }
10897
+ consumed.add(s.id);
10898
+ const node = build(s, new Set([s.id]));
10899
+ roots.push(node);
10900
+ }
10901
+ }
10902
+ return { roots, orphans, cycles: cycleMembers };
10903
+ }
10904
+ var TREE_BRANCH = "├── ";
10905
+ var TREE_LAST = "└── ";
10906
+ var TREE_VERTICAL = "│ ";
10907
+ var TREE_EMPTY = " ";
10908
+ function renderSessionTree(tree, options = {}) {
10909
+ if (tree.roots.length === 0 && tree.orphans.length === 0) {
10910
+ return "No sessions.";
10911
+ }
10912
+ const lines = ["Session Tree"];
10913
+ for (let i = 0;i < tree.roots.length; i++) {
10914
+ const isLast = i === tree.roots.length - 1 && tree.orphans.length === 0;
10915
+ renderNode(tree.roots[i], "", isLast, lines, tree.cycles, options);
10916
+ }
10917
+ if (tree.orphans.length > 0) {
10918
+ for (let i = 0;i < tree.orphans.length; i++) {
10919
+ const s = tree.orphans[i];
10920
+ const isLast = i === tree.orphans.length - 1;
10921
+ const branch = isLast ? TREE_LAST : TREE_BRANCH;
10922
+ lines.push(`${branch}${formatNodeLabel(s, true, false, options)}`);
10923
+ }
10924
+ }
10925
+ return lines.join(`
10926
+ `);
10927
+ }
10928
+ function renderNode(node, prefix, isLast, lines, cycles, options) {
10929
+ const branch = isLast ? TREE_LAST : TREE_BRANCH;
10930
+ const isCycle = cycles.has(node.session.id);
10931
+ lines.push(`${prefix}${branch}${formatNodeLabel(node.session, false, isCycle, options)}`);
10932
+ const childPrefix = prefix + (isLast ? TREE_EMPTY : TREE_VERTICAL);
10933
+ for (let i = 0;i < node.children.length; i++) {
10934
+ const isChildLast = i === node.children.length - 1;
10935
+ renderNode(node.children[i], childPrefix, isChildLast, lines, cycles, options);
10936
+ }
10937
+ }
10938
+ function formatNodeLabel(session, isOrphan, isCycle = false, options = {}) {
10939
+ const idStr = options.useShortId ? shortSessionId(session.id) : session.id;
10940
+ const sourceLabel = inferSourceLabel(session);
10941
+ const status = inferStatus(session);
10942
+ const created = new Date(session.createdAt).toISOString().slice(0, 16).replace("T", " ");
10943
+ const parts = [idStr, sourceLabel];
10944
+ if (status)
10945
+ parts.push(`(${status})`);
10946
+ parts.push(created);
10947
+ let label = parts.join(" ");
10948
+ if (isOrphan)
10949
+ label = `[orphan] ${label}`;
10950
+ if (isCycle)
10951
+ label = `[cycle] ${label}`;
10952
+ return label;
10953
+ }
10954
+ function shortSessionId(id) {
10955
+ const underscoreIdx = id.indexOf("_");
10956
+ const stripped = underscoreIdx > 0 && underscoreIdx < id.length - 8 ? id.slice(underscoreIdx + 1) : id;
10957
+ return stripped.length > 8 ? stripped.slice(0, 8) : stripped;
10958
+ }
10959
+ function inferSourceLabel(session) {
10960
+ const meta = session.metadata;
10961
+ const type = meta?.type;
10962
+ if (type === "workflow") {
10963
+ const name = meta?.workflowName;
10964
+ return name ? `workflow/${name}` : "workflow";
10965
+ }
10966
+ if (type === "agent")
10967
+ return "agent";
10968
+ if (type === "subagent" || type === "sub-agent")
10969
+ return "[subagent]";
10970
+ return "chat";
10971
+ }
10972
+ function inferStatus(session) {
10973
+ const meta = session.metadata;
10974
+ const status = meta?.status;
10975
+ if (typeof status === "string" && status.length > 0)
10976
+ return status;
10977
+ return null;
10978
+ }
10979
+
10980
+ // src/commands/sessions/list.ts
10812
10981
  var ListCommand = {
10813
10982
  command: "list [options]",
10814
10983
  aliases: ["ls"],
10815
10984
  describe: "列出所有会话",
10816
- builder: (yargs) => yargs.option("limit", { alias: "n", type: "number", default: 20 }).option("offset", { type: "number", default: 0 }).option("sort", { type: "string", default: "updatedAt" }).option("order", { type: "string", default: "desc" }).option("json", { alias: "j", type: "boolean", default: false }).option("quiet", { alias: "q", type: "boolean", hidden: true }).option("id", { alias: "i", type: "boolean", default: false, description: "显示 Session ID" }).option("type", { alias: "t", type: "string", description: "按 session 类型过滤 (如 workflow)" }).option("status", { alias: "s", type: "string", description: "按状态过滤 (如 running, paused)" }),
10985
+ builder: (yargs) => yargs.option("limit", { alias: "n", type: "number", default: 20 }).option("offset", { type: "number", default: 0 }).option("sort", { type: "string", default: "updatedAt" }).option("order", { type: "string", default: "desc" }).option("json", { alias: "j", type: "boolean", default: false }).option("quiet", { alias: "q", type: "boolean", hidden: true }).option("id", { alias: "i", type: "boolean", default: false, description: "显示 Session ID" }).option("type", { alias: "t", type: "string", description: "按 session 类型过滤 (如 workflow)" }).option("status", { alias: "s", type: "string", description: "按状态过滤 (如 running, paused)" }).option("graph", { alias: "g", type: "boolean", default: false, description: "以层次化树形结构展示 session 父子关系" }).option("short-id", { type: "boolean", default: false, description: "[graph] 用 8 字符截断 id 显示(默认显示完整 sessionId)" }),
10817
10986
  async handler(args) {
10818
10987
  const isQuiet = args.quiet === true;
10819
10988
  if (isQuiet) {
@@ -10854,6 +11023,11 @@ var ListCommand = {
10854
11023
  const sessions = await sessionComponent.list(listOptions);
10855
11024
  const totalCount = await sessionComponent.getCount();
10856
11025
  const activeSessionId = sessionComponent.getActiveSessionId();
11026
+ if (args.graph) {
11027
+ const tree = buildSessionTree(sessions);
11028
+ output.log(renderSessionTree(tree, { useShortId: args.shortId === true }));
11029
+ return;
11030
+ }
10857
11031
  if (args.json) {
10858
11032
  output.json({
10859
11033
  total: sessions.length,
@@ -10868,6 +11042,8 @@ var ListCommand = {
10868
11042
  type: workflowMeta?.type || "chat",
10869
11043
  status: workflowMeta?.status,
10870
11044
  workflowName: workflowMeta?.workflowName,
11045
+ parentSessionId: s.parentSessionId ?? null,
11046
+ parentID: s.parentID ?? null,
10871
11047
  hasCheckpoint: !!s.metadata?.checkpoints?.checkpoints?.length,
10872
11048
  lastCheckpointAt: s.metadata?.checkpoints?.latestCheckpointId,
10873
11049
  createdAt: new Date(s.createdAt).toISOString(),
@@ -10885,6 +11061,7 @@ var ListCommand = {
10885
11061
  chalk6.bold("#"),
10886
11062
  chalk6.bold("Title"),
10887
11063
  chalk6.bold("ID"),
11064
+ chalk6.bold("Parent"),
10888
11065
  hasTypeFilter || hasStatusFilter ? chalk6.bold("Status") : null,
10889
11066
  chalk6.bold("Msgs"),
10890
11067
  chalk6.bold("CP")
@@ -10894,8 +11071,9 @@ var ListCommand = {
10894
11071
  const hasCp = (s.metadata?.checkpoints?.checkpoints?.length ?? 0) > 0;
10895
11072
  const title = s.title.length > 20 ? s.title.slice(0, 17) + "..." : s.title;
10896
11073
  const idStr = s.id;
11074
+ const useShortId = args.shortId === true;
11075
+ const parentStr = s.parentSessionId ? chalk6.gray(useShortId ? shortSessionId(s.parentSessionId) : s.parentSessionId) : chalk6.gray("-");
10897
11076
  const workflowMeta = s.metadata?.type === "workflow" ? s.metadata : null;
10898
- const typeStr = workflowMeta?.type || "";
10899
11077
  const statusStr = workflowMeta?.status || "";
10900
11078
  let statusDisplay = "";
10901
11079
  if (hasTypeFilter || hasStatusFilter) {
@@ -10906,7 +11084,8 @@ var ListCommand = {
10906
11084
  const cells = [
10907
11085
  marker + " " + (args.offset + i + 1),
10908
11086
  title,
10909
- chalk6.gray(idStr)
11087
+ chalk6.gray(idStr),
11088
+ parentStr
10910
11089
  ];
10911
11090
  if (hasTypeFilter || hasStatusFilter) {
10912
11091
  cells.push(statusDisplay || chalk6.gray("-"));
@@ -19309,6 +19488,7 @@ import fs5 from "fs";
19309
19488
  import path8 from "path";
19310
19489
  import { createRunWorkflowTool } from "@ai-setting/roy-agent-core/env/workflow/tools";
19311
19490
  import { getTracerProvider as getTracerProvider4, propagation, wrapFunction } from "@ai-setting/roy-agent-core";
19491
+ import { isValidSessionId } from "@ai-setting/roy-agent-core/env/session";
19312
19492
  var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
19313
19493
  const output = new OutputService2;
19314
19494
  const envService = new EnvironmentService(output);
@@ -19380,6 +19560,14 @@ var runWorkflow = wrapFunction(async function runWorkflowImpl(args) {
19380
19560
  parallelLimit: args.parallelLimit,
19381
19561
  timeout: args.timeout
19382
19562
  };
19563
+ const rawEnvParentId = process.env["ROY_PARENT_SESSION_ID"];
19564
+ if (typeof rawEnvParentId === "string" && rawEnvParentId.length > 0) {
19565
+ if (isValidSessionId(rawEnvParentId)) {
19566
+ runOptions.parentSessionId = rawEnvParentId;
19567
+ } else {
19568
+ output.warn(`Ignoring malformed ROY_PARENT_SESSION_ID env value (must match /^[A-Za-z0-9_-]{8,128}$/)`);
19569
+ }
19570
+ }
19383
19571
  if (args.session) {
19384
19572
  const sessionId = args.session;
19385
19573
  output.log(chalk69.blue(`\uD83D\uDD04 Resuming workflow from session: ${sessionId}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-setting/roy-agent-cli",
3
- "version": "1.5.111",
3
+ "version": "1.5.113",
4
4
  "type": "module",
5
5
  "description": "CLI for roy-agent - Non-interactive command execution",
6
6
  "main": "./dist/index.js",