poe-code 4.0.31-beta.1 → 4.0.32

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 (35) hide show
  1. package/dist/cli/commands/traces.js +3 -1
  2. package/dist/cli/commands/traces.js.map +1 -1
  3. package/dist/index.js +1815 -1275
  4. package/dist/index.js.map +4 -4
  5. package/dist/metafile.json +1 -1
  6. package/package.json +1 -1
  7. package/packages/agent-trace-viewer/dist/index.d.ts +2 -2
  8. package/packages/agent-trace-viewer/dist/index.js +1 -1
  9. package/packages/agent-trace-viewer/dist/loader.d.ts +1 -0
  10. package/packages/agent-trace-viewer/dist/loader.js +90 -6
  11. package/packages/agent-trace-viewer/dist/run.d.ts +2 -0
  12. package/packages/agent-trace-viewer/dist/run.js +43 -11
  13. package/packages/agent-trace-viewer/dist/types.d.ts +9 -0
  14. package/packages/agent-traces/dist/collect.js +36 -8
  15. package/packages/agent-traces/dist/index-store/concurrency.d.ts +1 -0
  16. package/packages/agent-traces/dist/index-store/concurrency.js +16 -0
  17. package/packages/agent-traces/dist/index-store/head.d.ts +3 -0
  18. package/packages/agent-traces/dist/index-store/head.js +19 -0
  19. package/packages/agent-traces/dist/index-store/store.d.ts +45 -0
  20. package/packages/agent-traces/dist/index-store/store.js +263 -0
  21. package/packages/agent-traces/dist/index.d.ts +3 -1
  22. package/packages/agent-traces/dist/index.js +1 -0
  23. package/packages/agent-traces/dist/readers/claude.js +25 -6
  24. package/packages/agent-traces/dist/readers/pi.js +61 -10
  25. package/packages/agent-traces/dist/readers/poe-code.js +27 -9
  26. package/packages/agent-traces/dist/types.d.ts +18 -0
  27. package/packages/terminal-pilot/dist/cli.js +8 -14
  28. package/packages/terminal-pilot/dist/cli.js.map +2 -2
  29. package/packages/terminal-pilot/dist/testing/cli-repl.js +8 -14
  30. package/packages/terminal-pilot/dist/testing/cli-repl.js.map +2 -2
  31. package/packages/terminal-pilot/dist/testing/qa-cli.js +8 -14
  32. package/packages/terminal-pilot/dist/testing/qa-cli.js.map +2 -2
  33. package/packages/toolcraft/dist/cli.js +7 -1
  34. package/packages/toolcraft/dist/renderer.js +1 -14
  35. package/packages/toolcraft-openapi/dist/generate.js +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "4.0.31-beta.1",
3
+ "version": "4.0.32",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,4 +1,4 @@
1
- export { detectTraceFile, listTraces, loadSubagentSummaries, loadTrace, loadTraceFromFile, loadTraceTree } from "./loader.js";
1
+ export { defaultTraceIndexDir, detectTraceFile, listTraces, loadSubagentSummaries, loadTrace, loadTraceFromFile, loadTraceTree } from "./loader.js";
2
2
  export { computeContextBreakdown } from "./breakdown.js";
3
3
  export { CONTEXT_WINDOWS, DEFAULT_CONTEXT_WINDOW } from "./context.js";
4
4
  export { renderBreakdown, renderContextGauge, renderSubagents, renderTraceDetail, renderTraceLine } from "./render.js";
@@ -10,5 +10,5 @@ export { openTraceHtml } from "./open-html.js";
10
10
  export type { OpenTraceHtmlOptions } from "./open-html.js";
11
11
  export { runTraceViewer } from "./run.js";
12
12
  export type { RunTraceViewerOptions } from "./run.js";
13
- export type { ContextBreakdown, ContextBreakdownCategory, ContextBreakdownItem, ContextUsage, ListTracesOptions, LoadTraceOptions, LoadTraceTreeOptions, SubagentSummary, TraceTreeNode, TraceView } from "./types.js";
13
+ export type { ContextBreakdown, ContextBreakdownCategory, ContextBreakdownItem, ContextUsage, ListTracesOptions, LoadTraceOptions, LoadTraceTreeOptions, SubagentSummary, TraceIndexMode, TraceTreeNode, TraceView } from "./types.js";
14
14
  export type { AgentTraceFileSystem, AgentTraceSource, NormalizedTrace, NormalizedTraceTurn, SqliteTraceDatabase, SqliteTraceDatabaseFactory, TraceReference, TraceUsage } from "../../agent-traces/dist/index.js";
