@ricsam/r5dctl 0.0.27 → 0.0.29

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
@@ -63,6 +63,10 @@ r5dctl -s <session-id> conversation --raw # raw JSON message/tool p
63
63
  r5dctl -s <session-id> conversation --tools # include provider-shaped tool definitions
64
64
  r5dctl -s <session-id> conversation --system # include system prompt messages
65
65
  r5dctl -s <session-id> conversation --raw --tools --system # exact raw agent request transcript
66
+ r5dctl conversation overview <session-id> # dialogue/thinking with tool work omitted
67
+ r5dctl conversation inspect-work <session-id> <work-id> # compact call list for one omitted turn
68
+ r5dctl conversation inspect-work <session-id> <work-id> --summary
69
+ r5dctl conversation inspect-work <session-id> <work-id> --full
66
70
  r5dctl -s <session-id> prompt --mode plan --model max "..."
67
71
  r5dctl -s <session-id> answer-questions -a1 "Recipe Collection" -a2 "Both Manual & AI"
68
72
  r5dctl -s <session-id> apply-required-envs -e KEY=value
@@ -86,6 +90,8 @@ Conversation output is human-readable by default and excludes both the system pr
86
90
 
87
91
  When available, conversation rendering uses the newest complete persisted model-request snapshot on the active conversation branch, so its mode, tier, model, thinking mode, tools, and messages reflect the request that actually ran. Legacy or empty sessions without snapshots fall back to reconstruction from the latest conversation context.
88
92
 
93
+ `conversation overview` is a deterministic active-branch projection for continuing work in another session. It keeps user messages, injected context, assistant thinking/commentary/final responses, and user decisions, while replacing each turn's tool batches with a stable work ID and numbered call ranges. Use `conversation inspect-work` with that session and work ID to inspect the omitted calls. Inspection is compact by default; `--summary` adds bounded targets/outcomes and `--full` renders persisted inputs and results with the normal tool renderers. The explicit `--compact`, `--summary`, and `--full` flags are mutually exclusive. Compact and summary output are designed to be narrowed with `grep`, `head`, `tail`, `sed`, or `cat -n`.
94
+
89
95
  Project mode is derived from the persisted `backwardsCompatible` project setting:
90
96
 
91
97
  - `greenfield`: agent can make breaking/reset-style changes
