autodev-cli 1.4.97 → 1.4.101

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 (50) hide show
  1. package/media/profile/00-identity.md +8 -20
  2. package/media/profile/01-learning.md +12 -19
  3. package/media/profile/02-memory-mcp.md +4 -44
  4. package/media/profile/03-living-docs.md +10 -13
  5. package/media/profile/04-skill-files.md +3 -5
  6. package/media/profile/05-skill-creation.md +3 -14
  7. package/media/profile/06-core-rules.md +10 -47
  8. package/media/profile/07-core-loop.md +8 -25
  9. package/media/profile/08-thinking.md +10 -23
  10. package/media/profile/09-parallel-panel.md +9 -24
  11. package/media/profile/10-codebase-verification.md +7 -16
  12. package/media/profile/11-git-debug-security.md +5 -10
  13. package/media/profile/12-todo-format.md +3 -16
  14. package/media/profile/13-workflow-principles.md +3 -7
  15. package/media/profile/14-contracts.md +9 -12
  16. package/media/profile/15-soul.md +6 -8
  17. package/media/profile/16-journal.md +5 -32
  18. package/media/profile/17-issue-tracking.md +9 -14
  19. package/media/profile/18-knowledgebase.md +6 -9
  20. package/media/profile/19-subagent-context-management.md +11 -496
  21. package/media/profile/20-project-graph.md +23 -49
  22. package/out/commands/mcpOperate.js +150 -32
  23. package/out/commands/mcpOperate.js.map +1 -1
  24. package/out/core/controlSpec.d.ts +56 -0
  25. package/out/core/controlSpec.js +267 -0
  26. package/out/core/controlSpec.js.map +1 -0
  27. package/out/dispatcher.js +3 -1
  28. package/out/dispatcher.js.map +1 -1
  29. package/out/graphRender.d.ts +87 -0
  30. package/out/graphRender.js +279 -0
  31. package/out/graphRender.js.map +1 -0
  32. package/out/graphStore.d.ts +377 -2
  33. package/out/graphStore.js +1240 -64
  34. package/out/graphStore.js.map +1 -1
  35. package/out/journal.d.ts +35 -0
  36. package/out/journal.js +167 -0
  37. package/out/journal.js.map +1 -0
  38. package/out/messageBuilder.d.ts +1 -1
  39. package/out/messageBuilder.js +29 -29
  40. package/out/messageBuilder.js.map +1 -1
  41. package/out/periodicActions.d.ts +18 -0
  42. package/out/periodicActions.js +49 -0
  43. package/out/periodicActions.js.map +1 -1
  44. package/out/profileBuilder.d.ts +1 -1
  45. package/out/profileBuilder.js +31 -4
  46. package/out/profileBuilder.js.map +1 -1
  47. package/out/taskLoop.d.ts +19 -0
  48. package/out/taskLoop.js +214 -4
  49. package/out/taskLoop.js.map +1 -1
  50. package/package.json +2 -2
@@ -22,6 +22,14 @@
22
22
  * 3. Every `evaluation` identifies a `rubric`.
23
23
  * 4. Superseded nodes remain addressable — supersede never deletes; it links a
24
24
  * new version with a `supersedes` edge and flags the old one.
25
+ *
26
+ * MATERIALISATION (Tier 0). The log is append-only, so reload is incremental: we
27
+ * remember a byte offset and apply only the newly-appended tail on top of the
28
+ * live maps (apply is idempotent last-writer-wins) — a full clear+rebuild only
29
+ * happens when the file shrank (a rewrite). Two derived indexes are kept in step:
30
+ * an adjacency index (nodeId → incident edges) and an entity canonical-key index
31
+ * (name → entity id) so `UsageService` / `usage-service` / `usage service` all
32
+ * resolve to ONE entity.
25
33
  */
26
34
  export type GraphNodeType = 'entity' | 'claim' | 'source' | 'artifact' | 'agent_run' | 'evaluation' | 'task' | 'commit' | 'metric' | 'note' | 'question' | 'decision';
27
35
  export type GraphEdgeType = 'mentions' | 'supports' | 'contradicts' | 'derived_from' | 'produced' | 'evaluates' | 'revises' | 'supersedes' | 'depends_on' | 'parent_of' | 'resolved_to' | 'relates_to';
