@neta-art/cohub-cli 6.4.0 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -133,8 +133,14 @@ List recent turns across all visible Sessions in a Space:
133
133
  cohub -s <spaceId> spaces turns ls
134
134
  cohub -s <spaceId> spaces turns ls --author others --limit 50 --json
135
135
  cohub -s <spaceId> spaces turns ls --session <sessionId>
136
+ cohub -s <spaceId> spaces turns intermediate <sessionId> <turnId>
137
+ cohub -s <spaceId> spaces turns intermediate <sessionId> <turnId> --json
136
138
  ```
137
139
 
140
+ When `--session` is provided, the CLI uses the same full turn endpoint as the
141
+ Web session view. Intermediate messages are read from the turn's CDN archive;
142
+ `--json` returns the archive without reducing its content blocks.
143
+
138
144
  Use `pageInfo.nextCursor` with `--cursor` to load older pages. Use a previous
139
145
  `snapshotCursor` with `--after` and an explicit `--before` boundary to query
140
146
  newer turns:
@@ -1,4 +1,4 @@
1
- import type { SpaceTurnListItem, SpaceTurnListOptions, SpaceTurnsResponse } from "@neta-art/cohub";
1
+ import type { SpaceTurnListItem, SpaceTurnListOptions, SpaceTurnsResponse, SessionTurnRecord, TurnIntermediateMessagesFile } from "@neta-art/cohub";
2
2
  import type { Command } from "commander";
3
3
  import { type Row } from "../output.js";
4
4
  export type SpaceTurnListCliOptions = {
@@ -9,12 +9,30 @@ export type SpaceTurnListCliOptions = {
9
9
  limit?: string;
10
10
  session?: string;
11
11
  json?: boolean;
12
+ direction?: "older" | "newer";
12
13
  };
13
14
  type SpaceTurnsCommandClient = {
14
15
  space(spaceId: string): {
15
16
  turns: {
16
17
  list(options: SpaceTurnListOptions): Promise<SpaceTurnsResponse>;
17
18
  };
19
+ session(sessionId: string): {
20
+ turns: {
21
+ listPaginated(options?: {
22
+ cursor?: number;
23
+ limit?: number;
24
+ direction?: "older" | "newer";
25
+ }): Promise<{
26
+ session: unknown;
27
+ turns: SessionTurnRecord[];
28
+ hasMore: boolean;
29
+ nextCursor: number | undefined;
30
+ }>;
31
+ intermediate: {
32
+ get(turnId: string): Promise<TurnIntermediateMessagesFile | null>;
33
+ };
34
+ };
35
+ };
18
36
  };
19
37
  };
20
38
  export declare class InvalidSpaceTurnCliOptionsError extends Error {
@@ -22,6 +40,8 @@ export declare class InvalidSpaceTurnCliOptionsError extends Error {
22
40
  constructor(message: string, detail: string);
23
41
  }
24
42
  export declare function parseSpaceTurnListOptions(options: SpaceTurnListCliOptions): SpaceTurnListOptions;
43
+ export declare function parseSessionTurnCursor(value: string | undefined): number | undefined;
44
+ export declare function validateSpaceTurnListMode(options: SpaceTurnListCliOptions): void;
25
45
  export declare function toSpaceTurnRows(turns: SpaceTurnListItem[]): Row[];
26
46
  export declare function registerSpaceTurns(spacesCmd: Command, dependencies?: {
27
47
  createClient?: () => SpaceTurnsCommandClient;
@@ -48,6 +48,23 @@ export function parseSpaceTurnListOptions(options) {
48
48
  sessionId: options.session,
49
49
  };
50
50
  }
51
+ export function parseSessionTurnCursor(value) {
52
+ if (value === undefined)
53
+ return undefined;
54
+ const cursor = Number(value);
55
+ if (!Number.isSafeInteger(cursor) || cursor < 1) {
56
+ throw new InvalidSpaceTurnCliOptionsError("Invalid cursor", "Session cursor must be a positive turn sequence");
57
+ }
58
+ return cursor;
59
+ }
60
+ export function validateSpaceTurnListMode(options) {
61
+ if (!options.session && options.direction !== undefined) {
62
+ throw new InvalidSpaceTurnCliOptionsError("Invalid direction", "--direction only applies with --session");
63
+ }
64
+ if (options.session && (options.author || options.after || options.before)) {
65
+ throw new InvalidSpaceTurnCliOptionsError("Invalid session turn options", "--session uses the Session turns API; omit --author, --after, and --before");
66
+ }
67
+ }
51
68
  export function toSpaceTurnRows(turns) {
52
69
  return turns.map((turn) => ({
53
70
  createdAt: turn.createdAt,
@@ -71,13 +88,14 @@ export function registerSpaceTurns(spacesCmd, dependencies = {}) {
71
88
  turnsCmd
72
89
  .command("ls")
73
90
  .alias("list")
74
- .description("List recent turns across sessions")
75
- .option("--author <any|self|others>", "Filter turns by author")
76
- .option("--after <cursor>", "Only turns after a snapshot cursor")
77
- .option("--before <timestamp>", "Only turns at or before an ISO 8601 timestamp")
78
- .option("--cursor <cursor>", "Older-page cursor from a previous result")
79
- .option("--limit <n>", "Page size, from 1 to 100")
80
- .option("--session <id>", "Only turns from this session")
91
+ .description("List turns in the space, or full turns from one session")
92
+ .option("--author <any|self|others>", "Filter space turns by author")
93
+ .option("--after <cursor>", "Start after a previous snapshot cursor")
94
+ .option("--before <timestamp>", "End at an ISO 8601 timestamp")
95
+ .option("--cursor <cursor>", "Page cursor; with --session, use a turn sequence")
96
+ .option("--limit <n>", "Maximum turns per page, 1-100")
97
+ .option("--session <id>", "Use the full turn list for this session")
98
+ .option("--direction <older|newer>", "Session page direction; use with --session")
81
99
  .option("--json", "Output as JSON")
82
100
  .action(async (options) => {
83
101
  let query;
@@ -93,6 +111,45 @@ export function registerSpaceTurns(spacesCmd, dependencies = {}) {
93
111
  const spaceId = resolveSpace(spacesCmd);
94
112
  const client = dependencies.createClient?.() ?? createClient();
95
113
  try {
114
+ try {
115
+ validateSpaceTurnListMode(options);
116
+ }
117
+ catch (cause) {
118
+ if (cause instanceof InvalidSpaceTurnCliOptionsError)
119
+ return error(cause.message, cause.detail);
120
+ throw cause;
121
+ }
122
+ if (options.session) {
123
+ let sessionCursor;
124
+ try {
125
+ sessionCursor = parseSessionTurnCursor(options.cursor);
126
+ }
127
+ catch (cause) {
128
+ if (cause instanceof InvalidSpaceTurnCliOptionsError)
129
+ return error(cause.message, cause.detail);
130
+ throw cause;
131
+ }
132
+ const result = await client.space(spaceId).session(options.session).turns.listPaginated({
133
+ cursor: sessionCursor,
134
+ limit: query.limit,
135
+ direction: options.direction,
136
+ });
137
+ if (jsonRequested(options))
138
+ return outJson(result);
139
+ if (result.turns.length === 0)
140
+ return console.log(" No turns found");
141
+ table(result.turns, [
142
+ { key: "sequence", label: "Seq" },
143
+ { key: "id", label: "Turn ID" },
144
+ { key: "status", label: "Status" },
145
+ { key: "userText", label: "User" },
146
+ { key: "assistantText", label: "Assistant" },
147
+ { key: "updatedAt", label: "Updated" },
148
+ ]);
149
+ if (result.hasMore)
150
+ console.log(`\n More turns available - next cursor: ${result.nextCursor}`);
151
+ return;
152
+ }
96
153
  const result = await client.space(spaceId).turns.list(query);
97
154
  if (jsonRequested(options))
98
155
  return outJson(result);
@@ -117,5 +174,32 @@ export function registerSpaceTurns(spacesCmd, dependencies = {}) {
117
174
  handleHttp(cause);
118
175
  }
119
176
  });
177
+ turnsCmd
178
+ .command("intermediate <sessionId> <turnId>")
179
+ .description("Read persisted intermediate messages from the CDN archive")
180
+ .option("--json", "Output as JSON")
181
+ .action(async (sessionId, turnId, options) => {
182
+ const spaceId = resolveSpace(spacesCmd);
183
+ const client = dependencies.createClient?.() ?? createClient();
184
+ try {
185
+ const archive = await client.space(spaceId).session(sessionId).turns.intermediate.get(turnId);
186
+ if (jsonRequested(options))
187
+ return outJson(archive);
188
+ if (!archive)
189
+ return console.log(" No intermediate messages found");
190
+ console.log(`Turn ${archive.turnId}`);
191
+ console.log(` ${archive.summary.messageCount} intermediate messages · ${archive.summary.toolCallCount} tool calls`);
192
+ for (const [index, message] of archive.messages.entries()) {
193
+ console.log(`\n${index + 1}. ${message.role}${message.provider ? ` · ${message.provider}/${message.model ?? ""}` : ""}`);
194
+ if (message.text)
195
+ console.log(message.text);
196
+ if (message.toolCallsObjectKey)
197
+ console.log(" Tool calls: available");
198
+ }
199
+ }
200
+ catch (cause) {
201
+ handleHttp(cause);
202
+ }
203
+ });
120
204
  return turnsCmd;
121
205
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub-cli",
3
- "version": "6.4.0",
3
+ "version": "6.5.0",
4
4
  "description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -19,7 +19,7 @@
19
19
  "commander": "^15.0.0",
20
20
  "pixi.js": "^8.20.1",
21
21
  "sharp": "^0.35.4",
22
- "@neta-art/cohub": "8.7.0"
22
+ "@neta-art/cohub": "8.8.0"
23
23
  },
24
24
  "publishConfig": {
25
25
  "access": "public"