package/dist/cjs/cli.cjs CHANGED
@@ -34,6 +34,7 @@ __export(cli_exports, {
34
34
  main: () => main,
35
35
  parseAnswerFlags: () => parseAnswerFlags,
36
36
  parseConversationRenderArgs: () => parseConversationRenderArgs,
37
+ parseConversationWorkDetailArgs: () => parseConversationWorkDetailArgs,
37
38
  parseEnvFlags: () => parseEnvFlags,
38
39
  parseGlobalArgs: () => parseGlobalArgs,
39
40
  parsePromptArgs: () => parsePromptArgs,
@@ -41,7 +42,9 @@ __export(cli_exports, {
41
42
  parseSetEnvArgs: () => parseSetEnvArgs,
42
43
  parseShellArgs: () => parseShellArgs,
43
44
  readDotenvFile: () => readDotenvFile,
45
+ renderConversationOverviewResponse: () => renderConversationOverviewResponse,
44
46
  renderConversationResponse: () => renderConversationResponse,
47
+ renderConversationWorkResponse: () => renderConversationWorkResponse,
45
48
  renderProcessList: () => renderProcessList,
46
49
  resolveCommandExecution: () => resolveCommandExecution,
47
50
  runR5dctlCli: () => runR5dctlCli,
@@ -163,6 +166,16 @@ const SHARED_HELP_ENTRIES = [
163
166
  usage: "-s <session-id> conversation [--raw] [--tools] [--system]",
164
167
  description: "Read the agent request transcript in human-readable form."
165
168
  },
169
+ {
170
+ section: "sessions",
171
+ usage: "conversation overview <session-id>",
172
+ description: "Read dialogue and thinking while replacing tool work with inspectable ranges."
173
+ },
174
+ {
175
+ section: "sessions",
176
+ usage: "conversation inspect-work <session-id> <work-id> [--compact|--summary|--full]",
177
+ description: "Inspect one turn's omitted tool work at the selected detail."
178
+ },
166
179
  {
167
180
  section: "sessions",
168
181
  usage: '-s <session-id> prompt --mode <mode> --model <tier> "<message>"',
@@ -316,10 +329,12 @@ function renderCliOnlyCommandHelp(entry) {
316
329
  `;
317
330
  }
318
331
  function renderSharedCommandHelp(pathSegments) {
319
- const entry = SHARED_HELP_ENTRIES.find((candidate) => {
320
- const usageSegments = candidate.usage.split(" ").map((segment) => segment.replace(/^\[/, "").replace(/\]$/, "")).filter((segment) => !segment.startsWith("-") && !segment.startsWith("<") && !segment.startsWith("["));
321
- return usageSegments.length <= pathSegments.length && usageSegments.every((segment, index) => segment === pathSegments[index]);
322
- });
332
+ const entry = SHARED_HELP_ENTRIES.map((candidate) => ({
333
+ candidate,
334
+ usageSegments: candidate.usage.split(" ").map((segment) => segment.replace(/^\[/, "").replace(/\]$/, "")).filter((segment) => !segment.startsWith("-") && !segment.startsWith("<") && !segment.startsWith("["))
335
+ })).filter(
336
+ ({ usageSegments }) => usageSegments.length <= pathSegments.length && usageSegments.every((segment, index) => segment === pathSegments[index])
337
+ ).sort((left, right) => right.usageSegments.length - left.usageSegments.length)[0]?.candidate;
323
338
  if (!entry) {
324
339
  return void 0;
325
340
  }
@@ -1206,6 +1221,30 @@ function renderConversationResponse(read) {
1206
1221
  return read.agentText.endsWith("\n") ? read.agentText : `${read.agentText}
1207
1222
  `;
1208
1223
  }
1224
+ function parseConversationWorkDetailArgs(args) {
1225
+ let detail = "compact";
1226
+ let selected = false;
1227
+ for (const arg of args) {
1228
+ const candidate = arg === "--compact" ? "compact" : arg === "--summary" ? "summary" : arg === "--full" ? "full" : void 0;
1229
+ if (!candidate) {
1230
+ throw new Error(`Unknown inspect-work argument: ${arg}`);
1231
+ }
1232
+ if (selected) {
1233
+ throw new Error("Use only one of --compact, --summary, or --full");
1234
+ }
1235
+ detail = candidate;
1236
+ selected = true;
1237
+ }
1238
+ return detail;
1239
+ }
1240
+ function renderConversationOverviewResponse(read) {
1241
+ return read.overviewText.endsWith("\n") ? read.overviewText : `${read.overviewText}
1242
+ `;
1243
+ }
1244
+ function renderConversationWorkResponse(read) {
1245
+ return read.workText.endsWith("\n") ? read.workText : `${read.workText}
1246
+ `;
1247
+ }
1209
1248
  async function executeR5dctlCommand(client, json, args) {
1210
1249
  const write = (data, human) => writeDataOutput(json, data, human);
1211
1250
  const [first, second, third] = args;
@@ -1394,6 +1433,22 @@ ${result.message}
1394
1433
  write(result, "Session deleted.\n");
1395
1434
  return;
1396
1435
  }
1436
+ if (first === "conversation" && second === "overview") {
1437
+ if (args.length > 3) {
1438
+ throw new Error(`Unexpected conversation overview argument: ${args[3]}`);
1439
+ }
1440
+ const read = await client.sessions.conversationOverview(requireValue(args[2], "Missing session id"));
1441
+ write(read, renderConversationOverviewResponse(read));
1442
+ return;
1443
+ }
1444
+ if (first === "conversation" && second === "inspect-work") {
1445
+ const sessionId = requireValue(args[2], "Missing session id");
1446
+ const workId = requireValue(args[3], "Missing work id");
1447
+ const detail = parseConversationWorkDetailArgs(args.slice(4));
1448
+ const read = await client.sessions.inspectConversationWork(sessionId, workId, { detail });
1449
+ write(read, renderConversationWorkResponse(read));
1450
+ return;
1451
+ }
1397
1452
  if (first === "sessions" && second === "conversation" || first === "conversation") {
1398
1453
  const offset = first === "conversation" ? 1 : 2;
1399
1454
  const renderOptions = parseConversationRenderArgs(args.slice(offset + 1));
@@ -1716,6 +1771,33 @@ function resolveCommandExecution(options, rest) {
1716
1771
  throw new Error("Unknown delete command");
1717
1772
  }
1718
1773
  if (command === "conversation") {
1774
+ const subcommand = commandArgs[0];
1775
+ if (subcommand === "overview") {
1776
+ const sessionId2 = options.session ?? commandArgs[1];
1777
+ if (!sessionId2) {
1778
+ throw new Error("Session id is required for `conversation overview`");
1779
+ }
1780
+ const remainingArgs = options.session ? commandArgs.slice(1) : commandArgs.slice(2);
1781
+ return {
1782
+ kind: "plugin",
1783
+ pluginArgs: ["conversation", "overview", sessionId2, ...remainingArgs]
1784
+ };
1785
+ }
1786
+ if (subcommand === "inspect-work") {
1787
+ const sessionId2 = options.session ?? commandArgs[1];
1788
+ if (!sessionId2) {
1789
+ throw new Error("Session id is required for `conversation inspect-work`");
1790
+ }
1791
+ const workId = options.session ? commandArgs[1] : commandArgs[2];
1792
+ if (!workId) {
1793
+ throw new Error("Work id is required for `conversation inspect-work`");
1794
+ }
1795
+ const remainingArgs = options.session ? commandArgs.slice(2) : commandArgs.slice(3);
1796
+ return {
1797
+ kind: "plugin",
1798
+ pluginArgs: ["conversation", "inspect-work", sessionId2, workId, ...remainingArgs]
1799
+ };
1800
+ }
1719
1801
  const sessionId = options.session;
1720
1802
  if (!sessionId) {
1721
1803
  throw new Error("--session/-s is required for `conversation`");
@@ -1938,6 +2020,7 @@ async function main(argv = process.argv.slice(2)) {
1938
2020
  main,
1939
2021
  parseAnswerFlags,
1940
2022
  parseConversationRenderArgs,
2023
+ parseConversationWorkDetailArgs,
1941
2024
  parseEnvFlags,
1942
2025
  parseGlobalArgs,
1943
2026
  parsePromptArgs,
@@ -1945,7 +2028,9 @@ async function main(argv = process.argv.slice(2)) {
1945
2028
  parseSetEnvArgs,
1946
2029
  parseShellArgs,
1947
2030
  readDotenvFile,
2031
+ renderConversationOverviewResponse,
1948
2032
  renderConversationResponse,
2033
+ renderConversationWorkResponse,
1949
2034
  renderProcessList,
1950
2035
  resolveCommandExecution,
1951
2036
  runR5dctlCli,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "type": "commonjs"
5
5
  }
package/dist/mjs/cli.mjs CHANGED
@@ -116,6 +116,16 @@ const SHARED_HELP_ENTRIES = [
116
116
  usage: "-s <session-id> conversation [--raw] [--tools] [--system]",
117
117
  description: "Read the agent request transcript in human-readable form."
118
118
  },
119
+ {
120
+ section: "sessions",
121
+ usage: "conversation overview <session-id>",
122
+ description: "Read dialogue and thinking while replacing tool work with inspectable ranges."
123
+ },
124
+ {
125
+ section: "sessions",
126
+ usage: "conversation inspect-work <session-id> <work-id> [--compact|--summary|--full]",
127
+ description: "Inspect one turn's omitted tool work at the selected detail."
128
+ },
119
129
  {
120
130
  section: "sessions",
121
131
  usage: '-s <session-id> prompt --mode <mode> --model <tier> "<message>"',
@@ -269,10 +279,12 @@ function renderCliOnlyCommandHelp(entry) {
269
279
  `;
270
280
  }
271
281
  function renderSharedCommandHelp(pathSegments) {
272
- const entry = SHARED_HELP_ENTRIES.find((candidate) => {
273
- const usageSegments = candidate.usage.split(" ").map((segment) => segment.replace(/^\[/, "").replace(/\]$/, "")).filter((segment) => !segment.startsWith("-") && !segment.startsWith("<") && !segment.startsWith("["));
274
- return usageSegments.length <= pathSegments.length && usageSegments.every((segment, index) => segment === pathSegments[index]);
275
- });
282
+ const entry = SHARED_HELP_ENTRIES.map((candidate) => ({
283
+ candidate,
284
+ usageSegments: candidate.usage.split(" ").map((segment) => segment.replace(/^\[/, "").replace(/\]$/, "")).filter((segment) => !segment.startsWith("-") && !segment.startsWith("<") && !segment.startsWith("["))
285
+ })).filter(
286
+ ({ usageSegments }) => usageSegments.length <= pathSegments.length && usageSegments.every((segment, index) => segment === pathSegments[index])
287
+ ).sort((left, right) => right.usageSegments.length - left.usageSegments.length)[0]?.candidate;
276
288
  if (!entry) {
277
289
  return void 0;
278
290
  }
@@ -1159,6 +1171,30 @@ function renderConversationResponse(read) {
1159
1171
  return read.agentText.endsWith("\n") ? read.agentText : `${read.agentText}
1160
1172
  `;
1161
1173
  }
1174
+ function parseConversationWorkDetailArgs(args) {
1175
+ let detail = "compact";
1176
+ let selected = false;
1177
+ for (const arg of args) {
1178
+ const candidate = arg === "--compact" ? "compact" : arg === "--summary" ? "summary" : arg === "--full" ? "full" : void 0;
1179
+ if (!candidate) {
1180
+ throw new Error(`Unknown inspect-work argument: ${arg}`);
1181
+ }
1182
+ if (selected) {
1183
+ throw new Error("Use only one of --compact, --summary, or --full");
1184
+ }
1185
+ detail = candidate;
1186
+ selected = true;
1187
+ }
1188
+ return detail;
1189
+ }
1190
+ function renderConversationOverviewResponse(read) {
1191
+ return read.overviewText.endsWith("\n") ? read.overviewText : `${read.overviewText}
1192
+ `;
1193
+ }
1194
+ function renderConversationWorkResponse(read) {
1195
+ return read.workText.endsWith("\n") ? read.workText : `${read.workText}
1196
+ `;
1197
+ }
1162
1198
  async function executeR5dctlCommand(client, json, args) {
1163
1199
  const write = (data, human) => writeDataOutput(json, data, human);
1164
1200
  const [first, second, third] = args;
@@ -1347,6 +1383,22 @@ ${result.message}
1347
1383
  write(result, "Session deleted.\n");
1348
1384
  return;
1349
1385
  }
1386
+ if (first === "conversation" && second === "overview") {
1387
+ if (args.length > 3) {
1388
+ throw new Error(`Unexpected conversation overview argument: ${args[3]}`);
1389
+ }
1390
+ const read = await client.sessions.conversationOverview(requireValue(args[2], "Missing session id"));
1391
+ write(read, renderConversationOverviewResponse(read));
1392
+ return;
1393
+ }
1394
+ if (first === "conversation" && second === "inspect-work") {
1395
+ const sessionId = requireValue(args[2], "Missing session id");
1396
+ const workId = requireValue(args[3], "Missing work id");
1397
+ const detail = parseConversationWorkDetailArgs(args.slice(4));
1398
+ const read = await client.sessions.inspectConversationWork(sessionId, workId, { detail });
1399
+ write(read, renderConversationWorkResponse(read));
1400
+ return;
1401
+ }
1350
1402
  if (first === "sessions" && second === "conversation" || first === "conversation") {
1351
1403
  const offset = first === "conversation" ? 1 : 2;
1352
1404
  const renderOptions = parseConversationRenderArgs(args.slice(offset + 1));
@@ -1669,6 +1721,33 @@ function resolveCommandExecution(options, rest) {
1669
1721
  throw new Error("Unknown delete command");
1670
1722
  }
1671
1723
  if (command === "conversation") {
1724
+ const subcommand = commandArgs[0];
1725
+ if (subcommand === "overview") {
1726
+ const sessionId2 = options.session ?? commandArgs[1];
1727
+ if (!sessionId2) {
1728
+ throw new Error("Session id is required for `conversation overview`");
1729
+ }
1730
+ const remainingArgs = options.session ? commandArgs.slice(1) : commandArgs.slice(2);
1731
+ return {
1732
+ kind: "plugin",
1733
+ pluginArgs: ["conversation", "overview", sessionId2, ...remainingArgs]
1734
+ };
1735
+ }
1736
+ if (subcommand === "inspect-work") {
1737
+ const sessionId2 = options.session ?? commandArgs[1];
1738
+ if (!sessionId2) {
1739
+ throw new Error("Session id is required for `conversation inspect-work`");
1740
+ }
1741
+ const workId = options.session ? commandArgs[1] : commandArgs[2];
1742
+ if (!workId) {
1743
+ throw new Error("Work id is required for `conversation inspect-work`");
1744
+ }
1745
+ const remainingArgs = options.session ? commandArgs.slice(2) : commandArgs.slice(3);
1746
+ return {
1747
+ kind: "plugin",
1748
+ pluginArgs: ["conversation", "inspect-work", sessionId2, workId, ...remainingArgs]
1749
+ };
1750
+ }
1672
1751
  const sessionId = options.session;
1673
1752
  if (!sessionId) {
1674
1753
  throw new Error("--session/-s is required for `conversation`");
@@ -1890,6 +1969,7 @@ export {
1890
1969
  main,
1891
1970
  parseAnswerFlags,
1892
1971
  parseConversationRenderArgs,
1972
+ parseConversationWorkDetailArgs,
1893
1973
  parseEnvFlags,
1894
1974
  parseGlobalArgs,
1895
1975
  parsePromptArgs,
@@ -1897,7 +1977,9 @@ export {
1897
1977
  parseSetEnvArgs,
1898
1978
  parseShellArgs,
1899
1979
  readDotenvFile,
1980
+ renderConversationOverviewResponse,
1900
1981
  renderConversationResponse,
1982
+ renderConversationWorkResponse,
1901
1983
  renderProcessList,
1902
1984
  resolveCommandExecution,
1903
1985
  runR5dctlCli,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "type": "module"
5
5
  }
@@ -1,4 +1,4 @@
1
- import { type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlEnvData, type R5dctlProcessListInput, type R5dctlProcessRun, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
1
+ import { type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlConversationOverviewResponse, type R5dctlConversationWorkDetail, type R5dctlConversationWorkResponse, type R5dctlEnvData, type R5dctlProcessListInput, type R5dctlProcessRun, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
2
2
  export type GlobalOptions = {
3
3
  baseUrl?: string;
4
4
  json: boolean;
@@ -71,6 +71,9 @@ export type EnvSummaryData = Record<string, {
71
71
  export declare function summarizeEnvData(data: R5dctlEnvData): EnvSummaryData;
72
72
  export declare function parseConversationRenderArgs(args: string[]): ConversationRenderOptions;
73
73
  export declare function renderConversationResponse(read: R5dctlConversationResponse): string;
74
+ export declare function parseConversationWorkDetailArgs(args: string[]): R5dctlConversationWorkDetail;
75
+ export declare function renderConversationOverviewResponse(read: R5dctlConversationOverviewResponse): string;
76
+ export declare function renderConversationWorkResponse(read: R5dctlConversationWorkResponse): string;
74
77
  export declare function resolveCommandExecution(options: GlobalOptions, rest: string[]): CommandExecutionPlan;
75
78
  export declare function runR5dctlCli(argv: string[]): Promise<number>;
76
79
  export declare function main(argv?: string[]): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "type": "module",
5
5
  "main": "./dist/cjs/cli.cjs",
6
6
  "module": "./dist/mjs/cli.mjs",
@@ -26,7 +26,7 @@
26
26
  "r5dctl": "dist/cjs/main.cjs"
27
27
  },
28
28
  "dependencies": {
29
- "@ricsam/r5d-api": "^0.0.27",
29
+ "@ricsam/r5d-api": "^0.0.29",
30
30
  "dotenv": "^17",
31
31
  "ws": "^8.18.3"
32
32
  },