@ricsam/r5dctl 0.0.71 → 0.0.72

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
@@ -71,10 +71,12 @@ r5dctl -s <session-id> conversation --system # include system prompt m
71
71
  r5dctl -s <session-id> conversation --raw --tools --system # exact raw agent request transcript
72
72
  r5dctl -s <session-id> conversation -f # print current transcript, then follow new output (--watch also works)
73
73
  r5dctl conversation overview <session-id> # dialogue/thinking with tool work omitted
74
+ r5dctl conversation overview <session-id> --skeleton # user messages, decisions, and per-turn work markers only
74
75
  r5dctl conversation inspect-node <session-id> <node-id> # raw persisted node plus traversal metadata
75
76
  r5dctl conversation inspect-work <session-id> <work-id> # compact call list for one omitted turn
76
77
  r5dctl conversation inspect-work <session-id> <work-id> --summary
77
- r5dctl conversation inspect-work <session-id> <work-id> --full
78
+ r5dctl conversation inspect-work <session-id> <work-id> --full --calls 12-20
79
+ r5dctl conversation inspect-work <session-id> <work-id> --include-polls
78
80
  r5dctl conversation move-head <session-id> <node-id> # rewind or replay the transcript; files stay put
79
81
  r5dctl conversation fork <session-id> <node-id> # copy the branch up to a node into a new session
80
82
  r5dctl conversation fork <session-id> <node-id> --name "Retry with tests"
@@ -107,7 +109,7 @@ r5dctl k8s usage --window 7d
107
109
  r5dctl k8s usage --workload default/api --window 7d --json
108
110
  ```
109
111
 
110
- `session start` creates an ordinary agent-mode chat on an explicitly selected existing worktree, or creates a named worktree from an explicit `worktree:<branch>` source. It requires project, worker, model, and prompt and never infers them from the current shell. Starts and prompts return after durable enqueue while execution continues asynchronously. Task specialization belongs in the prompt; there are no predefined debug, explore, research, or test agents.
112
+ `session start` creates an ordinary agent-mode chat on an explicitly selected existing worktree, or creates a named worktree from an explicit `worktree:<branch>` source. It requires project, worker, model, and prompt and never infers them from the current shell. Starts and prompts return after durable enqueue while execution continues asynchronously. Task specialization belongs in the prompt; there are no predefined debug, explore, research, or test agents. `session stop` returns as soon as the agent run is stopped; the stopped worktree's workspace publication finishes asynchronously behind the response, and `merge` republishes at its own boundary before reading the worktree.
111
113
 
112
114
  Add `-f`/`--follow`/`--watch` to `session start` to attach after enqueue, or to `conversation` to print the current transcript and follow new output. Assistant text is written to stdout and lifecycle/tool progress to stderr; `--tools` includes tool calls and results. With global `--json`, follow mode emits one JSON event per line. Ctrl-C only detaches and never stops the session. The CLI reconnects transiently interrupted event streams and resynchronizes committed conversation revisions without repeating assistant text.
113
115
 
@@ -132,7 +134,11 @@ Conversation output is human-readable by default and excludes both the system pr
132
134
 
133
135
  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.
134
136
 
135
- `conversation overview` is a deterministic active-branch projection for recovering earlier work after a fresh-context boundary. 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. Adjacent tool batches with no visible content between them are coalesced into one range. 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`.
137
+ `conversation overview` is a deterministic active-branch projection for recovering earlier work after a fresh-context boundary. 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. Adjacent tool batches with no visible content between them are coalesced into one range. `--skeleton` drops thinking and commentary too, keeping only dialogue, questions/answers, terminal responses, and one work marker per turn the fastest first read of a long session. When the last turn is unfinished, both views end with a `[Turn in progress: ...]` footer naming the pending state and last node, so "still running" is distinguishable from "ended without a response".
138
+
139
+ 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. `--calls <n[-m]>` selects a server-side call range while keeping the original call numbers, so a `calls 83–90 omitted` marker in the overview can be inspected directly. Compact and summary output are designed to be narrowed with `grep`, `head`, `tail`, `sed`, or `cat -n`.
140
+
141
+ Persisted shell results are dispatch-time snapshots, so a long-running command's stored status can go stale. Rendering joins each unresolved run against the durable process-run store: summary rows gain `final_status=`/`final_exitCode=` next to the stale snapshot fields, `--full` appends a `## Final process outcomes` section with byte counts and output tails, and `shell_poll` calls whose run already finished are folded into one `[calls N–M folded: ...]` annotation carrying the final status. `--include-polls` restores the raw poll rows; call numbering never changes either way.
136
142
 
