@danypops/pi-lector 0.2.2 → 0.4.0

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.
@@ -4,6 +4,7 @@ import type {
4
4
  DocumentSymbolEntry,
5
5
  Hover,
6
6
  IncomingCall,
7
+ IntelligenceProvenance,
7
8
  JobSnapshot,
8
9
  OutgoingCall,
9
10
  PopulateSymbolGraphResult,
@@ -159,20 +160,29 @@ function formatCallHierarchyEntry(entry: { kind: string; name: string; location:
159
160
  return `${kind} ${name} -- ${location}`;
160
161
  }
161
162
 
162
- export function formatPrepareCallHierarchyCall(args: { path?: unknown; line?: unknown; character?: unknown }, theme: LectorTheme): string {
163
- return formatPositionalCall("prepare_call_hierarchy", args, theme);
163
+ export type CallHierarchyDirection = "prepare" | "incoming" | "outgoing";
164
+
165
+ // A real discriminated union, not one shape with optional fields -- lets formatCallHierarchyResult
166
+ // narrow `items`/`calls` per branch without an unsafe assertion.
167
+ export type CallHierarchyToolDetails =
168
+ | { readonly direction: "prepare"; readonly items: readonly CallHierarchyEntry[]; readonly provenance?: IntelligenceProvenance }
169
+ | { readonly direction: "incoming"; readonly calls: readonly IncomingCall[]; readonly provenance?: IntelligenceProvenance }
170
+ | { readonly direction: "outgoing"; readonly calls: readonly OutgoingCall[]; readonly provenance?: IntelligenceProvenance };
171
+
172
+ export function formatCallHierarchyCall(args: { direction?: unknown; path?: unknown; line?: unknown; character?: unknown }, theme: LectorTheme): string {
173
+ const direction = typeof args.direction === "string" ? args.direction : "";
174
+ const path = typeof args.path === "string" ? args.path : "";
175
+ const line = typeof args.line === "number" ? args.line : "?";
176
+ const character = typeof args.character === "number" ? args.character : "?";
177
+ return `${theme.fg("toolTitle", theme.bold("call_hierarchy"))} ${theme.fg("muted", direction)} ${theme.fg("accent", `${path}:${line}:${character}`)}`;
164
178
  }
165
179
 
166
- export function formatPrepareCallHierarchyResult(items: readonly CallHierarchyEntry[] | undefined, theme: LectorTheme): string {
180
+ function formatPrepareCallHierarchyResult(items: readonly CallHierarchyEntry[] | undefined, theme: LectorTheme): string {
167
181
  if (!items || items.length === 0) return theme.fg("dim", "No call-hierarchy root at this position.");
168
182
  return items.map((item) => formatCallHierarchyEntry(item, theme)).join("\n");
169
183
  }
170
184
 
171
- export function formatIncomingCallsCall(args: { path?: unknown; line?: unknown; character?: unknown }, theme: LectorTheme): string {
172
- return formatPositionalCall("incoming_calls", args, theme);
173
- }
174
-
175
- export function formatIncomingCallsResult(calls: readonly IncomingCall[] | undefined, expanded: boolean, theme: LectorTheme): string {
185
+ function formatIncomingCallsResult(calls: readonly IncomingCall[] | undefined, expanded: boolean, theme: LectorTheme): string {
176
186
  if (!calls || calls.length === 0) return theme.fg("dim", "No incoming calls found.");
177
187
 
178
188
  const displayCount = expanded ? calls.length : Math.min(calls.length, DEFAULT_VISIBLE_CALLS);
@@ -184,11 +194,7 @@ export function formatIncomingCallsResult(calls: readonly IncomingCall[] | undef
184
194
  return lines.join("\n");
185
195
  }
186
196
 
187
- export function formatOutgoingCallsCall(args: { path?: unknown; line?: unknown; character?: unknown }, theme: LectorTheme): string {
188
- return formatPositionalCall("outgoing_calls", args, theme);
189
- }
190
-
191
- export function formatOutgoingCallsResult(calls: readonly OutgoingCall[] | undefined, expanded: boolean, theme: LectorTheme): string {
197
+ function formatOutgoingCallsResult(calls: readonly OutgoingCall[] | undefined, expanded: boolean, theme: LectorTheme): string {
192
198
  if (!calls || calls.length === 0) return theme.fg("dim", "No outgoing calls found.");
193
199
 
194
200
  const displayCount = expanded ? calls.length : Math.min(calls.length, DEFAULT_VISIBLE_CALLS);
@@ -200,6 +206,13 @@ export function formatOutgoingCallsResult(calls: readonly OutgoingCall[] | undef
200
206
  return lines.join("\n");
201
207
  }
202
208
 
209
+ export function formatCallHierarchyResult(details: CallHierarchyToolDetails | undefined, expanded: boolean, theme: LectorTheme): string {
210
+ if (!details) return theme.fg("dim", "No result.");
211
+ if (details.direction === "prepare") return formatPrepareCallHierarchyResult(details.items, theme);
212
+ if (details.direction === "incoming") return formatIncomingCallsResult(details.calls, expanded, theme);
213
+ return formatOutgoingCallsResult(details.calls, expanded, theme);
214
+ }
215
+
203
216
  export function formatPopulateSymbolGraphCall(args: { path?: unknown; maxFiles?: unknown; maxSymbolsPerFile?: unknown }, theme: LectorTheme): string {
204
217
  const path = typeof args.path === "string" ? args.path : "";
205
218
  return `${theme.fg("toolTitle", theme.bold("populate_symbol_graph"))} ${theme.fg("accent", path)}`;
@@ -6,12 +6,30 @@ const DEFAULT_VISIBLE_FILES = 20;
6
6
  const DEFAULT_VISIBLE_COMMITS = 10;
7
7
  const DEFAULT_VISIBLE_DIFF_LINES = 60;
8
8
 
9
- export function formatGitStatusCall(args: { directory?: unknown }, theme: LectorTheme): string {
9
+ export type GitAction = "status" | "log" | "diff";
10
+
11
+ export interface GitToolDetails {
12
+ readonly action: GitAction;
13
+ readonly summary?: GitStatusSummary;
14
+ readonly entries?: readonly GitLogEntry[];
15
+ readonly result?: GitDiffResult;
16
+ }
17
+
18
+ export function formatGitCall(args: { action?: unknown; directory?: unknown; ref?: unknown }, theme: LectorTheme): string {
19
+ const action = typeof args.action === "string" ? args.action : "";
10
20
  const directory = typeof args.directory === "string" ? args.directory : "";
11
- return `${theme.fg("toolTitle", theme.bold("git_status"))} ${theme.fg("accent", directory)}`;
21
+ const ref = typeof args.ref === "string" ? ` ${args.ref}` : "";
22
+ return `${theme.fg("toolTitle", theme.bold("git"))} ${theme.fg("muted", action)} ${theme.fg("accent", directory)}${ref}`;
12
23
  }
13
24
 
14
- export function formatGitStatusResult(summary: GitStatusSummary | undefined, expanded: boolean, theme: LectorTheme): string {
25
+ export function formatGitResult(details: GitToolDetails | undefined, expanded: boolean, theme: LectorTheme): string {
26
+ if (!details) return theme.fg("dim", "No result.");
27
+ if (details.action === "status") return formatGitStatusResult(details.summary, expanded, theme);
28
+ if (details.action === "log") return formatGitLogResult(details.entries, expanded, theme);
29
+ return formatGitDiffResult(details.result, expanded, theme);
30
+ }
31
+
32
+ function formatGitStatusResult(summary: GitStatusSummary | undefined, expanded: boolean, theme: LectorTheme): string {
15
33
  if (!summary) return theme.fg("dim", "No status available.");
16
34
  const branch = summary.current ?? "(detached)";
17
35
  const tracking = summary.tracking ? `, tracking ${summary.tracking} (+${summary.ahead}/-${summary.behind})` : "";
@@ -30,12 +48,7 @@ export function formatGitStatusResult(summary: GitStatusSummary | undefined, exp
30
48
  return lines.join("\n");
31
49
  }
32
50
 
33
- export function formatGitLogCall(args: { directory?: unknown; maxCount?: unknown }, theme: LectorTheme): string {
34
- const directory = typeof args.directory === "string" ? args.directory : "";
35
- return `${theme.fg("toolTitle", theme.bold("git_log"))} ${theme.fg("accent", directory)}`;
36
- }
37
-
38
- export function formatGitLogResult(entries: readonly GitLogEntry[] | undefined, expanded: boolean, theme: LectorTheme): string {
51
+ function formatGitLogResult(entries: readonly GitLogEntry[] | undefined, expanded: boolean, theme: LectorTheme): string {
39
52
  if (!entries || entries.length === 0) return theme.fg("dim", "No commits found.");
40
53
  const displayCount = expanded ? entries.length : Math.min(DEFAULT_VISIBLE_COMMITS, entries.length);
41
54
  const lines = entries
@@ -46,13 +59,7 @@ export function formatGitLogResult(entries: readonly GitLogEntry[] | undefined,
46
59
  return lines.join("\n");
47
60
  }
48
61
 
49
- export function formatGitDiffCall(args: { directory?: unknown; ref?: unknown }, theme: LectorTheme): string {
50
- const directory = typeof args.directory === "string" ? args.directory : "";
51
- const ref = typeof args.ref === "string" ? ` ${args.ref}` : "";
52
- return `${theme.fg("toolTitle", theme.bold("git_diff"))} ${theme.fg("accent", directory)}${ref}`;
53
- }
54
-
55
- export function formatGitDiffResult(result: GitDiffResult | undefined, expanded: boolean, theme: LectorTheme): string {
62
+ function formatGitDiffResult(result: GitDiffResult | undefined, expanded: boolean, theme: LectorTheme): string {
56
63
  if (!result || result.diff.length === 0) return theme.fg("dim", "No differences.");
57
64
  const lines = result.diff.split("\n");
58
65
  const displayCount = expanded ? lines.length : Math.min(DEFAULT_VISIBLE_DIFF_LINES, lines.length);