@@ -1,4 +1,4 @@
1
- export { detectTraceFile, listTraces, loadSubagentSummaries, loadTrace, loadTraceFromFile, loadTraceTree } from "./loader.js";
1
+ export { defaultTraceIndexDir, detectTraceFile, listTraces, loadSubagentSummaries, loadTrace, loadTraceFromFile, loadTraceTree } from "./loader.js";
2
2
  export { computeContextBreakdown } from "./breakdown.js";
3
3
  export { CONTEXT_WINDOWS, DEFAULT_CONTEXT_WINDOW } from "./context.js";
4
4
  export { renderBreakdown, renderContextGauge, renderSubagents, renderTraceDetail, renderTraceLine } from "./render.js";
@@ -1,5 +1,6 @@
1
1
  import { type AgentTraceSource, type TraceReference } from "../../agent-traces/dist/index.js";
2
2
  import type { ListTracesOptions, LoadTraceOptions, LoadTraceTreeOptions, SubagentSummary, TraceTreeNode, TraceView } from "./types.js";
3
+ export declare function defaultTraceIndexDir(): string;
3
4
  export declare function listTraces(options: ListTracesOptions): Promise<TraceReference[]>;
4
5
  export declare function loadTrace(reference: TraceReference, options: LoadTraceOptions): Promise<TraceView>;
5
6
  export declare function loadSubagentSummaries(view: TraceView, options: LoadTraceOptions): Promise<SubagentSummary[]>;
@@ -1,14 +1,16 @@
1
- import { traceReaders } from "@poe-code/agent-traces";
1
+ import path from "node:path";
2
+ import { openTraceIndex, traceReaders } from "@poe-code/agent-traces";
3
+ import { resolveCacheDir } from "@poe-code/cached-resource";
2
4
  import { UserError } from "@poe-code/user-error";
3
5
  import { computeContextBreakdown } from "./breakdown.js";
4
6
  import { computeContextUsage } from "./context.js";
5
7
  import { defaultTraceTokenCacheDir, readCachedBreakdown, traceFileIdentity, writeCachedBreakdown } from "./token-cache.js";
6
8
  const DEFAULT_TREE_MAX_DEPTH = 8;
7
9
  const DEFAULT_TREE_MAX_NODES = 50;