@@ -32,6 +40,14 @@ export interface GraphNode {
32
40
  type: GraphNodeType;
33
41
  name: string;
34
42
  body?: string;
43
+ /**
44
+ * A one-line gist of the node — the navigation enabler (Tier 1, item 3).
45
+ * Agent-supplied at write (the writing agent already holds the context, and it
46
+ * rides its provenance like any write). Optional and purely additive: old log
47
+ * lines without `summary` replay fine. When absent on an interior/hub node, a
48
+ * deterministic structural rollup is synthesized on read (no LLM call).
49
+ */
50
+ summary?: string;
35
51
  props?: Record<string, unknown>;
36
52
  /** Where the fact came from (a citation, url, file:line, or a source node id). */
37
53
  source?: string;
@@ -69,6 +85,8 @@ export interface AddNodeInput {
69
85
  name: string;
70
86
  id?: string;
71
87
  body?: string;
88
+ /** One-line gist (Tier 1). Stamped with a `summaryAt` prop so staleness is detectable. */
89
+ summary?: string;
72
90
  props?: Record<string, unknown>;
73
91
  source?: string;
74
92
  inference?: boolean;
@@ -86,26 +104,227 @@ export interface AddEdgeInput {
86
104
  /** A write rejected by an invariant — the caller turns this into a helpful error. */
87
105
  export declare class GraphInvariantError extends Error {
88
106
  }
107
+ /**
108
+ * Split a label into normalised word tokens: break camelCase / PascalCase and
109
+ * acronym boundaries into words, lowercase, and split on any non-alphanumeric.
110
+ * `"UsageService"` → `["usage","service"]`, `"usage-service"` → `["usage","service"]`,
111
+ * `"HTTPServer v2"` → `["http","server","v2"]`.
112
+ */
113
+ export declare function tokenize(s: string): string[];
114
+ /**
115
+ * Canonical dedup key for an entity name: a **sorted, de-duplicated token set**.
116
+ * This collapses camelCase, kebab-case and spaced spellings AND word order to a
117
+ * single key, so `UsageService`, `usage-service` and `usage service` map to one
118
+ * `entity:` id. Sorting means `"Service Usage"` also collapses onto the same key.
119
+ */
120
+ export declare function canonicalKey(s: string): string;
121
+ /** Rough token estimate for budgeting — ~4 chars/token. */
122
+ export declare function estimateTokens(s: string): number;
123
+ /**
124
+ * Parse a `file:line`-style source into its cumulative path segments — the spine
125
+ * an auto-scaffold builds (item 1). `"src/foo/bar.ts:12"` → `["src","src/foo",
126
+ * "src/foo/bar.ts"]`; `"pay.ts:10"` → `["pay.ts"]`. Returns null for a URL, a
127
+ * source-node id (`source:ab12`), or anything that doesn't look like a path — the
128
+ * scaffold is deterministic and conservative, never a guess.
129
+ */
130
+ export declare function parseSourcePath(source: string | undefined): string[] | null;
131
+ /** A scored query row (Tier 1) — reused by graph_query, graph_map and graph_search. */
132
+ export interface ScoredNode {
133
+ node: GraphNode;
134
+ score: number;
135
+ textScore: number;
136
+ matched: string[];
137
+ substring: boolean;
138
+ }
139
+ /** One "where do I start" map entry: a node plus its effective (authored or synthesized) summary. */
140
+ export interface MapEntry {
141
+ id: string;
142
+ type: GraphNodeType;
143
+ name: string;
144
+ summary?: string;
145
+ synthesized?: boolean;
146
+ stale?: boolean;
147
+ degree: number;
148
+ }
149
+ export interface GraphMap {
150
+ /** Pinned "core" tier (item 4): project invariants always prepended within budget. */
151
+ pinned: MapEntry[];
152
+ hubs: MapEntry[];
153
+ questions: MapEntry[];
154
+ decisions: MapEntry[];
155
+ contradictions: {
156
+ a: {
157
+ id: string;
158
+ name: string;
159
+ };
160
+ b: {
161
+ id: string;
162
+ name: string;
163
+ };
164
+ }[];
165
+ }
166
+ /** One node of a navigable table-of-contents (item 2). */
167
+ export interface TocNode {
168
+ id: string;
169
+ type: string;
170
+ name: string;
171
+ summary?: string;
172
+ synthesized?: boolean;
173
+ /** Total parent_of children (before the maxChildren cap). */
174
+ childCount: number;
175
+ children: TocNode[];
176
+ /** Children collapsed by the maxChildren cap or depth bound — the "+K more". */
177
+ moreChildren?: number;
178
+ }
179
+ export interface TocResult {
180
+ roots: TocNode[];
181
+ /** True when the spine was sparse and roots fell back to deterministic clustering. */
182
+ clustered?: boolean;
183
+ }
184
+ /** One row of a graph_search bundle — citable, with the edge-path from its seed. */
185
+ export interface SearchRow {
186
+ id: string;
187
+ type: GraphNodeType;
188
+ name: string;
189
+ score: number;
190
+ matched: string[];
191
+ summary?: string;
192
+ synthesized?: boolean;
193
+ inference?: boolean;
194
+ seedId: string;
195
+ /** The edge used to reach this node (undefined for a seed). */
196
+ via?: {
197
+ edge: GraphEdgeType;
198
+ fromId: string;
199
+ dir: 'out' | 'in';
200
+ };
201
+ /** Hop descriptors from the seed, e.g. ["supports→ claim:ab12"] — for explainability. */
202
+ path: string[];
203
+ conflicts: {
204
+ id: string;
205
+ name: string;
206
+ }[];
207
+ }
208
+ export interface SearchResult {
209
+ intent: string;
210
+ terms: string[];
211
+ budget: number;
212
+ hops: number;
213
+ rows: SearchRow[];
214
+ }
89
215
  export declare class GraphStore {
90
216
  private identity;
91
217
  private readonly dir;
92
218
  private readonly file;
219
+ /** Disposable materialised cache for cold-start (item 3). JSONL stays the sole source of truth. */
220
+ private readonly snapshotFile;
221
+ private readonly snapshotEnabled;
222
+ /** Byte offset the on-disk snapshot covers (0 = none loaded/written this session). */
223
+ private snapshotCoversBytes;
224
+ /** Ops applied since the last snapshot was written/loaded — the regeneration trigger. */
225
+ private opsSinceSnapshot;
93
226
  private nodes;
94
227
  private edges;
228
+ /** nodeId → incident edges (both directions). Rebuilt on clear, kept in step in apply(). */
229
+ private adjacency;
230
+ /** entity canonical-key → entity node id — the dedup + legacy-id resolution index. */
231
+ private entityIndex;
95
232
  private lastSize;
96
233
  private lastMtimeMs;
97
- constructor(workspaceRoot: string, identity: Identity);
234
+ /** byte offset up to (and including) the last COMPLETE log line we've applied. */
235
+ private lastOffset;
236
+ /** total log ops applied since the last full rebuild (for dead-weight telemetry). */
237
+ private appliedOps;
238
+ /** complete-but-corrupt (JSON-unparseable) MIDDLE lines seen; a torn FINAL line is NOT counted. */
239
+ private parseFailures;
240
+ /** wall-clock ms of the last (incremental or full) reload. */
241
+ private lastReplayMs;
242
+ /** Monotonic node-set version bumped by apply() — the invalidation signal reload uses. */
243
+ private mutationSeq;
244
+ /** IDF over the resident node set, memoised until mutationSeq changes (item 1). */
245
+ private idfCache;
246
+ private idfCacheSeq;
247
+ constructor(workspaceRoot: string, identity: Identity, opts?: {
248
+ snapshot?: boolean;
249
+ });
98
250
  /** Where the graph lives (for messages). */
99
251
  get path(): string;
100
252
  private ensureDir;
101
- /** Re-materialise from disk when the log changed under us (another agent wrote). */
253
+ private clear;
254
+ /**
255
+ * Re-materialise from disk when the log changed under us (another agent wrote).
256
+ * INCREMENTAL: since the log is append-only we treat `lastOffset` as a byte
257
+ * cursor and apply only the newly-appended tail on top of the live maps (apply
258
+ * is idempotent). A full clear+rebuild happens only when the file shrank below
259
+ * our cursor (a rewrite). A torn final line is left unconsumed and picked up on
260
+ * a later tick once the writer finishes it. This is provably identical to a
261
+ * full replay because apply() is last-writer-wins and the log is append-only.
262
+ */
102
263
  reloadIfChanged(): void;
264
+ /**
265
+ * Cold-start load: if a valid snapshot covers a prefix of the current log, adopt
266
+ * it and tail-replay only the uncovered bytes; otherwise full-replay. The
267
+ * snapshot is a DISPOSABLE cache — a missing / stale / corrupt one simply falls
268
+ * back to full replay, and the JSONL is never touched.
269
+ */
270
+ private loadFromScratch;
271
+ /** sha256 of the first min(4096, covers) bytes of the log — the cheap rewrite guard. */
272
+ private headSig;
273
+ /**
274
+ * Adopt the on-disk snapshot iff it is a valid prefix of the current log:
275
+ * `coversBytes` in (0, size] AND the head-signature still matches (guards against
276
+ * a rewritten/truncated log whose prefix changed). Rebuilds the derived indexes
277
+ * from the resident node/edge set rather than trusting serialized indexes.
278
+ */
279
+ private tryLoadSnapshot;
280
+ /** Regenerate the snapshot when the uncovered tail grew past the byte/op threshold. */
281
+ private maybeWriteSnapshot;
282
+ /**
283
+ * Write the snapshot atomically (temp file + rename) so a partial write is never
284
+ * visible and concurrent multi-agent regenerations can't corrupt it — the loser
285
+ * of a rename race simply leaves a consistent, self-describing file behind. Snaps
286
+ * only the byte prefix we've fully applied (`lastOffset`), so a torn final line is
287
+ * never captured.
288
+ */
289
+ private writeSnapshot;
290
+ /** Force a snapshot now (test hook / explicit checkpoint). No-op when snapshots are disabled. */
291
+ materializeSnapshot(): boolean;
292
+ /** Read bytes [start,end), apply every COMPLETE line, and advance lastOffset past them. */
293
+ private replayRange;
103
294
  private apply;
295
+ private indexEntity;
296
+ private indexEdge;
297
+ private pushAdj;
298
+ private unindexEdge;
104
299
  private append;
105
300
  addNode(input: AddNodeInput): {
106
301
  node: GraphNode;
107
302
  created: boolean;
108
303
  };
304
+ /**
305
+ * The write path. `scaffold:true` (the public {@link addNode}) additionally runs
306
+ * the deterministic parent_of auto-scaffold (item 1); the scaffold's own entity
307
+ * writes pass `scaffold:false` so they never recurse.
308
+ */
309
+ private addNodeInternal;
310
+ /**
311
+ * Deterministically fill the parent_of tree from a fact's provenance — NO LLM.
312
+ * A `file:line` source on a claim/artifact/decision/note upserts `entity` nodes
313
+ * for the file and its ancestor dirs and links a `dir → file → fact` spine; a
314
+ * `props.area` tag upserts an area entity and parents the fact under it. Every
315
+ * derived node/edge carries this run's provenance and a `props.autoScaffold=true`
316
+ * marker, and is idempotent (deterministic ids + edge dedup) so re-adds and
317
+ * concurrent writers converge instead of duplicating.
318
+ */
319
+ private scaffold;
320
+ private scaffoldFromSource;
321
+ private scaffoldFromArea;
322
+ /** Is there already an edge of `type` from→to? (idempotency for scaffold/rollup edges). */
323
+ private hasEdge;
324
+ /** Add a parent_of edge (marked autoScaffold) unless it already exists. */
325
+ private linkParentOf;
326
+ /** Deterministic id for a new node: entities dedupe by canonical key (+ aliases), others are fresh. */
327
+ private mintId;
109
328
  addEdge(input: AddEdgeInput): GraphEdge;
110
329
  /**
111
330
  * Version a node: create the replacement, link it with a `supersedes` edge,
@@ -118,28 +337,172 @@ export declare class GraphStore {
118
337
  edge: GraphEdge;
119
338
  };
120
339
  getNode(idOrName: string): GraphNode | undefined;
340
+ /** Incident `contradicts` edges of a node, resolved to {id,name} of the other endpoint. */
341
+ contradictionsFor(id: string): {
342
+ id: string;
343
+ name: string;
344
+ }[];
345
+ /** Node degree (incident edge count) — shared ranking infra for Tier 1. */
346
+ degree(id: string): number;
347
+ /** IDF over the resident node set, memoised until the node set mutates. */
348
+ private idf;
349
+ /** Exponential recency lift in [0,1]: 1 at now, decaying with age (τ≈30d). */
350
+ private recencyDecay;
351
+ /** Field-weighted TF·IDF text score for a node against a set of query terms. */
352
+ private scoreNode;
353
+ /**
354
+ * Relevance-ranked query (Tier 1, item 1). OR-semantics: a node is a hit if it
355
+ * matches ≥1 query term OR contains the intent as an exact substring (the old
356
+ * behaviour, kept as a guaranteed-inclusion signal → strict superset). Ranked by
357
+ * `textScore·(1 + wRecency·decay + wDegree·log1p(degree))`. `mode:'recent'` keeps
358
+ * the pure recency order; superseded nodes hidden unless includeSuperseded.
359
+ */
360
+ scoredQuery(opts: {
361
+ type?: string;
362
+ text?: string;
363
+ id?: string;
364
+ includeSuperseded?: boolean;
365
+ limit?: number;
366
+ mode?: 'relevance' | 'recent';
367
+ }): ScoredNode[];
368
+ /**
369
+ * Search nodes by type and/or text. Thin wrapper over {@link scoredQuery}: with
370
+ * `text` it returns relevance-ranked hits (item 1); without, recency order. The
371
+ * old pure-substring behaviour survives as a guaranteed-inclusion subset.
372
+ */
121
373
  query(opts: {
122
374
  type?: string;
123
375
  text?: string;
124
376
  id?: string;
125
377
  includeSuperseded?: boolean;
126
378
  limit?: number;
379
+ mode?: 'relevance' | 'recent';
127
380
  }): GraphNode[];
128
381
  /**
129
382
  * Bounded neighbourhood around a node — the playbook's "context construction
130
383
  * from a graph": resolve the entity, expand a hop or two over allowed edge
131
384
  * types, and return a small, citable subgraph rather than the whole graph.
385
+ * Uses the adjacency index (O(visited degree), not O(E·hops)) and returns the
386
+ * BFS hop-distance per node so the caller can rank/token-budget the result.
387
+ * `includeConflicts` (default true) always follows `contradicts` edges so a
388
+ * conflicting claim can never be hidden by an `edgeTypes` filter.
132
389
  */
133
390
  neighbors(opts: {
134
391
  idOrName: string;
135
392
  hops?: number;
136
393
  edgeTypes?: string[];
137
394
  limit?: number;
395
+ includeConflicts?: boolean;
138
396
  }): {
139
397
  center: GraphNode;
140
398
  nodes: GraphNode[];
141
399
  edges: GraphEdge[];
400
+ dist: Record<string, number>;
142
401
  } | null;
402
+ /** Distinct neighbour nodes of a node (via the adjacency index). */
403
+ private neighborNodes;
404
+ /** `parent_of` children of a node (this node as the parent). */
405
+ private childrenOf;
406
+ /**
407
+ * DETERMINISTIC one-line rollup for an interior/hub node with NO authored
408
+ * summary — NO LLM call. Synthesised from structure: child (or, absent
409
+ * `parent_of` children, neighbour) type counts + the top child names by degree.
410
+ * Returns undefined for a leaf/low-degree node (nothing to summarise).
411
+ */
412
+ rollupSummary(id: string): string | undefined;
413
+ /**
414
+ * The summary to SHOW for a node: the authored one if present, else the
415
+ * deterministic structural rollup (flagged synthesized), else nothing.
416
+ */
417
+ effectiveSummary(node: GraphNode): {
418
+ text: string;
419
+ synthesized: boolean;
420
+ } | undefined;
421
+ /**
422
+ * An AUTHORED summary is stale when the node has been superseded, or gained a
423
+ * `parent_of` child AFTER the summary was written (`props.summaryAt`). Nodes
424
+ * with no authored summary are "unsummarized", not stale.
425
+ */
426
+ summaryStale(node: GraphNode): boolean;
427
+ private mapEntry;
428
+ /**
429
+ * "Where do I start" for an agent with no id/name in hand. Ranks entities (and
430
+ * any node when `focusType` unset) by degree() over the adjacency index, and
431
+ * bundles the open `question`s, freshest `decision`s, and live `contradicts`
432
+ * pairs it already knows how to find. Purely read-side; render via graphRender.
433
+ */
434
+ map(opts?: {
435
+ depth?: number;
436
+ focusType?: string;
437
+ maxChildren?: number;
438
+ }): GraphMap;
439
+ /** A node is pinned by `props.pinned===true` or by the reserved `props.area==='core'`. */
440
+ private isPinnedNode;
441
+ /** Live pinned nodes (project invariants) — always prepended within budget. */
442
+ pinnedNodes(): GraphNode[];
443
+ /** Set/clear the pin flag on a node (upsert; the node stays otherwise unchanged). */
444
+ pin(idOrName: string, pinned?: boolean): GraphNode;
445
+ /**
446
+ * Vectorless, explainable, CITABLE retrieval — the PageIndex centrepiece done
447
+ * without embeddings and without a server-side model (the calling agent is the
448
+ * reasoner). Seed with the item-1 ranked query on `intent`, then best-first
449
+ * expand a relevance-priority frontier: pop the best node, expand 1 hop
450
+ * (strong provenance edges — supports/derived_from/produced/evaluates/
451
+ * depends_on/parent_of — before weak relates_to/mentions), score newly-found
452
+ * nodes against the intent, push. Stop at node_budget. Each returned row cites
453
+ * `[id]` with the matched terms and the edge-path from its seed.
454
+ */
455
+ search(opts: {
456
+ intent: string;
457
+ nodeBudget?: number;
458
+ hops?: number;
459
+ }): SearchResult;
460
+ private parentOfChildIds;
461
+ private hasParentOfParent;
462
+ private hasParentOfChild;
463
+ /** Connected components of `pool` over the given (undirected) edge types. */
464
+ private components;
465
+ /**
466
+ * Depth-bounded, summarized hierarchy (PageIndex-style "text-stripped overview →
467
+ * drill"). The spine is `parent_of` (roots = entities with no incoming parent_of);
468
+ * where that spine is sparse the uncovered remainder falls back to deterministic
469
+ * clustering (by `props.area`, else connected components over relates_to/
470
+ * depends_on). Each level shows the top `maxChildren` by degree and collapses the
471
+ * rest to `+K more`. Summaries reuse {@link effectiveSummary}. Pass `root` to
472
+ * expand one branch.
473
+ */
474
+ toc(opts?: {
475
+ root?: string;
476
+ depth?: number;
477
+ focusType?: string;
478
+ maxChildren?: number;
479
+ }): TocResult;
480
+ /** Deterministic id for a cluster's rollup node, so concurrent rollups upsert not duplicate. */
481
+ private rollupId;
482
+ /** parent_of descendants of a node (transitive), excluding itself. */
483
+ private descendants;
484
+ private rollupFromMembers;
485
+ /** The rollup/summary node for a cluster centre, if one has been created. */
486
+ rollupNodeFor(idOrName: string): GraphNode | undefined;
487
+ /**
488
+ * Create or upsert a hierarchical rollup for a cluster (item 5). The cluster is a
489
+ * centre entity's `parent_of` descendants, or — absent a spine — its N-hop
490
+ * neighbourhood. The rollup is a `note` with `props.rollup=true` and a
491
+ * DETERMINISTIC id (`summary:<centre-key>`) so concurrent rollups of the same
492
+ * cluster upsert rather than duplicate; it links `derived_from → each member`
493
+ * (members stay fully addressable in `props.members`) and hangs under the centre
494
+ * via `parent_of` so it's discoverable in the TOC. Summary text is agent-supplied
495
+ * or the deterministic Tier-1 rollup (no LLM on the default path).
496
+ */
497
+ rollup(opts: {
498
+ idOrName?: string;
499
+ hops?: number;
500
+ summary?: string;
501
+ }): {
502
+ node: GraphNode;
503
+ members: string[];
504
+ created: boolean;
505
+ };
143
506
  stats(): {
144
507
  nodeCount: number;
145
508
  edgeCount: number;
@@ -149,5 +512,17 @@ export declare class GraphStore {
149
512
  isolated: number;
150
513
  contradictions: number;
151
514
  openQuestions: number;
515
+ unsummarized: number;
516
+ staleSummaries: number;
517
+ spinelessHubs: number;
518
+ pinned: number;
519
+ fileBytes: number;
520
+ totalOps: number;
521
+ deadWeight: number;
522
+ deadWeightRatio: number;
523
+ lastReplayMs: number;
524
+ estTokens: number;
525
+ parseFailures: number;
526
+ tornFinalLine: boolean;
152
527
  };
153
528
  }