@mrclrchtr/supi-code-intelligence 4.10.0 → 5.0.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.
- package/README.md +2 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
- package/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
- package/node_modules/@mrclrchtr/supi-core/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
- package/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
- package/node_modules/@mrclrchtr/supi-lsp/README.md +80 -5
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
- package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
- package/node_modules/@mrclrchtr/supi-lsp/package.json +7 -6
- package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +10 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +206 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +78 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-collection.ts +114 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-evidence.ts +372 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-host.ts +14 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-pull.ts +62 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +491 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-request.ts +9 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +71 -11
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-waiters.ts +206 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +365 -297
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-state.ts +52 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-sync.ts +185 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client-file-state.ts +25 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +467 -115
- package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +161 -33
- package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +10 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/config/defaults.json +1 -1
- package/node_modules/@mrclrchtr/supi-lsp/src/debug-telemetry.ts +45 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +38 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-client-state.ts +79 -9
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +13 -4
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +300 -24
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +5 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +464 -96
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-refactor-provider.ts +130 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +45 -329
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/refactor-planning.ts +57 -120
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-edit-normalizer.ts +320 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-symbol-mapper.ts +207 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/readiness.ts +72 -2
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +151 -26
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostic-surface.ts +40 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +50 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +136 -120
- package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-transition-debug.ts +49 -0
- package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +102 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +17 -7
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/LICENSE +21 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/README.md +258 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/babel.cjs +257 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/jiti.cjs +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-cli.mjs +34 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-hooks.mjs +124 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-native.mjs +121 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.d.mts +1 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.mjs +4 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-static.mjs +23 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.cjs +30 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.cts +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.mts +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.mjs +29 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/types.d.ts +420 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/package.json +146 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +6 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +0 -9
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +0 -8
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +16 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +65 -87
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +47 -95
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-timing.ts +147 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client-lifecycle.ts +39 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client.ts +561 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-message-size.ts +24 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-protocol.ts +452 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +4 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +12 -4
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/exports.ts +4 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/imports.ts +4 -2
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/node-at.ts +5 -3
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +33 -12
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/blocking-test-bootstrap.mjs +34 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/bootstrap.mjs +8 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store-helpers.ts +23 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store.ts +400 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/request-control.ts +48 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-parser-helpers.ts +24 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-query-helpers.ts +43 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime.ts +421 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/service.ts +116 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/worker-main.ts +201 -0
- package/package.json +5 -5
- package/src/analysis/health/diagnostics.ts +236 -24
- package/src/analysis/health/recovery.ts +6 -2
- package/src/analysis/provider.ts +58 -0
- package/src/analysis/readiness.ts +30 -9
- package/src/analysis/refactor/apply.ts +45 -1
- package/src/analysis/refactor/mutation-authority.ts +143 -0
- package/src/analysis/relations/callees.ts +9 -1
- package/src/analysis/relations/types.ts +5 -2
- package/src/analysis/search/ast-scan-timing.ts +9 -2
- package/src/analysis/search/ast-scan.ts +1 -1
- package/src/analysis/search/deadline.ts +2 -2
- package/src/analysis/search/pattern-analysis.ts +46 -32
- package/src/analysis/search/pattern.ts +12 -2
- package/src/analysis/target/anchored.ts +20 -11
- package/src/analysis/target/file.ts +18 -11
- package/src/analysis/target/identity.ts +19 -3
- package/src/analysis/target/symbol.ts +36 -15
- package/src/api.ts +4 -0
- package/src/diagnostics/evidence.ts +51 -0
- package/src/session/capability-adapter.ts +12 -3
- package/src/session/find-workflow.ts +17 -7
- package/src/session/graph/collect.ts +18 -2
- package/src/session/graph-workflow.ts +19 -12
- package/src/session/health-refresh.ts +148 -0
- package/src/session/health-types.ts +37 -15
- package/src/session/health-workflow.ts +37 -39
- package/src/session/inspect/collect.ts +20 -3
- package/src/session/inspect-workflow.ts +10 -5
- package/src/session/orientation/collect.ts +10 -1
- package/src/session/orientation/context-facts.ts +3 -1
- package/src/session/orientation/context-sections.ts +20 -7
- package/src/session/orientation/gather.ts +17 -11
- package/src/session/orientation-types.ts +2 -1
- package/src/session/orientation-workflow.ts +15 -8
- package/src/session/refactor-plans.ts +2 -0
- package/src/session/refactor-workflow.ts +59 -14
- package/src/session/session.ts +4 -1
- package/src/session/target-workflow.ts +54 -23
- package/src/session/workflow-control.ts +7 -3
- package/src/substrate/lsp/lifecycle.ts +26 -46
- package/src/substrate/lsp/maintenance.ts +199 -25
- package/src/substrate/lsp/state.ts +2 -2
- package/src/substrate/workspace-provider-host.ts +25 -3
- package/src/tool/find/execute.ts +7 -1
- package/src/tool/find/render.ts +20 -3
- package/src/tool/find/tui.ts +23 -21
- package/src/tool/graph/execute.ts +23 -3
- package/src/tool/graph/tui.ts +59 -46
- package/src/tool/health/execute.ts +7 -2
- package/src/tool/health/markdown.ts +56 -14
- package/src/tool/health/refresh-status.ts +105 -0
- package/src/tool/health/tui.ts +95 -98
- package/src/tool/infra/workflow-control.ts +8 -0
- package/src/tool/inspect/execute.ts +7 -1
- package/src/tool/inspect/tui.ts +26 -18
- package/src/tool/orientation/execute.ts +21 -3
- package/src/tool/orientation/tui.ts +51 -35
- package/src/tool/refactor-apply/execute.ts +3 -0
- package/src/tool/refactor-apply/tui.ts +43 -25
- package/src/tool/refactor-plan/execute.ts +4 -0
- package/src/tool/refactor-plan/tui.ts +33 -20
- package/src/tool/register.ts +127 -22
- package/src/tool/resolve/execute.ts +18 -1
- package/src/tool/resolve/tui.ts +42 -24
- package/src/tool/result/display.ts +107 -0
- package/src/tool/result/errors.ts +20 -17
- package/src/tool/result/find.ts +52 -8
- package/src/tool/result/graph.ts +44 -1
- package/src/tool/result/health.ts +53 -1
- package/src/tool/result/inspect.ts +113 -1
- package/src/tool/result/orientation.ts +66 -14
- package/src/tool/result/refactor.ts +36 -4
- package/src/tool/result/resolve.ts +44 -7
- package/src/tool/result/types.ts +20 -0
- package/src/types/execution.ts +18 -5
- package/src/types/index.ts +8 -1
- package/src/ui/status-command.ts +5 -3
- package/src/ui/status-overlay.ts +4 -0
- package/src/ui/tui/common.ts +108 -10
- package/src/ui/tui/display.ts +48 -0
- package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime.ts +0 -351
|
@@ -3,7 +3,8 @@ import { createEvidenceList, type EvidenceList } from "../../analysis/evidence.t
|
|
|
3
3
|
import type { ApplyResult } from "../../analysis/refactor/apply.ts";
|
|
4
4
|
import type { RefactorPlan } from "../../session/refactor-plans.ts";
|
|
5
5
|
import { assembledNextQueries, assembleToolResult, type ToolResultAssembly } from "./assembly.ts";
|
|
6
|
-
import
|
|
6
|
+
import { createToolDisplaySection } from "./display.ts";
|
|
7
|
+
import type { SearchDetails, ToolDisplaySection } from "./types.ts";
|
|
7
8
|
|
|
8
9
|
export interface RefactorPlanAssemblyData {
|
|
9
10
|
readonly plan: Readonly<RefactorPlan>;
|
|
@@ -14,6 +15,7 @@ export interface RefactorPlanAssemblyData {
|
|
|
14
15
|
export interface RefactorPlanResultAssembly {
|
|
15
16
|
readonly assembled: ToolResultAssembly<RefactorPlanAssemblyData>;
|
|
16
17
|
readonly details: SearchDetails;
|
|
18
|
+
readonly displaySections: readonly ToolDisplaySection[];
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export interface RefactorApplyAssemblyData {
|
|
@@ -24,6 +26,13 @@ export interface RefactorApplyAssemblyData {
|
|
|
24
26
|
export interface RefactorApplyResultAssembly {
|
|
25
27
|
readonly assembled: ToolResultAssembly<RefactorApplyAssemblyData>;
|
|
26
28
|
readonly details: SearchDetails;
|
|
29
|
+
readonly displaySections: readonly ToolDisplaySection[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function formatEdit(edit: FileEdit): string {
|
|
33
|
+
const range = edit.range;
|
|
34
|
+
const replacement = edit.newText.replace(/\n/g, " ↵ ");
|
|
35
|
+
return `${edit.file} L${range.start.line + 1}:${range.start.character + 1} → L${range.end.line + 1}:${range.end.character + 1}: ${replacement}`;
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
/** Assemble a bounded refactor plan and all facts needed by its renderers. */
|
|
@@ -59,6 +68,17 @@ export function assembleRefactorPlanDetails(
|
|
|
59
68
|
|
|
60
69
|
return {
|
|
61
70
|
assembled,
|
|
71
|
+
displaySections: [
|
|
72
|
+
createToolDisplaySection({
|
|
73
|
+
key: "refactor.edits",
|
|
74
|
+
title: "Proposed edits",
|
|
75
|
+
items: edits.items,
|
|
76
|
+
totalCount: edits.metadata.totalCount,
|
|
77
|
+
omittedCount: edits.metadata.omittedCount,
|
|
78
|
+
partialReason: edits.metadata.partialReason,
|
|
79
|
+
format: formatEdit,
|
|
80
|
+
}),
|
|
81
|
+
],
|
|
62
82
|
details: {
|
|
63
83
|
confidence: assembled.confidence,
|
|
64
84
|
scope: null,
|
|
@@ -98,8 +118,22 @@ export function assembleRefactorApplyDetails(
|
|
|
98
118
|
provenance,
|
|
99
119
|
});
|
|
100
120
|
|
|
121
|
+
const changedFiles = [...new Set(plan.edits.edits.map((edit) => edit.file))];
|
|
122
|
+
|
|
101
123
|
return {
|
|
102
124
|
assembled,
|
|
125
|
+
displaySections:
|
|
126
|
+
applyResult.kind === "applied"
|
|
127
|
+
? [
|
|
128
|
+
createToolDisplaySection({
|
|
129
|
+
key: "refactor.changedFiles",
|
|
130
|
+
title: "Changed files",
|
|
131
|
+
items: changedFiles,
|
|
132
|
+
totalCount: changedFiles.length,
|
|
133
|
+
format: (file) => file,
|
|
134
|
+
}),
|
|
135
|
+
]
|
|
136
|
+
: [],
|
|
103
137
|
details: {
|
|
104
138
|
confidence: assembled.confidence,
|
|
105
139
|
scope: null,
|
|
@@ -107,9 +141,7 @@ export function assembleRefactorApplyDetails(
|
|
|
107
141
|
omittedCount: assembled.totals.omittedCount,
|
|
108
142
|
evidenceLists: [...assembled.evidenceLists],
|
|
109
143
|
nextQueries: assembledNextQueries(assembled),
|
|
110
|
-
...(applyResult.kind === "applied"
|
|
111
|
-
? { changedFiles: [...new Set(plan.edits.edits.map((edit) => edit.file))] }
|
|
112
|
-
: {}),
|
|
144
|
+
...(applyResult.kind === "applied" ? { changedFiles } : {}),
|
|
113
145
|
},
|
|
114
146
|
};
|
|
115
147
|
}
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
type ResultProvenance,
|
|
11
11
|
type ToolResultAssembly,
|
|
12
12
|
} from "./assembly.ts";
|
|
13
|
-
import
|
|
13
|
+
import { createToolDisplaySection } from "./display.ts";
|
|
14
|
+
import type { ResolveDetails, ToolDisplaySection } from "./types.ts";
|
|
14
15
|
|
|
15
16
|
/** Presentation-neutral assembled code_resolve result. */
|
|
16
17
|
export interface ResolveResultAssembly {
|
|
@@ -18,6 +19,7 @@ export interface ResolveResultAssembly {
|
|
|
18
19
|
readonly cwd: string;
|
|
19
20
|
readonly assembled: ToolResultAssembly<TargetWorkflowOutcome>;
|
|
20
21
|
readonly details: ResolveDetails;
|
|
22
|
+
readonly displaySections: readonly ToolDisplaySection[];
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
interface ResolveProjection {
|
|
@@ -56,16 +58,19 @@ export function assembleResolveResult(
|
|
|
56
58
|
provenance,
|
|
57
59
|
});
|
|
58
60
|
|
|
61
|
+
const details = {
|
|
62
|
+
...projection.details,
|
|
63
|
+
omittedCount: assembled.totals.omittedCount,
|
|
64
|
+
evidenceLists: [...assembled.evidenceLists],
|
|
65
|
+
nextQueries: assembledNextQueries(assembled),
|
|
66
|
+
};
|
|
67
|
+
|
|
59
68
|
return Object.freeze({
|
|
60
69
|
outcome,
|
|
61
70
|
cwd,
|
|
62
71
|
assembled,
|
|
63
|
-
details
|
|
64
|
-
|
|
65
|
-
omittedCount: assembled.totals.omittedCount,
|
|
66
|
-
evidenceLists: [...assembled.evidenceLists],
|
|
67
|
-
nextQueries: assembledNextQueries(assembled),
|
|
68
|
-
},
|
|
72
|
+
details,
|
|
73
|
+
displaySections: resolveDisplaySections(details),
|
|
69
74
|
});
|
|
70
75
|
}
|
|
71
76
|
|
|
@@ -233,6 +238,38 @@ function toTargetDetails(target: Readonly<TargetStoreEntry>, cwd: string) {
|
|
|
233
238
|
};
|
|
234
239
|
}
|
|
235
240
|
|
|
241
|
+
function resolveDisplaySections(details: ResolveDetails): ToolDisplaySection[] {
|
|
242
|
+
if (details.targets.length > 0) {
|
|
243
|
+
return [
|
|
244
|
+
createToolDisplaySection({
|
|
245
|
+
key: "resolve.targets",
|
|
246
|
+
title: "Targets",
|
|
247
|
+
items: details.targets,
|
|
248
|
+
totalCount: details.targetCount,
|
|
249
|
+
omittedCount: details.omittedCount,
|
|
250
|
+
format: (target) =>
|
|
251
|
+
`${target.name ?? "anonymous"} (${target.kind ?? "unknown"}) — ${target.file}:${target.displayLine}:${target.displayCharacter} [${target.targetId}]`,
|
|
252
|
+
}),
|
|
253
|
+
];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (details.candidates && details.candidates.length > 0) {
|
|
257
|
+
return [
|
|
258
|
+
createToolDisplaySection({
|
|
259
|
+
key: "resolve.candidates",
|
|
260
|
+
title: "Candidates",
|
|
261
|
+
items: details.candidates,
|
|
262
|
+
totalCount: details.targetCount,
|
|
263
|
+
omittedCount: details.omittedCount,
|
|
264
|
+
format: (candidate) =>
|
|
265
|
+
`${candidate.rank}. ${candidate.name} (${candidate.kind ?? "unknown"}) — ${candidate.file}:${candidate.line}:${candidate.character} [${candidate.targetId}]`,
|
|
266
|
+
}),
|
|
267
|
+
];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
|
|
236
273
|
function resolveProvenance(outcome: TargetWorkflowOutcome): ResultProvenance[] {
|
|
237
274
|
const sources = new Set<"semantic" | "structural">();
|
|
238
275
|
if (outcome.kind === "resolved") {
|
package/src/tool/result/types.ts
CHANGED
|
@@ -19,6 +19,26 @@ import type {
|
|
|
19
19
|
} from "../../session/target-store.ts";
|
|
20
20
|
import type { ResultProvenance } from "./assembly.ts";
|
|
21
21
|
|
|
22
|
+
/** Final state for a public tool result. */
|
|
23
|
+
export type ToolResultStatus = "completed" | "invalid-input" | "disambiguation" | "unavailable";
|
|
24
|
+
|
|
25
|
+
/** Truncation state for model-facing tool content. */
|
|
26
|
+
export interface ToolOutputTruncationDetails {
|
|
27
|
+
truncated: boolean;
|
|
28
|
+
fullOutputPath?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Bounded, structured rows for the expanded TUI body. */
|
|
32
|
+
export interface ToolDisplaySection {
|
|
33
|
+
key: string;
|
|
34
|
+
title: string;
|
|
35
|
+
lines: readonly string[];
|
|
36
|
+
shownCount: number;
|
|
37
|
+
totalCount: number | null;
|
|
38
|
+
omittedCount: number | null;
|
|
39
|
+
partialReason: string | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
22
42
|
// ── Anchored coordinate resolution metadata ───────────────────────────
|
|
23
43
|
|
|
24
44
|
/**
|
package/src/types/execution.ts
CHANGED
|
@@ -6,6 +6,9 @@ import type {
|
|
|
6
6
|
InspectDetails,
|
|
7
7
|
ResolveDetails,
|
|
8
8
|
SearchDetails,
|
|
9
|
+
ToolDisplaySection,
|
|
10
|
+
ToolOutputTruncationDetails,
|
|
11
|
+
ToolResultStatus,
|
|
9
12
|
} from "../tool/result/types.ts";
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -26,6 +29,8 @@ import type {
|
|
|
26
29
|
*/
|
|
27
30
|
export interface CodeIntelToolExecCtx {
|
|
28
31
|
cwd: string;
|
|
32
|
+
/** Opaque identity for Debug Events directly owned by this public Tool call. */
|
|
33
|
+
operationId?: string;
|
|
29
34
|
/** Abort signal from the agent runtime; forward to long-running subprocesses. */
|
|
30
35
|
signal?: AbortSignal;
|
|
31
36
|
/** Progress callback; long-running executors emit coarse beats, not chatty ones. */
|
|
@@ -39,13 +44,21 @@ export interface CodeIntelToolExecCtx {
|
|
|
39
44
|
session: WorkspaceCodeIntelligenceSession;
|
|
40
45
|
}
|
|
41
46
|
|
|
47
|
+
/** Shared metadata attached to one persisted Code Intelligence result. */
|
|
48
|
+
export interface CodeIntelResultDetails {
|
|
49
|
+
status?: ToolResultStatus;
|
|
50
|
+
message?: string;
|
|
51
|
+
displaySections?: readonly ToolDisplaySection[];
|
|
52
|
+
truncation?: ToolOutputTruncationDetails;
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
/** Tool result shape returned by executeAction. */
|
|
43
56
|
export interface CodeIntelResult {
|
|
44
57
|
content: string;
|
|
45
58
|
details?:
|
|
46
|
-
| { type: "context"; data: ContextDetails }
|
|
47
|
-
| { type: "inspect"; data: InspectDetails }
|
|
48
|
-
| { type: "search"; data: SearchDetails }
|
|
49
|
-
| { type: "resolve"; data: ResolveDetails }
|
|
50
|
-
| { type: "health"; data: HealthDetails };
|
|
59
|
+
| (CodeIntelResultDetails & { type: "context"; data: ContextDetails })
|
|
60
|
+
| (CodeIntelResultDetails & { type: "inspect"; data: InspectDetails })
|
|
61
|
+
| (CodeIntelResultDetails & { type: "search"; data: SearchDetails })
|
|
62
|
+
| (CodeIntelResultDetails & { type: "resolve"; data: ResolveDetails })
|
|
63
|
+
| (CodeIntelResultDetails & { type: "health"; data: HealthDetails });
|
|
51
64
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -8,7 +8,11 @@ export {
|
|
|
8
8
|
|
|
9
9
|
// ── Execution context and result ────────────────────────────────────────
|
|
10
10
|
|
|
11
|
-
export type {
|
|
11
|
+
export type {
|
|
12
|
+
CodeIntelResult,
|
|
13
|
+
CodeIntelResultDetails,
|
|
14
|
+
CodeIntelToolExecCtx,
|
|
15
|
+
} from "./execution.ts";
|
|
12
16
|
|
|
13
17
|
// ── Detail types ────────────────────────────────────────────────────────
|
|
14
18
|
|
|
@@ -23,4 +27,7 @@ export type {
|
|
|
23
27
|
OrientationSectionDetails,
|
|
24
28
|
ResolveDetails,
|
|
25
29
|
SearchDetails,
|
|
30
|
+
ToolDisplaySection,
|
|
31
|
+
ToolOutputTruncationDetails,
|
|
32
|
+
ToolResultStatus,
|
|
26
33
|
} from "../tool/result/types.ts";
|
package/src/ui/status-command.ts
CHANGED
|
@@ -52,7 +52,7 @@ export function registerCiStatusCommand(pi: ExtensionAPI): void {
|
|
|
52
52
|
fetchDetailedDiagnostics: async (maxSeverity) => {
|
|
53
53
|
const lspState = getWorkspaceLspRuntime(ctx.cwd);
|
|
54
54
|
if (lspState.kind !== "ready") return [];
|
|
55
|
-
return lspState.runtime.getOutstandingDiagnostics(maxSeverity);
|
|
55
|
+
return lspState.runtime.getOutstandingDiagnostics(maxSeverity).entries;
|
|
56
56
|
},
|
|
57
57
|
onRefresh: async () => {
|
|
58
58
|
const fresh = await gatherCiStatusData(ctx.cwd, pi);
|
|
@@ -95,10 +95,11 @@ async function gatherCiStatusData(cwd: string, pi: ExtensionAPI): Promise<CiStat
|
|
|
95
95
|
const semanticAvailable = servers.some(
|
|
96
96
|
(server) => server.status === "running" && server.ready === true,
|
|
97
97
|
);
|
|
98
|
-
const
|
|
98
|
+
const diagnosticSnapshot =
|
|
99
99
|
lspState.kind === "ready" && semanticAvailable
|
|
100
100
|
? lspState.runtime.getOutstandingDiagnosticSummary(1)
|
|
101
|
-
: [];
|
|
101
|
+
: { entries: [], current: false };
|
|
102
|
+
const diagnostics = diagnosticSnapshot.entries;
|
|
102
103
|
const semanticState = deriveSemanticCapabilityState(workspace, lspState, semanticAvailable);
|
|
103
104
|
|
|
104
105
|
// Sort: errors desc, warnings desc, info desc, hints desc
|
|
@@ -123,6 +124,7 @@ async function gatherCiStatusData(cwd: string, pi: ExtensionAPI): Promise<CiStat
|
|
|
123
124
|
diagnostics,
|
|
124
125
|
serverInventoryAvailable,
|
|
125
126
|
semanticAvailable,
|
|
127
|
+
diagnosticSnapshotCurrent: diagnosticSnapshot.current,
|
|
126
128
|
capabilities: {
|
|
127
129
|
semantic: semanticState,
|
|
128
130
|
structural: {
|
package/src/ui/status-overlay.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface CiStatusData {
|
|
|
37
37
|
serverInventoryAvailable: boolean;
|
|
38
38
|
/** Whether diagnostics and semantic absence claims are currently supported. */
|
|
39
39
|
semanticAvailable: boolean;
|
|
40
|
+
/** Whether tracked-file diagnostic counts prove the current document and workspace state. */
|
|
41
|
+
diagnosticSnapshotCurrent: boolean;
|
|
40
42
|
/** Sorted: errors desc, then warnings desc, then info desc, then hints desc. */
|
|
41
43
|
diagnostics: OutstandingDiagnosticSummaryEntry[];
|
|
42
44
|
capabilities: {
|
|
@@ -373,6 +375,8 @@ export class CiStatusDialog {
|
|
|
373
375
|
const t = this.theme;
|
|
374
376
|
if (!this.data.semanticAvailable) {
|
|
375
377
|
container.addChild(new Text(t.fg("dim", " (diagnostics unavailable)"), 1, 0));
|
|
378
|
+
} else if (!this.data.diagnosticSnapshotCurrent) {
|
|
379
|
+
container.addChild(new Text(t.fg("warning", " diagnostic snapshot is stale"), 1, 0));
|
|
376
380
|
} else {
|
|
377
381
|
container.addChild(new Text(t.fg("success", " ✓ no issues"), 1, 0));
|
|
378
382
|
}
|
package/src/ui/tui/common.ts
CHANGED
|
@@ -6,19 +6,47 @@
|
|
|
6
6
|
* partial/error guards, and the shared simple-result pattern.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
getMarkdownTheme,
|
|
11
|
+
type Theme,
|
|
12
|
+
type ToolRenderResultOptions,
|
|
13
|
+
} from "@earendil-works/pi-coding-agent";
|
|
10
14
|
import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
|
|
11
15
|
import { formatEvidenceBadge } from "@mrclrchtr/supi-core/evidence-badge";
|
|
16
|
+
import { truncateDisplayText } from "../../tool/result/display.ts";
|
|
17
|
+
import { renderToolDisplaySections } from "./display.ts";
|
|
18
|
+
|
|
19
|
+
export { formatCallPath, formatCallValue, renderToolDisplaySections } from "./display.ts";
|
|
20
|
+
|
|
21
|
+
import type {
|
|
22
|
+
ToolDisplaySection,
|
|
23
|
+
ToolOutputTruncationDetails,
|
|
24
|
+
ToolResultStatus,
|
|
25
|
+
} from "../../tool/result/types.ts";
|
|
12
26
|
|
|
13
27
|
// ── Result type ──────────────────────────────────────────────────
|
|
14
28
|
|
|
15
29
|
/** Shape of a pi tool result consumed by renderResult functions. */
|
|
16
30
|
export interface ToolResult {
|
|
17
31
|
content: Array<{ type: string; text?: string }>;
|
|
18
|
-
details?: {
|
|
19
|
-
|
|
32
|
+
details?: {
|
|
33
|
+
type: string;
|
|
34
|
+
data: Record<string, unknown>;
|
|
35
|
+
status?: ToolResultStatus;
|
|
36
|
+
message?: string;
|
|
37
|
+
displaySections?: readonly ToolDisplaySection[];
|
|
38
|
+
truncation?: ToolOutputTruncationDetails;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** PI render context used by Code Intelligence result renderers. */
|
|
43
|
+
export interface ToolRendererContext {
|
|
44
|
+
isError: boolean;
|
|
20
45
|
}
|
|
21
46
|
|
|
47
|
+
/** PI render options used by Code Intelligence result renderers. */
|
|
48
|
+
export type ResultOptios = ToolRenderResultOptions;
|
|
49
|
+
|
|
22
50
|
// ── Evidence key labels ──────────────────────────────────────────
|
|
23
51
|
|
|
24
52
|
export const EVIDENCE_KEY_LABELS: Record<string, string> = {
|
|
@@ -142,7 +170,7 @@ export function renderMarkdownDetail(
|
|
|
142
170
|
const markdownText = source.content?.find((c) => c.type === "text")?.text ?? "";
|
|
143
171
|
if (!markdownText) return;
|
|
144
172
|
container.addChild(new Spacer(1));
|
|
145
|
-
const divider = `${theme.fg("border", "────")} ${theme.fg("dim", "raw markdown")} ${theme.fg("border", "
|
|
173
|
+
const divider = `${theme.fg("border", "────")} ${theme.fg("dim", "raw markdown")} ${theme.fg("border", "────")}`;
|
|
146
174
|
container.addChild(new Text(divider, 0, 0));
|
|
147
175
|
container.addChild(new Markdown(markdownText, 0, 0, getMarkdownTheme()));
|
|
148
176
|
}
|
|
@@ -157,13 +185,62 @@ export function renderError(label: string, theme: Theme): Text {
|
|
|
157
185
|
return new Text(theme.fg("error", label), 0, 0);
|
|
158
186
|
}
|
|
159
187
|
|
|
160
|
-
|
|
188
|
+
/** Render an execution failure from PI's renderer context. */
|
|
189
|
+
export function renderExecutionError(
|
|
190
|
+
context: ToolRendererContext | undefined,
|
|
191
|
+
label: string,
|
|
192
|
+
theme: Theme,
|
|
193
|
+
): Text | null {
|
|
194
|
+
return context?.isError ? renderError(label, theme) : null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Render a domain error encoded in structured result details. */
|
|
198
|
+
export function renderDomainError(result: ToolResult, theme: Theme): Text | null {
|
|
199
|
+
const status = result.details?.status;
|
|
200
|
+
if (status !== "invalid-input" && status !== "disambiguation" && status !== "unavailable") {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const label =
|
|
205
|
+
status === "invalid-input"
|
|
206
|
+
? "Invalid input"
|
|
207
|
+
: status === "disambiguation"
|
|
208
|
+
? "Choose a target"
|
|
209
|
+
: "Unavailable";
|
|
210
|
+
const message = result.details?.message
|
|
211
|
+
? `: ${truncateDisplayText(result.details.message, 160)}`
|
|
212
|
+
: "";
|
|
213
|
+
return renderError(`${label}${message}`, theme);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Render an invalid-input or unavailable result with its structured body. */
|
|
217
|
+
export function renderDomainResult(
|
|
218
|
+
result: ToolResult,
|
|
219
|
+
options: ResultOptios,
|
|
220
|
+
theme: Theme,
|
|
221
|
+
error: Text,
|
|
222
|
+
): Container | Text {
|
|
223
|
+
if (!options.expanded) return error;
|
|
224
|
+
const container = new Container();
|
|
225
|
+
container.addChild(error);
|
|
226
|
+
renderToolDisplaySections(container, result.details?.displaySections, theme);
|
|
227
|
+
renderMarkdownDetail(container, result, theme);
|
|
228
|
+
return container;
|
|
229
|
+
}
|
|
161
230
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
231
|
+
/** Render the structured output-truncation disclosure. */
|
|
232
|
+
export function renderTruncationDisclosure(result: ToolResult, theme: Theme): Text | null {
|
|
233
|
+
const truncation = result.details?.truncation;
|
|
234
|
+
if (!truncation?.truncated) return null;
|
|
235
|
+
|
|
236
|
+
const path = truncation.fullOutputPath
|
|
237
|
+
? `; full output: ${truncateDisplayText(truncation.fullOutputPath, 160)}`
|
|
238
|
+
: "";
|
|
239
|
+
return new Text(theme.fg("warning", `Output truncated${path}`), 0, 0);
|
|
165
240
|
}
|
|
166
241
|
|
|
242
|
+
// ── Result options ───────────────────────────────────────────────
|
|
243
|
+
|
|
167
244
|
// ── Shared simple-result renderer ─────────────────────────────────
|
|
168
245
|
|
|
169
246
|
/**
|
|
@@ -172,19 +249,34 @@ export interface ResultOptios {
|
|
|
172
249
|
*
|
|
173
250
|
* Handles partial, error, compact, and expanded states uniformly.
|
|
174
251
|
*/
|
|
252
|
+
// biome-ignore lint/complexity/useMaxParams: renderer signature keeps the shared helper convenient for each tool
|
|
175
253
|
export function renderSimpleResult(
|
|
176
254
|
result: ToolResult,
|
|
177
255
|
options: ResultOptios,
|
|
178
256
|
theme: Theme,
|
|
179
257
|
partialLabel: string,
|
|
258
|
+
context?: ToolRendererContext,
|
|
180
259
|
): Container | Text {
|
|
181
260
|
if (options.isPartial) return renderPartial(partialLabel, theme);
|
|
182
|
-
|
|
261
|
+
|
|
262
|
+
const executionError = renderExecutionError(context, "Tool failed", theme);
|
|
263
|
+
if (executionError) return executionError;
|
|
264
|
+
|
|
265
|
+
const domainError = renderDomainError(result, theme);
|
|
266
|
+
if (domainError) return renderDomainResult(result, options, theme, domainError);
|
|
183
267
|
|
|
184
268
|
const data = result.details?.data as Record<string, unknown> | undefined;
|
|
185
269
|
if (options.expanded) return buildExpandedView(result, data, theme);
|
|
186
270
|
|
|
187
|
-
|
|
271
|
+
const compact = buildSimpleCompact(data, theme);
|
|
272
|
+
const truncation = renderTruncationDisclosure(result, theme);
|
|
273
|
+
if (!truncation) return compact;
|
|
274
|
+
|
|
275
|
+
const container = new Container();
|
|
276
|
+
container.addChild(compact);
|
|
277
|
+
container.addChild(new Spacer(1));
|
|
278
|
+
container.addChild(truncation);
|
|
279
|
+
return container;
|
|
188
280
|
}
|
|
189
281
|
|
|
190
282
|
function buildExpandedView(
|
|
@@ -197,7 +289,13 @@ function buildExpandedView(
|
|
|
197
289
|
const header = buildSimpleHeader(data, theme);
|
|
198
290
|
if (header) container.addChild(header);
|
|
199
291
|
|
|
292
|
+
renderToolDisplaySections(container, result.details?.displaySections, theme);
|
|
200
293
|
renderStructuredDetailBody(container, data, theme);
|
|
294
|
+
const truncation = renderTruncationDisclosure(result, theme);
|
|
295
|
+
if (truncation) {
|
|
296
|
+
container.addChild(new Spacer(1));
|
|
297
|
+
container.addChild(truncation);
|
|
298
|
+
}
|
|
201
299
|
renderMarkdownDetail(container, result, theme);
|
|
202
300
|
|
|
203
301
|
return container;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type Container, Text } from "@earendil-works/pi-tui";
|
|
3
|
+
import { readToolDisplaySections, truncateDisplayText } from "../../tool/result/display.ts";
|
|
4
|
+
import type { ToolDisplaySection } from "../../tool/result/types.ts";
|
|
5
|
+
|
|
6
|
+
/** Render bounded structured rows for an expanded TUI body. */
|
|
7
|
+
export function renderToolDisplaySections(
|
|
8
|
+
container: Container,
|
|
9
|
+
value: unknown,
|
|
10
|
+
theme: Theme,
|
|
11
|
+
): void {
|
|
12
|
+
for (const section of readToolDisplaySections(value)) {
|
|
13
|
+
container.addChild(
|
|
14
|
+
new Text(theme.fg("dim", `${section.title}${formatDisplayBounds(section)}`), 0, 0),
|
|
15
|
+
);
|
|
16
|
+
for (const line of section.lines) {
|
|
17
|
+
container.addChild(new Text(theme.fg("muted", line), 0, 0));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatDisplayBounds(section: ToolDisplaySection): string {
|
|
23
|
+
if (section.totalCount === null) {
|
|
24
|
+
const omitted = section.omittedCount ? `; ${section.omittedCount} collected omitted` : "";
|
|
25
|
+
const reason = section.partialReason
|
|
26
|
+
? `; more may exist — ${section.partialReason}`
|
|
27
|
+
: "; partial";
|
|
28
|
+
return ` (${section.shownCount}${omitted}${reason})`;
|
|
29
|
+
}
|
|
30
|
+
if (section.omittedCount && section.omittedCount > 0) {
|
|
31
|
+
return ` (${section.shownCount} of ${section.totalCount}; ${section.omittedCount} omitted)`;
|
|
32
|
+
}
|
|
33
|
+
return ` (${section.totalCount})`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Format one call argument for a compact human transcript row. */
|
|
37
|
+
export function formatCallValue(value: unknown, maxLength = 60): string | null {
|
|
38
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
39
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
40
|
+
return truncateDisplayText(normalized, maxLength);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Show the final path segment while accepting both POSIX and Windows paths. */
|
|
44
|
+
export function formatCallPath(value: unknown, maxLength = 60): string | null {
|
|
45
|
+
const formatted = formatCallValue(value, Number.MAX_SAFE_INTEGER);
|
|
46
|
+
if (!formatted) return null;
|
|
47
|
+
return formatCallValue(formatted.split(/[\\/]/).pop() ?? formatted, maxLength);
|
|
48
|
+
}
|