8
- export async function listTraces(options) {
9
- const readers = options.sources === undefined
10
- ? traceReaders
11
- : traceReaders.filter((reader) => options.sources?.includes(reader.id) ?? false);
10
+ export function defaultTraceIndexDir() {
11
+ return path.join(resolveCacheDir("poe-code"), "trace-index");
12
+ }
13
+ async function discoverWithReaders(readers, options) {
12
14
  const discovered = [];
13
15
  for (const reader of readers) {
14
16
  try {
@@ -25,9 +27,91 @@ export async function listTraces(options) {
25
27
  // Trace backends are optional; missing local stores should not hide other sources.
26
28
  }
27
29
  }
28
- const sorted = discovered.sort((left, right) => dateValue(right.updatedAt) - dateValue(left.updatedAt));
30
+ return discovered;
31
+ }
32
+ function assembleReferences(options, ...groups) {
33
+ const sorted = groups
34
+ .flat()
35
+ .sort((left, right) => dateValue(right.updatedAt) - dateValue(left.updatedAt));
29
36
  return sorted.slice(0, options.limit ?? 50);
30
37
  }
38
+ function isIndexable(reader) {
39
+ return reader.scan !== undefined && reader.readHeadMetadata !== undefined;
40
+ }
41
+ export async function listTraces(options) {
42
+ const readers = options.sources === undefined
43
+ ? traceReaders
44
+ : traceReaders.filter((reader) => options.sources?.includes(reader.id) ?? false);
45
+ const mode = options.index ?? "off";
46
+ const indexable = readers.filter(isIndexable);
47
+ let index;
48
+ if (mode !== "off" && indexable.length > 0) {
49
+ try {
50
+ index = await openTraceIndex({
51
+ dir: options.indexDir ?? defaultTraceIndexDir(),
52
+ fs: options.fs
53
+ });
54
+ }
55
+ catch {
56
+ // An unusable index cache falls back to direct discovery.
57
+ }
58
+ }
59
+ if (index === undefined) {
60
+ const references = assembleReferences(options, await discoverWithReaders(readers, options));
61
+ if (mode === "background") {
62
+ queueMicrotask(() => options.onIndexUpdate?.(references));
63
+ }
64
+ return references;
65
+ }
66
+ const direct = readers.filter((reader) => !isIndexable(reader));
67
+ const runSync = async () => {
68
+ const syncOptions = {
69
+ readers: indexable,
70
+ homeDir: options.homeDir,
71
+ ...(options.onIndexProgress ? { onProgress: options.onIndexProgress } : {})
72
+ };
73
+ if (options.rebuildIndex === true) {
74
+ await index.rebuild(syncOptions);
75
+ }
76
+ else {
77
+ await index.sync(syncOptions);
78
+ }
79
+ };
80
+ const queryIndexed = () => index
81
+ .query({
82
+ cwd: options.cwd,
83
+ allWorkspaces: options.allWorkspaces,
84
+ since: options.since,
85
+ sources: indexable.map((reader) => reader.id),
86
+ limit: options.limit ?? 50
87
+ })
88
+ .catch(() => []);
89
+ if (mode === "sync") {
90
+ try {
91
+ await runSync();
92
+ }
93
+ catch {
94
+ return assembleReferences(options, await discoverWithReaders(readers, options));
95
+ }
96
+ const [indexed, directRefs] = await Promise.all([
97
+ queryIndexed(),
98
+ discoverWithReaders(direct, options)
99
+ ]);
100
+ return assembleReferences(options, indexed, directRefs);
101
+ }
102
+ const [indexed, directRefs] = await Promise.all([
103
+ queryIndexed(),
104
+ discoverWithReaders(direct, options)
105
+ ]);
106
+ const initial = assembleReferences(options, indexed, directRefs);
107
+ void runSync()
108
+ .then(async () => assembleReferences(options, await queryIndexed(), await discoverWithReaders(direct, options)))
109
+ .catch(() => initial)
110
+ .then((updated) => {
111
+ options.onIndexUpdate?.(updated);
112
+ });
113
+ return initial;
114
+ }
31
115
  export async function loadTrace(reference, options) {
32
116
  const reader = traceReaders.find((candidate) => candidate.id === reference.source);
33
117
  if (reader === undefined) {
@@ -16,6 +16,8 @@ export interface RunTraceViewerOptions {
16
16
  openExternal?: (target: string) => Promise<void>;
17
17
  tmpDir?: string;
18
18
  output?: WritableOutput;
19
+ indexDir?: string;
20
+ rebuildIndex?: boolean;
19
21
  }
20
22
  interface WritableOutput {
21
23
  write(chunk: string | Uint8Array): unknown;
@@ -29,21 +29,24 @@ export async function runTraceViewer(options) {
29
29
  writeLine(output, await renderTraceDetail(view, subagents));
30
30
  return;
31
31
  }
32
- const discover = () => listTraces({
32
+ const listOptions = {
33
33
  cwd: options.cwd,
34
34
  homeDir: options.homeDir,
35
35
  fs: options.fs,
36
36
  sources: options.sources,
37
37
  allWorkspaces: options.allWorkspaces,
38
38
  since: options.since,
39
- limit: options.limit ?? Number.POSITIVE_INFINITY
40
- });
41
- const references = await discover();
42
- if (references.length === 0) {
43
- writeLine(output, "No traces found");
44
- return;
45
- }
39
+ limit: options.limit ?? Number.POSITIVE_INFINITY,
40
+ ...(options.indexDir !== undefined ? { indexDir: options.indexDir } : {}),
41
+ ...(options.rebuildIndex === true ? { rebuildIndex: true } : {})
42
+ };
43
+ const discover = () => listTraces({ ...listOptions, index: "sync" });
46
44
  if (options.json || options.assumeYes || process.stdin.isTTY !== true) {
45
+ const references = await discover();
46
+ if (references.length === 0) {
47
+ writeLine(output, "No traces found");
48
+ return;
49
+ }
47
50
  if (options.json) {
48
51
  const listed = options.fullTitles === true ? references : references.map(withTruncatedTitle);
49
52
  writeLine(output, JSON.stringify(listed, null, 2));
@@ -52,9 +55,26 @@ export async function runTraceViewer(options) {
52
55
  writeLine(output, renderTraceReferenceTable(references));
53
56
  return;
54
57
  }
58
+ let resolveRevalidated;
59
+ const revalidated = new Promise((resolve) => {
60
+ resolveRevalidated = resolve;
61
+ });
62
+ const stale = await listTraces({
63
+ ...listOptions,
64
+ index: "background",
65
+ onIndexUpdate: resolveRevalidated
66
+ });
67
+ const references = stale.length > 0
68
+ ? stale
69
+ : await withSpinner({ message: "Indexing traces...", fn: async () => revalidated });
70
+ if (references.length === 0) {
71
+ writeLine(output, "No traces found");
72
+ return;
73
+ }
55
74
  await runExplorer(buildTraceExplorerConfig({
56
75
  title: "Agent traces",
57
76
  references,
77
+ ...(references === stale ? { revalidated } : {}),
58
78
  fs: options.fs,
59
79
  output,
60
80
  openExternal: options.openExternal,
@@ -116,8 +136,7 @@ function compactWhitespace(value) {
116
136
  }
117
137
  function buildTraceExplorerConfig(options) {
118
138
  const state = createExplorerState(options.references);
119
- async function refresh() {
120
- const references = await options.onRefresh();
139
+ function applyReferences(references) {
121
140
  const next = createExplorerState(references);
122
141
  state.references = next.references;
123
142
  state.rows = next.rows;
@@ -125,6 +144,18 @@ function buildTraceExplorerConfig(options) {
125
144
  state.childrenByRowId = next.childrenByRowId;
126
145
  state.detailByRowId = next.detailByRowId;
127
146
  }
147
+ async function refresh() {
148
+ applyReferences(await options.onRefresh());
149
+ }
150
+ let revalidation = options.revalidated;
151
+ async function rows() {
152
+ if (revalidation !== undefined) {
153
+ const pending = revalidation;
154
+ revalidation = undefined;
155
+ applyReferences(await pending);
156
+ }
157
+ return state.rows;
158
+ }
128
159
  const actions = [
129
160
  {
130
161
  id: "open",
@@ -228,8 +259,9 @@ function buildTraceExplorerConfig(options) {
228
259
  ];
229
260
  return normalizeExplorerConfig({
230
261
  title: options.title,
262
+ initialRows: state.rows,
231
263
  panes: [
232
- { id: "traces", kind: "list", title: options.title, rows: async () => state.rows, emptyHint: "No traces found", multiSelect: false },
264
+ { id: "traces", kind: "list", title: options.title, rows, emptyHint: "No traces found", multiSelect: false },
233
265
  {
234
266
  id: "preview",
235
267
  kind: "detail",
@@ -1,4 +1,5 @@
1
1
  import type { AgentTraceFileSystem, AgentTraceSource, NormalizedTrace, SqliteTraceDatabaseFactory, TraceReference } from "../../agent-traces/dist/index.js";
2
+ export type TraceIndexMode = "sync" | "background" | "off";
2
3
  export interface ListTracesOptions {
3
4
  cwd: string;
4
5
  homeDir: string;
@@ -8,6 +9,14 @@ export interface ListTracesOptions {
8
9
  since?: Date;
9
10
  limit?: number;
10
11
  sqlite?: SqliteTraceDatabaseFactory;
12
+ index?: TraceIndexMode;
13
+ indexDir?: string;
14
+ rebuildIndex?: boolean;
15
+ onIndexProgress?: (progress: {
16
+ scannedDirs: number;
17
+ headReads: number;
18
+ }) => void;
19
+ onIndexUpdate?: (references: TraceReference[]) => void;
11
20
  }
12
21
  export interface LoadTraceOptions {
13
22
  fs: AgentTraceFileSystem;
@@ -1,5 +1,6 @@
1
1
  import { promises as nodeFs } from "node:fs";
2
2
  import os from "node:os";
3
+ import { openTraceIndex } from "./index-store/store.js";
3
4
  import { traceReaders } from "./readers/index.js";
4
5
  const DEFAULT_SOURCES = traceReaders.map((reader) => reader.id);
5
6
  function compareRecordsNewestFirst(first, second) {
@@ -51,19 +52,46 @@ export async function collectHumanPromptsFromReaders(readers, options = {}) {
51
52
  const records = [];
52
53
  const seenRecords = new Set();
53
54
  let traceCount = 0;
55
+ let indexedReferences;
56
+ if (options.indexDir !== undefined) {
57
+ try {
58
+ const indexable = sources
59
+ .map((source) => readerById.get(source))
60
+ .filter((reader) => reader !== undefined &&
61
+ reader.scan !== undefined &&
62
+ reader.readHeadMetadata !== undefined);
63
+ const index = await openTraceIndex({ dir: options.indexDir, fs });
64
+ await index.sync({ readers: indexable, homeDir });
65
+ const references = await index.query({
66
+ cwd,
67
+ allWorkspaces: options.allWorkspaces,
68
+ since: options.since,
69
+ sources: indexable.map((reader) => reader.id),
70
+ limit: Number.POSITIVE_INFINITY
71
+ });
72
+ indexedReferences = new Map(indexable.map((reader) => [reader.id, []]));
73
+ for (const reference of references) {
74
+ indexedReferences.get(reference.source)?.push(reference);
75
+ }
76
+ }
77
+ catch {
78
+ indexedReferences = undefined;
79
+ }
80
+ }
54
81
  for (const source of sources) {
55
82
  const reader = readerById.get(source);
56
83
  if (!reader) {
57
84
  throw new Error(`Unsupported trace source: ${source}`);
58
85
  }
59
- const references = await reader.discover({
60
- cwd,
61
- homeDir,
62
- since: options.since,
63
- allWorkspaces: options.allWorkspaces,
64
- fs,
65
- sqlite: options.sqlite
66
- });
86
+ const references = indexedReferences?.get(source) ??
87
+ (await reader.discover({
88
+ cwd,
89
+ homeDir,
90
+ since: options.since,
91
+ allWorkspaces: options.allWorkspaces,
92
+ fs,
93
+ sqlite: options.sqlite
94
+ }));
67
95
  traceCount += references.length;
68
96
  for (const reference of references) {
69
97
  const trace = await reader.read(reference, { fs });
@@ -0,0 +1 @@
1
+ export declare function mapConcurrent<T, R>(items: readonly T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
@@ -0,0 +1,16 @@
1
+ export async function mapConcurrent(items, limit, fn) {
2
+ const results = new Array(items.length);
3
+ let next = 0;
4
+ const worker = async () => {
5
+ while (true) {
6
+ const index = next;
7
+ next += 1;
8
+ if (index >= items.length) {
9
+ return;
10
+ }
11
+ results[index] = await fn(items[index], index);
12
+ }
13
+ };
14
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));
15
+ return results;
16
+ }
@@ -0,0 +1,3 @@
1
+ import type { AgentTraceFileSystem } from "../types.js";
2
+ export declare const DEFAULT_HEAD_BYTES = 65536;
3
+ export declare function readHead(fs: AgentTraceFileSystem, filePath: string, maxBytes?: number): Promise<string>;
@@ -0,0 +1,19 @@
1
+ export const DEFAULT_HEAD_BYTES = 65_536;
2
+ function supportsOpen(fs) {
3
+ return typeof fs.open === "function";
4
+ }
5
+ export async function readHead(fs, filePath, maxBytes = DEFAULT_HEAD_BYTES) {
6
+ if (supportsOpen(fs)) {
7
+ const handle = await fs.open(filePath, "r");
8
+ try {
9
+ const buffer = Buffer.alloc(maxBytes);
10
+ const { bytesRead } = await handle.read(buffer, 0, maxBytes, 0);
11
+ return buffer.toString("utf8", 0, bytesRead);
12
+ }
13
+ finally {
14
+ await handle.close();
15
+ }
16
+ }
17
+ const contents = await fs.readFile(filePath, "utf8");
18
+ return contents.length > maxBytes ? contents.slice(0, maxBytes) : contents;
19
+ }
@@ -0,0 +1,45 @@
1
+ import type { AgentTraceFileSystem, AgentTraceSource, TraceReader, TraceReference } from "../types.js";
2
+ export interface TraceIndexRecord {
3
+ path: string;
4
+ source: AgentTraceSource;
5
+ id: string;
6
+ cwd?: string;
7
+ title?: string;
8
+ metadata?: Record<string, unknown>;
9
+ updatedAtMs: number;
10
+ mtimeMs: number;
11
+ size: number;
12
+ }
13
+ export interface TraceIndexSyncOptions {
14
+ readers: TraceReader[];
15
+ homeDir: string;
16
+ now?: () => number;
17
+ onProgress?: (progress: {
18
+ scannedDirs: number;
19
+ headReads: number;
20
+ }) => void;
21
+ }
22
+ export interface TraceIndexSyncStats {
23
+ scannedDirs: number;
24
+ statted: number;
25
+ headReads: number;
26
+ added: number;
27
+ updated: number;
28
+ removed: number;
29
+ }
30
+ export interface TraceIndexQueryOptions {
31
+ cwd?: string;
32
+ allWorkspaces?: boolean;
33
+ since?: Date;
34
+ sources?: AgentTraceSource[];
35
+ limit: number;
36
+ }
37
+ export interface TraceIndex {
38
+ sync(options: TraceIndexSyncOptions): Promise<TraceIndexSyncStats>;
39
+ query(options: TraceIndexQueryOptions): Promise<TraceReference[]>;
40
+ rebuild(options: TraceIndexSyncOptions): Promise<TraceIndexSyncStats>;
41
+ }
42
+ export declare function openTraceIndex(options: {
43
+ dir: string;
44
+ fs: AgentTraceFileSystem;
45
+ }): Promise<TraceIndex>;