@phnx-labs/agents-cli 1.22.83 → 1.22.84

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 (41) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/commands/accounts.js +1 -1
  3. package/dist/commands/sessions-trace.d.ts +11 -0
  4. package/dist/commands/sessions-trace.js +71 -0
  5. package/dist/lib/accounts/connect.d.ts +6 -0
  6. package/dist/lib/accounts/connect.js +70 -0
  7. package/dist/lib/daemon-ticks.js +23 -2
  8. package/dist/lib/feed/activity-stream.d.ts +60 -0
  9. package/dist/lib/feed/activity-stream.js +271 -0
  10. package/dist/lib/feed/activity.d.ts +7 -0
  11. package/dist/lib/feed/activity.js +10 -4
  12. package/dist/lib/feed/watch.d.ts +9 -3
  13. package/dist/lib/feed/watch.js +72 -36
  14. package/dist/lib/fleet-shared-state.d.ts +6 -0
  15. package/dist/lib/session/active.d.ts +38 -4
  16. package/dist/lib/session/active.js +36 -4
  17. package/dist/lib/session/bash-command.js +10 -0
  18. package/dist/lib/session/db.d.ts +47 -2
  19. package/dist/lib/session/db.js +131 -4
  20. package/dist/lib/session/mirror.d.ts +5 -0
  21. package/dist/lib/session/mirror.js +166 -0
  22. package/dist/lib/session/parse.d.ts +49 -0
  23. package/dist/lib/session/parse.js +324 -30
  24. package/dist/lib/session/prompt.d.ts +93 -2
  25. package/dist/lib/session/prompt.js +266 -15
  26. package/dist/lib/session/remote/peer-stream.d.ts +47 -0
  27. package/dist/lib/session/remote/peer-stream.js +142 -0
  28. package/dist/lib/session/remote/watch.d.ts +1 -1
  29. package/dist/lib/session/remote/watch.js +41 -42
  30. package/dist/lib/session/session-cache.d.ts +9 -0
  31. package/dist/lib/session/session-cache.js +40 -2
  32. package/dist/lib/session/timeline-pass.d.ts +129 -0
  33. package/dist/lib/session/timeline-pass.js +323 -0
  34. package/dist/lib/session/timeline.d.ts +182 -0
  35. package/dist/lib/session/timeline.js +636 -0
  36. package/dist/lib/session/types.d.ts +155 -1
  37. package/dist/lib/summarizer/pass.d.ts +2 -0
  38. package/dist/lib/summarizer/pass.js +14 -1
  39. package/dist/lib/summarizer/summarize.d.ts +7 -0
  40. package/dist/lib/summarizer/summarize.js +3 -0
  41. package/package.json +1 -1
@@ -43,7 +43,13 @@ export declare function sessionDisplayAgent(session: {
43
43
  }): string;
44
44
  /** A single normalized event within a session (message, tool call, thinking, etc.). */