137
143
  `conversation inspect-node` reads one exact persisted conversation node as formatted JSON. Its header includes the previous node, every direct next node, the next node on the active branch, whether the selected node is active, and the containing `work_...` ID when one is available. This allows callers that start with only a copied chat node ID to traverse nearby nodes or zoom out with `conversation inspect-work`.
138
144
 
package/dist/cjs/cli.cjs CHANGED
@@ -47,8 +47,9 @@ __export(cli_exports, {
47
47
  parseAnswerFlags: () => parseAnswerFlags,
48
48
  parseAnswerQuestionsCommandArgs: () => parseAnswerQuestionsCommandArgs,
49
49
  parseConversationForkArgs: () => parseConversationForkArgs,
50
+ parseConversationInspectWorkArgs: () => parseConversationInspectWorkArgs,
51
+ parseConversationOverviewArgs: () => parseConversationOverviewArgs,
50
52
  parseConversationRenderArgs: () => parseConversationRenderArgs,
51
- parseConversationWorkDetailArgs: () => parseConversationWorkDetailArgs,
52
53
  parseEnvFlags: () => parseEnvFlags,
53
54
  parseEnvRequestResponseArgs: () => parseEnvRequestResponseArgs,
54
55
  parseGetEnvsArgs: () => parseGetEnvsArgs,
@@ -251,8 +252,8 @@ const SHARED_HELP_ENTRIES = [
251
252
  },
252
253
  {
253
254
  section: "sessions",
254
- usage: "conversation overview <session-id>",
255
- description: "Read dialogue and thinking while replacing tool work with inspectable ranges."
255
+ usage: "conversation overview <session-id> [--skeleton]",
256
+ description: "Read dialogue and thinking while replacing tool work with inspectable ranges; --skeleton keeps only dialogue, decisions, and per-turn work markers."
256
257
  },
257
258
  {
258
259
  section: "sessions",
@@ -261,8 +262,8 @@ const SHARED_HELP_ENTRIES = [
261
262
  },
262
263
  {
263
264
  section: "sessions",
264
- usage: "conversation inspect-work <session-id> <work-id> [--compact|--summary|--full]",
265
- description: "Inspect one turn's omitted tool work at the selected detail."
265
+ usage: "conversation inspect-work <session-id> <work-id> [--compact|--summary|--full] [--calls <n[-m]>] [--include-polls]",
266
+ description: "Inspect one turn's omitted tool work at the selected detail; finished shell polls are folded unless --include-polls."
266
267
  },
267
268
  {
268
269
  section: "sessions",
@@ -2422,21 +2423,57 @@ async function followR5dctlSession(client, sessionId, options) {
2422
2423
  }
2423
2424
  return 0;
2424
2425
  }
2425
- function parseConversationWorkDetailArgs(args) {
2426
+ function parseConversationInspectWorkArgs(args) {
2426
2427
  let detail = "compact";
2427
2428
  let selected = false;
2428
- for (const arg of args) {
2429
+ let calls;
2430
+ let includePolls = false;
2431
+ for (let index = 0; index < args.length; index += 1) {
2432
+ const arg = args[index];
2429
2433
  const candidate = arg === "--compact" ? "compact" : arg === "--summary" ? "summary" : arg === "--full" ? "full" : void 0;
2430
- if (!candidate) {
2431
- throw new Error(`Unknown inspect-work argument: ${arg}`);
2434
+ if (candidate) {
2435
+ if (selected) {
2436
+ throw new Error("Use only one of --compact, --summary, or --full");
2437
+ }
2438
+ detail = candidate;
2439
+ selected = true;
2440
+ continue;
2441
+ }
2442
+ if (arg === "--calls") {
2443
+ if (calls !== void 0) {
2444
+ throw new Error("Use --calls only once");
2445
+ }
2446
+ index += 1;
2447
+ const value = requireValue(args[index], "Missing value for --calls");
2448
+ if (!/^[0-9]+(-[0-9]+)?$/.test(value)) {
2449
+ throw new Error(`Invalid --calls range: ${value} (use N or N-M)`);
2450
+ }
2451
+ calls = value;
2452
+ continue;
2432
2453
  }
2433
- if (selected) {
2434
- throw new Error("Use only one of --compact, --summary, or --full");
2454
+ if (arg === "--include-polls") {
2455
+ if (includePolls) {
2456
+ throw new Error("Use --include-polls only once");
2457
+ }
2458
+ includePolls = true;
2459
+ continue;
2435
2460
  }
2436
- detail = candidate;
2437
- selected = true;
2461
+ throw new Error(`Unknown inspect-work argument: ${arg}`);
2438
2462
  }
2439
- return detail;
2463
+ return { detail, ...calls !== void 0 ? { calls } : {}, includePolls };
2464
+ }
2465
+ function parseConversationOverviewArgs(args) {
2466
+ let skeleton = false;
2467
+ for (const arg of args) {
2468
+ if (arg !== "--skeleton") {
2469
+ throw new Error(`Unknown conversation overview argument: ${arg}`);
2470
+ }
2471
+ if (skeleton) {
2472
+ throw new Error("Use --skeleton only once");
2473
+ }
2474
+ skeleton = true;
2475
+ }
2476
+ return { skeleton };
2440
2477
  }
2441
2478
  function parseConversationForkArgs(args) {
2442
2479
  let name;
@@ -2665,10 +2702,9 @@ Sessions: ${result.sessions.length}
2665
2702
  return;
2666
2703
  }
2667
2704
  if (first === "conversation" && second === "overview") {
2668
- if (args.length > 3) {
2669
- throw new Error(`Unexpected conversation overview argument: ${args[3]}`);
2670
- }
2671
- const read = await client.sessions.conversationOverview(requireValue(args[2], "Missing session id"));
2705
+ const sessionId = requireValue(args[2], "Missing session id");
2706
+ const { skeleton } = parseConversationOverviewArgs(args.slice(3));
2707
+ const read = await client.sessions.conversationOverview(sessionId, skeleton ? { view: "skeleton" } : {});
2672
2708
  write(read, renderConversationOverviewResponse(read));
2673
2709
  return;
2674
2710
  }
@@ -2703,8 +2739,12 @@ Sessions: ${result.sessions.length}
2703
2739
  if (first === "conversation" && second === "inspect-work") {
2704
2740
  const sessionId = requireValue(args[2], "Missing session id");
2705
2741
  const workId = requireValue(args[3], "Missing work id");
2706
- const detail = parseConversationWorkDetailArgs(args.slice(4));
2707
- const read = await client.sessions.inspectConversationWork(sessionId, workId, { detail });
2742
+ const options = parseConversationInspectWorkArgs(args.slice(4));
2743
+ const read = await client.sessions.inspectConversationWork(sessionId, workId, {
2744
+ detail: options.detail,
2745
+ ...options.calls !== void 0 ? { calls: options.calls } : {},
2746
+ ...options.includePolls ? { polls: "include" } : {}
2747
+ });
2708
2748
  write(read, renderConversationWorkResponse(read));
2709
2749
  return;
2710
2750
  }
@@ -3220,6 +3260,14 @@ async function runCommand(argv) {
3220
3260
  return 0;
3221
3261
  }
3222
3262
  if (execution.kind === "session-run") {
3263
+ if (!options.json) {
3264
+ if (execution.command.kind === "start") {
3265
+ process.stderr.write("Starting session (publishing the workspace and provisioning the worktree)...\n");
3266
+ } else if (execution.command.kind === "stop") {
3267
+ process.stderr.write(`Stopping session ${execution.command.sessionId}...
3268
+ `);
3269
+ }
3270
+ }
3223
3271
  const result = await dispatchSessionRunCommand(client, execution.command);
3224
3272
  if (execution.command.kind !== "start" || !execution.command.follow) {
3225
3273
  writeDataOutput(options.json, result.data, result.human);
@@ -3317,8 +3365,9 @@ async function main(argv = process.argv.slice(2)) {
3317
3365
  parseAnswerFlags,
3318
3366
  parseAnswerQuestionsCommandArgs,
3319
3367
  parseConversationForkArgs,
3368
+ parseConversationInspectWorkArgs,
3369
+ parseConversationOverviewArgs,
3320
3370
  parseConversationRenderArgs,
3321
- parseConversationWorkDetailArgs,
3322
3371
  parseEnvFlags,
3323
3372
  parseEnvRequestResponseArgs,
3324
3373
  parseGetEnvsArgs,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.71",
3
+ "version": "0.0.72",
4
4
  "type": "commonjs"
5
5
  }
package/dist/mjs/cli.mjs CHANGED
@@ -167,8 +167,8 @@ const SHARED_HELP_ENTRIES = [
167
167
  },
168
168
  {
169
169
  section: "sessions",
170
- usage: "conversation overview <session-id>",
171
- description: "Read dialogue and thinking while replacing tool work with inspectable ranges."
170
+ usage: "conversation overview <session-id> [--skeleton]",
171
+ description: "Read dialogue and thinking while replacing tool work with inspectable ranges; --skeleton keeps only dialogue, decisions, and per-turn work markers."
172
172
  },
173
173
  {
174
174
  section: "sessions",
@@ -177,8 +177,8 @@ const SHARED_HELP_ENTRIES = [
177
177
  },
178
178
  {
179
179
  section: "sessions",
180
- usage: "conversation inspect-work <session-id> <work-id> [--compact|--summary|--full]",
181
- description: "Inspect one turn's omitted tool work at the selected detail."
180
+ usage: "conversation inspect-work <session-id> <work-id> [--compact|--summary|--full] [--calls <n[-m]>] [--include-polls]",
181
+ description: "Inspect one turn's omitted tool work at the selected detail; finished shell polls are folded unless --include-polls."
182
182
  },
183
183
  {
184
184
  section: "sessions",
@@ -2338,21 +2338,57 @@ async function followR5dctlSession(client, sessionId, options) {
2338
2338
  }
2339
2339
  return 0;
2340
2340
  }
2341
- function parseConversationWorkDetailArgs(args) {
2341
+ function parseConversationInspectWorkArgs(args) {
2342
2342
  let detail = "compact";
2343
2343
  let selected = false;
2344
- for (const arg of args) {
2344
+ let calls;
2345
+ let includePolls = false;
2346
+ for (let index = 0; index < args.length; index += 1) {
2347
+ const arg = args[index];
2345
2348
  const candidate = arg === "--compact" ? "compact" : arg === "--summary" ? "summary" : arg === "--full" ? "full" : void 0;
2346
- if (!candidate) {
2347
- throw new Error(`Unknown inspect-work argument: ${arg}`);
2349
+ if (candidate) {
2350
+ if (selected) {
2351
+ throw new Error("Use only one of --compact, --summary, or --full");
2352
+ }
2353
+ detail = candidate;
2354
+ selected = true;
2355
+ continue;
2356
+ }
2357
+ if (arg === "--calls") {
2358
+ if (calls !== void 0) {
2359
+ throw new Error("Use --calls only once");
2360
+ }
2361
+ index += 1;
2362
+ const value = requireValue(args[index], "Missing value for --calls");
2363
+ if (!/^[0-9]+(-[0-9]+)?$/.test(value)) {
2364
+ throw new Error(`Invalid --calls range: ${value} (use N or N-M)`);
2365
+ }
2366
+ calls = value;
2367
+ continue;
2348
2368
  }
2349
- if (selected) {
2350
- throw new Error("Use only one of --compact, --summary, or --full");
2369
+ if (arg === "--include-polls") {
2370
+ if (includePolls) {
2371
+ throw new Error("Use --include-polls only once");
2372
+ }
2373
+ includePolls = true;
2374
+ continue;
2351
2375
  }
2352
- detail = candidate;
2353
- selected = true;
2376
+ throw new Error(`Unknown inspect-work argument: ${arg}`);
2354
2377
  }
2355
- return detail;
2378
+ return { detail, ...calls !== void 0 ? { calls } : {}, includePolls };
2379
+ }
2380
+ function parseConversationOverviewArgs(args) {
2381
+ let skeleton = false;
2382
+ for (const arg of args) {
2383
+ if (arg !== "--skeleton") {
2384
+ throw new Error(`Unknown conversation overview argument: ${arg}`);
2385
+ }
2386
+ if (skeleton) {
2387
+ throw new Error("Use --skeleton only once");
2388
+ }
2389
+ skeleton = true;
2390
+ }
2391
+ return { skeleton };
2356
2392
  }
2357
2393
  function parseConversationForkArgs(args) {
2358
2394
  let name;
@@ -2581,10 +2617,9 @@ Sessions: ${result.sessions.length}
2581
2617
  return;
2582
2618
  }
2583
2619
  if (first === "conversation" && second === "overview") {
2584
- if (args.length > 3) {
2585
- throw new Error(`Unexpected conversation overview argument: ${args[3]}`);
2586
- }
2587
- const read = await client.sessions.conversationOverview(requireValue(args[2], "Missing session id"));
2620
+ const sessionId = requireValue(args[2], "Missing session id");
2621
+ const { skeleton } = parseConversationOverviewArgs(args.slice(3));
2622
+ const read = await client.sessions.conversationOverview(sessionId, skeleton ? { view: "skeleton" } : {});
2588
2623
  write(read, renderConversationOverviewResponse(read));
2589
2624
  return;
2590
2625
  }
@@ -2619,8 +2654,12 @@ Sessions: ${result.sessions.length}
2619
2654
  if (first === "conversation" && second === "inspect-work") {
2620
2655
  const sessionId = requireValue(args[2], "Missing session id");
2621
2656
  const workId = requireValue(args[3], "Missing work id");
2622
- const detail = parseConversationWorkDetailArgs(args.slice(4));
2623
- const read = await client.sessions.inspectConversationWork(sessionId, workId, { detail });
2657
+ const options = parseConversationInspectWorkArgs(args.slice(4));
2658
+ const read = await client.sessions.inspectConversationWork(sessionId, workId, {
2659
+ detail: options.detail,
2660
+ ...options.calls !== void 0 ? { calls: options.calls } : {},
2661
+ ...options.includePolls ? { polls: "include" } : {}
2662
+ });
2624
2663
  write(read, renderConversationWorkResponse(read));
2625
2664
  return;
2626
2665
  }
@@ -3136,6 +3175,14 @@ async function runCommand(argv) {
3136
3175
  return 0;
3137
3176
  }
3138
3177
  if (execution.kind === "session-run") {
3178
+ if (!options.json) {
3179
+ if (execution.command.kind === "start") {
3180
+ process.stderr.write("Starting session (publishing the workspace and provisioning the worktree)...\n");
3181
+ } else if (execution.command.kind === "stop") {
3182
+ process.stderr.write(`Stopping session ${execution.command.sessionId}...
3183
+ `);
3184
+ }
3185
+ }
3139
3186
  const result = await dispatchSessionRunCommand(client, execution.command);
3140
3187
  if (execution.command.kind !== "start" || !execution.command.follow) {
3141
3188
  writeDataOutput(options.json, result.data, result.human);
@@ -3232,8 +3279,9 @@ export {
3232
3279
  parseAnswerFlags,
3233
3280
  parseAnswerQuestionsCommandArgs,
3234
3281
  parseConversationForkArgs,
3282
+ parseConversationInspectWorkArgs,
3283
+ parseConversationOverviewArgs,
3235
3284
  parseConversationRenderArgs,
3236
- parseConversationWorkDetailArgs,
3237
3285
  parseEnvFlags,
3238
3286
  parseEnvRequestResponseArgs,
3239
3287
  parseGetEnvsArgs,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.71",
3
+ "version": "0.0.72",
4
4
  "type": "module"
5
5
  }
@@ -298,7 +298,15 @@ export type R5dctlFollowOptions = {
298
298
  maxReconnects?: number;
299
299
  };
300
300
  export declare function followR5dctlSession(client: R5dctlFollowClient, sessionId: string, options: R5dctlFollowOptions): Promise<number>;
301
- export declare function parseConversationWorkDetailArgs(args: string[]): R5dctlConversationWorkDetail;
301
+ export type ConversationInspectWorkOptions = {
302
+ detail: R5dctlConversationWorkDetail;
303
+ calls?: string;
304
+ includePolls: boolean;
305
+ };
306
+ export declare function parseConversationInspectWorkArgs(args: string[]): ConversationInspectWorkOptions;
307
+ export declare function parseConversationOverviewArgs(args: string[]): {
308
+ skeleton: boolean;
309
+ };
302
310
  export declare function parseConversationForkArgs(args: string[]): string | undefined;
303
311
  export declare function renderConversationOverviewResponse(read: R5dctlConversationOverviewResponse): string;
304
312
  export declare function renderConversationNodeResponse(read: R5dctlConversationNodeResponse): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.71",
3
+ "version": "0.0.72",
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.71",
29
+ "@ricsam/r5d-api": "^0.0.72",
30
30
  "dotenv": "^17",
31
31
  "qrcode": "^1.5.4",
32
32
  "ws": "^8.18.3"