45
45
  export interface SessionEvent {
46
- type: 'message' | 'tool_use' | 'tool_result' | 'thinking' | 'error' | 'init' | 'result' | 'usage' | 'attachment' | 'hook' | 'interrupt';
46
+ /**
47
+ * `file_change` is the harness's own file ledger (Claude `file-history-delta`,
48
+ * Codex `FileChange`, OpenCode `patch`) rather than a tool call. It is emitted
49
+ * only on request (`includeFileHistory`) or by the Codex item reader, never in
50
+ * the default published stream — see `ParseSessionOptions.includeFileHistory`.
51
+ */
52
+ type: 'message' | 'tool_use' | 'tool_result' | 'thinking' | 'error' | 'init' | 'result' | 'usage' | 'attachment' | 'hook' | 'interrupt' | 'file_change';
47
53
  agent: SessionAgentId;
48
54
  timestamp: string;
49
55
  role?: 'user' | 'assistant';
@@ -57,6 +63,13 @@ export interface SessionEvent {
57
63
  success?: boolean;
58
64
  /** Structured harness outcome; never inferred from free-text output. */
59
65
  outcome?: 'ok' | 'error' | 'unknown';
66
+ /**
67
+ * The call never RAN: a permission rule or hook denied it (Claude
68
+ * `toolDenialKind`), or the turn was aborted. Distinct from a failure — a
69
+ * blocked call says nothing about whether the work would have succeeded, so
70
+ * the timeline counts the two separately.
71
+ */
72
+ blocked?: boolean;
60
73
  exitCode?: number;
61
74
  statusCode?: number;
62
75
  errorCode?: string;
@@ -93,6 +106,35 @@ export interface SessionEvent {
93
106
  * programmatically, not the user). Undefined for every other event.
94
107
  */
95
108
  slashCommand?: string;
109
+ /**
110
+ * The label the HARNESS itself wrote for this call — Claude's Bash
111
+ * `input.description` ("Locate the prior session transcript on disk"), Kimi's
112
+ * `tool.call.description`, OpenCode's `state.title` / `state.input.description`,
113
+ * Codex's `CommandExecution.command`. Human-written, one per call, and exactly
114
+ * what a now-line needs; `summarizeToolUse` renders the mechanical form
115
+ * instead, which is why this is kept separately rather than folded into it.
116
+ */
117
+ label?: string;
118
+ /**
119
+ * Verb class the HARNESS assigned (Codex `parsed_cmd.type`, a typed tool
120
+ * name). Absent when the harness does not classify its own call — then the
121
+ * consumer derives one from `command`.
122
+ */
123
+ verbClass?: SessionVerbClass;
124
+ /**
125
+ * Per-path file operations the harness recorded for this call (Codex
126
+ * `FileChange.changes`, OpenCode `patch.files`). The exact edit ledger, as
127
+ * opposed to inferring one from Edit/Write arguments.
128
+ */
129
+ changes?: Array<{
130
+ path: string;
131
+ op: 'created' | 'modified' | 'deleted';
132
+ }>;
133
+ /**
134
+ * Codex tags an `AgentMessage` with the role it played in the turn
135
+ * (`commentary` is the narration between tool calls). Absent elsewhere.
136
+ */
137
+ phase?: string;
96
138
  }
97
139
  /** A displayable file attachment discovered in a session transcript. */
98
140
  export interface SessionAttachment {
@@ -148,6 +190,110 @@ export interface SessionChecklistItem {
148
190
  * left no summary; the row deliberately carries no goal/checkpoints.
149
191
  */
150
192
  export type SummaryState = 'pending' | 'ready' | 'skipped';
193
+ /**
194
+ * How a tool call is bucketed on a timeline step (PHNX-3939). Coarse on purpose
195
+ * — a step renders as "6 run · 2 blocked", not as a tool histogram. Taken from
196
+ * the harness when it classifies its own call (Codex `parsed_cmd.type`, a
197
+ * harness tool name) and derived from the command otherwise.
198
+ */
199
+ export type SessionVerbClass = 'read' | 'edit' | 'run' | 'git' | 'test' | 'browser' | 'agent' | 'other';
200
+ /**
201
+ * One step of the narration-anchored timeline (PHNX-3939): the agent's own
202
+ * short line about what it is doing, plus the tool calls that ran under it.
203
+ *
204
+ * The text is never model-written — it is the harness's own narration (Claude
205
+ * assistant text, Codex `AgentMessage` commentary, Gemini thought subject), a
206
+ * thinking block when there is no narration, the user's tidied turn, or a
207
+ * mix-derived line when tools ran with nothing said. `source` says which.
208
+ */
209
+ export interface SessionStep {
210
+ /** Headline: the first sentence of the narration, capped. */
211
+ text: string;
212
+ /** ISO time this step opened. */
213
+ at: string;
214
+ /** ISO time of the last event folded into it. */
215
+ endedAt?: string;
216
+ source: 'narration' | 'thinking' | 'derived' | 'user';
217
+ /** Tool calls attached to this step. */
218
+ tools: number;
219
+ /** Calls that RAN and failed (non-zero exit, `is_error`, harness error status). */
220
+ failed: number;
221
+ /** Calls that never ran: a permission rule, a hook denial, an aborted turn. */
222
+ blocked: number;
223
+ /** Per-verb-class tally of the attached calls. */
224
+ mix?: Partial<Record<SessionVerbClass, number>>;
225
+ /** Milestones recognized under this step ("worktree created", "PR opened", "files changed"). */
226
+ marks?: string[];
227
+ /** True on the newest step while the session is working. */
228
+ live?: boolean;
229
+ /** Harness label of the running tool on a live step — the now-line. */
230
+ now?: string;
231
+ }
232
+ /**
233
+ * The bounded projection of a session's timeline that rides the row (PHNX-3939).
234
+ *
235
+ * `steps` is the tail; everything before it collapses into `earlier` so the
236
+ * payload stays flat as a session grows. `state` is honest about harnesses that
237
+ * cannot supply one: `partial` when an event cap was hit, `unavailable` with a
238
+ * `reason` when the harness writes no parseable transcript (OpenClaw) — never
239
+ * an empty step list presented as "nothing happened".
240
+ */
241
+ export interface SessionTimeline {
242
+ /** Newest last, at most `keep` (8). */
243
+ steps: SessionStep[];
244
+ earlier: {
245
+ steps: number;
246
+ tools: number;
247
+ failed: number;
248
+ };
249
+ /** Totals across the WHOLE session, not just `steps`. */
250
+ tools: number;
251
+ failed: number;
252
+ blocked: number;
253
+ spanMs: number;
254
+ state: 'ready' | 'partial' | 'unavailable';
255
+ reason?: string;
256
+ }
257
+ /**
258
+ * The session's operative request: the latest genuine user turn, tidied but
259
+ * never rewritten (PHNX-3939). `turns` counts every genuine user turn so a
260
+ * consumer can say "latest of 6"; `continues` names the session a `/continue`
261
+ * picked up.
262
+ */
263
+ export type SessionRequest = import('./prompt.js').TidyRequest & {
264
+ /**
265
+ * Genuine user turns in the session so far, so a consumer can say "latest of
266
+ * 6". Present only when the daemon's timeline fold counted them; a request
267
+ * tidied inline from the indexed turn alone does not know the count and says
268
+ * nothing rather than claiming 1.
269
+ */
270
+ turns?: number;
271
+ continues?: {
272
+ id: string;
273
+ label?: string;
274
+ };
275
+ };
276
+ /** One file the session created, modified or deleted. */
277
+ export interface SessionFileChange {
278
+ path: string;
279
+ op: 'created' | 'modified' | 'deleted';
280
+ /** How many times the session touched it. */
281
+ edits: number;
282
+ /** ISO time of the last touch. */
283
+ at: string;
284
+ }
285
+ /**
286
+ * The files a session changed (PHNX-3939). `source: 'harness'` means the
287
+ * harness recorded the change itself (Codex `FileChange`, OpenCode `patch`,
288
+ * Claude `file-history-delta`); `'tools'` means it was derived from Edit/Write
289
+ * calls because the harness records no file ledger. `changes` is bounded to 8
290
+ * rows; `total` is the real count.
291
+ */
292
+ export interface SessionFiles {
293
+ changes: SessionFileChange[];
294
+ total: number;
295
+ source: 'harness' | 'tools';
296
+ }
151
297
  /** Metadata attached when a session was spawned by `agents teams`. */
152
298
  export interface TeamOrigin {
153
299
  /** Teammate name if set, otherwise first 8 chars of the agent UUID. */
@@ -256,6 +402,14 @@ export interface SessionMeta {
256
402
  topic?: string;
257
403
  /** Full, cleaned first genuine user turn; distinct from the one-line topic. */
258
404
  firstUserMessage?: string;
405
+ /**
406
+ * Full, cleaned LATEST genuine user turn. For a `/continue`, a redirect, or an
407
+ * interrupted-and-restated session the operative request is the last thing the
408
+ * user said, not the first — which is what the session row and the sidebar's
409
+ * Request card show (PHNX-3939). Equal to {@link firstUserMessage} for a
410
+ * single-turn session; absent for rows indexed before this field shipped.
411
+ */
412
+ lastUserMessage?: string;
259
413
  /**
260
414
  * The session's human-readable name — one field, several sources with a plain
261
415
  * priority: an agent-generated title / Claude `/rename` wins; else the launch
@@ -15,6 +15,8 @@ import { type SummarizerConfig } from './config.js';
15
15
  import { summarize as defaultSummarize } from './summarize.js';
16
16
  /** Max sessions summarized per tick — a debounce ceiling on local-model calls. */
17
17
  export declare const SUMMARIZER_MAX_PER_TICK = 8;
18
+ /** Narration headlines handed to the model per session — the recent tail, not the history. */
19
+ export declare const SUMMARIZER_STEP_INPUT = 12;
18
20
  export interface SummarizerPassOptions {
19
21
  now?: number;
20
22
  config?: SummarizerConfig;
@@ -17,6 +17,8 @@ import { resolveSummarizerConfig, isSummarizerRunnable } from './config.js';
17
17
  import { summarize as defaultSummarize } from './summarize.js';
18
18
  /** Max sessions summarized per tick — a debounce ceiling on local-model calls. */
19
19
  export const SUMMARIZER_MAX_PER_TICK = 8;
20
+ /** Narration headlines handed to the model per session — the recent tail, not the history. */
21
+ export const SUMMARIZER_STEP_INPUT = 12;
20
22
  /**
21
23
  * Merge model checkpoint TEXTS with any prior stored checkpoints so a line that
22
24
  * already existed keeps its original `at`, and only genuinely new lines get
@@ -87,7 +89,18 @@ export async function runSummarizerPass(opts = {}) {
87
89
  }
88
90
  let computed;
89
91
  try {
90
- computed = await runSummarize(prompt, { todos: s.todos, plan: s.plan, phase: s.phase }, { baseUrl: config.baseUrl, model: config.model, ...(opts.signal ? { signal: opts.signal } : {}) });
92
+ computed = await runSummarize(prompt, {
93
+ todos: s.todos,
94
+ plan: s.plan,
95
+ phase: s.phase,
96
+ // The agent's own narration headlines, when the timeline pass has
97
+ // folded them (PHNX-3939) — the model's progress input was previously
98
+ // only the checklist, which many sessions never write. Optional by
99
+ // construction: a row with no timeline passes nothing extra.
100
+ ...(s.timeline?.steps.length
101
+ ? { steps: s.timeline.steps.slice(-SUMMARIZER_STEP_INPUT).map((step) => step.text) }
102
+ : {}),
103
+ }, { baseUrl: config.baseUrl, model: config.model, ...(opts.signal ? { signal: opts.signal } : {}) });
91
104
  }
92
105
  catch {
93
106
  computed = undefined;
@@ -20,6 +20,13 @@ export interface SummarizeProgress {
20
20
  plan?: string;
21
21
  /** Coarse lifecycle phase (running / waiting / idle / …), when known. */
22
22
  phase?: string;
23
+ /**
24
+ * The agent's own narration headlines, oldest first — the last K steps the
25
+ * daemon's timeline fold produced (PHNX-3939). Optional: many sessions never
26
+ * write a checklist, so this is often the only evidence of progress the model
27
+ * gets, but a row with no folded timeline simply passes none.
28
+ */
29
+ steps?: string[];
23
30
  }
24
31
  /** The validated model output. `at` timestamps are stamped by the caller. */
25
32
  export interface SummarizeResult {
@@ -32,6 +32,9 @@ export function buildSummarizeUserMessage(prompt, progress) {
32
32
  }
33
33
  if (progress.plan)
34
34
  parts.push(`PLAN:\n${progress.plan.trim().slice(0, 4000)}`);
35
+ if (progress.steps?.length) {
36
+ parts.push(`WHAT THE AGENT SAID IT WAS DOING (oldest first):\n${progress.steps.map((step) => `- ${step}`).join('\n')}`);
37
+ }
35
38
  return parts.join('\n\n');
36
39
  }
37
40
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phnx-labs/agents-cli",
3
- "version": "1.22.83",
3
+ "version": "1.22.84",
4
4
  "description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",