pi-studio 0.5.11 → 0.5.12
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/CHANGELOG.md +5 -0
- package/index.ts +324 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,11 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.12] — 2026-03-15
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Studio now has a `Load git diff` button that loads the current git changes (staged + unstaged tracked changes plus untracked text files) into the editor from the current Studio context and sets the editor language to `diff`.
|
|
11
|
+
|
|
7
12
|
## [0.5.11] — 2026-03-15
|
|
8
13
|
|
|
9
14
|
### Added
|
package/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionCommandContext, SessionEntry, Theme } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
2
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { readFileSync, statSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
@@ -120,6 +120,13 @@ interface GetFromEditorRequestMessage {
|
|
|
120
120
|
requestId: string;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
interface LoadGitDiffRequestMessage {
|
|
124
|
+
type: "load_git_diff_request";
|
|
125
|
+
requestId: string;
|
|
126
|
+
sourcePath?: string;
|
|
127
|
+
resourceDir?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
123
130
|
interface CancelRequestMessage {
|
|
124
131
|
type: "cancel_request";
|
|
125
132
|
requestId: string;
|
|
@@ -137,6 +144,7 @@ type IncomingStudioMessage =
|
|
|
137
144
|
| SaveOverRequestMessage
|
|
138
145
|
| SendToEditorRequestMessage
|
|
139
146
|
| GetFromEditorRequestMessage
|
|
147
|
+
| LoadGitDiffRequestMessage
|
|
140
148
|
| CancelRequestMessage;
|
|
141
149
|
|
|
142
150
|
const REQUEST_TIMEOUT_MS = 5 * 60 * 1000;
|
|
@@ -904,6 +912,207 @@ function writeStudioFile(pathArg: string, cwd: string, content: string):
|
|
|
904
912
|
}
|
|
905
913
|
}
|
|
906
914
|
|
|
915
|
+
function splitStudioGitPathOutput(output: string): string[] {
|
|
916
|
+
return output
|
|
917
|
+
.split(/\r?\n/)
|
|
918
|
+
.map((line) => line.trim())
|
|
919
|
+
.filter((line) => line.length > 0);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function formatStudioGitSpawnFailure(
|
|
923
|
+
result: { stdout?: string | Buffer | null; stderr?: string | Buffer | null },
|
|
924
|
+
args: string[],
|
|
925
|
+
): string {
|
|
926
|
+
const stderr = typeof result.stderr === "string"
|
|
927
|
+
? result.stderr.trim()
|
|
928
|
+
: (result.stderr ? result.stderr.toString("utf-8").trim() : "");
|
|
929
|
+
const stdout = typeof result.stdout === "string"
|
|
930
|
+
? result.stdout.trim()
|
|
931
|
+
: (result.stdout ? result.stdout.toString("utf-8").trim() : "");
|
|
932
|
+
return stderr || stdout || `git ${args.join(" ")} failed`;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
function readStudioTextFileIfPossible(path: string): string | null {
|
|
936
|
+
try {
|
|
937
|
+
const buf = readFileSync(path);
|
|
938
|
+
const sample = buf.subarray(0, 8192);
|
|
939
|
+
let nulCount = 0;
|
|
940
|
+
let controlCount = 0;
|
|
941
|
+
for (let i = 0; i < sample.length; i++) {
|
|
942
|
+
const b = sample[i];
|
|
943
|
+
if (b === 0x00) nulCount += 1;
|
|
944
|
+
else if (b < 0x08 || (b > 0x0D && b < 0x20 && b !== 0x1B)) controlCount += 1;
|
|
945
|
+
}
|
|
946
|
+
if (nulCount > 0 || (sample.length > 0 && controlCount / sample.length > 0.1)) {
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
return buf.toString("utf-8").replace(/\r\n/g, "\n");
|
|
950
|
+
} catch {
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
function buildStudioSyntheticNewFileDiff(filePath: string, content: string): string {
|
|
956
|
+
const lines = content.split("\n");
|
|
957
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
958
|
+
lines.pop();
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
const diffLines = [
|
|
962
|
+
`diff --git a/${filePath} b/${filePath}`,
|
|
963
|
+
"new file mode 100644",
|
|
964
|
+
"--- /dev/null",
|
|
965
|
+
`+++ b/${filePath}`,
|
|
966
|
+
`@@ -0,0 +1,${lines.length} @@`,
|
|
967
|
+
];
|
|
968
|
+
|
|
969
|
+
if (lines.length > 0) {
|
|
970
|
+
diffLines.push(lines.map((line) => `+${line}`).join("\n"));
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
return diffLines.join("\n");
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
function resolveStudioGitDiffBaseDir(sourcePath: string | undefined, resourceDir: string | undefined, fallbackCwd: string): string {
|
|
977
|
+
const source = typeof sourcePath === "string" ? sourcePath.trim() : "";
|
|
978
|
+
if (source) {
|
|
979
|
+
return dirname(source);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
const resource = typeof resourceDir === "string" ? resourceDir.trim() : "";
|
|
983
|
+
if (resource) {
|
|
984
|
+
return isAbsolute(resource) ? resource : resolve(fallbackCwd, resource);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
return fallbackCwd;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
function readStudioGitDiff(baseDir: string):
|
|
991
|
+
| { ok: true; text: string; label: string }
|
|
992
|
+
| { ok: false; level: "info" | "warning" | "error"; message: string } {
|
|
993
|
+
const repoRootArgs = ["rev-parse", "--show-toplevel"];
|
|
994
|
+
const repoRootResult = spawnSync("git", repoRootArgs, {
|
|
995
|
+
cwd: baseDir,
|
|
996
|
+
encoding: "utf-8",
|
|
997
|
+
});
|
|
998
|
+
if (repoRootResult.status !== 0) {
|
|
999
|
+
return {
|
|
1000
|
+
ok: false,
|
|
1001
|
+
level: "warning",
|
|
1002
|
+
message: "No git repository found for the current Studio context.",
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
const repoRoot = repoRootResult.stdout.trim();
|
|
1006
|
+
|
|
1007
|
+
const hasHead = spawnSync("git", ["rev-parse", "--verify", "HEAD"], {
|
|
1008
|
+
cwd: repoRoot,
|
|
1009
|
+
encoding: "utf-8",
|
|
1010
|
+
}).status === 0;
|
|
1011
|
+
|
|
1012
|
+
const untrackedArgs = ["ls-files", "--others", "--exclude-standard"];
|
|
1013
|
+
const untrackedResult = spawnSync("git", untrackedArgs, {
|
|
1014
|
+
cwd: repoRoot,
|
|
1015
|
+
encoding: "utf-8",
|
|
1016
|
+
});
|
|
1017
|
+
if (untrackedResult.status !== 0) {
|
|
1018
|
+
return {
|
|
1019
|
+
ok: false,
|
|
1020
|
+
level: "error",
|
|
1021
|
+
message: `Failed to list untracked files: ${formatStudioGitSpawnFailure(untrackedResult, untrackedArgs)}`,
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
const untrackedPaths = splitStudioGitPathOutput(untrackedResult.stdout ?? "").sort();
|
|
1025
|
+
|
|
1026
|
+
let diffOutput = "";
|
|
1027
|
+
let statSummary = "";
|
|
1028
|
+
let currentTreeFileCount = 0;
|
|
1029
|
+
|
|
1030
|
+
if (hasHead) {
|
|
1031
|
+
const diffArgs = ["diff", "HEAD", "--unified=3", "--find-renames", "--no-color", "--"];
|
|
1032
|
+
const diffResult = spawnSync("git", diffArgs, {
|
|
1033
|
+
cwd: repoRoot,
|
|
1034
|
+
encoding: "utf-8",
|
|
1035
|
+
});
|
|
1036
|
+
if (diffResult.status !== 0) {
|
|
1037
|
+
return {
|
|
1038
|
+
ok: false,
|
|
1039
|
+
level: "error",
|
|
1040
|
+
message: `Failed to collect git diff: ${formatStudioGitSpawnFailure(diffResult, diffArgs)}`,
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
diffOutput = diffResult.stdout ?? "";
|
|
1044
|
+
|
|
1045
|
+
const statArgs = ["diff", "HEAD", "--stat", "--find-renames", "--no-color", "--"];
|
|
1046
|
+
const statResult = spawnSync("git", statArgs, {
|
|
1047
|
+
cwd: repoRoot,
|
|
1048
|
+
encoding: "utf-8",
|
|
1049
|
+
});
|
|
1050
|
+
if (statResult.status === 0) {
|
|
1051
|
+
const statLines = splitStudioGitPathOutput(statResult.stdout ?? "");
|
|
1052
|
+
statSummary = statLines.length > 0 ? (statLines[statLines.length - 1] ?? "") : "";
|
|
1053
|
+
}
|
|
1054
|
+
} else {
|
|
1055
|
+
const trackedArgs = ["ls-files", "--cached"];
|
|
1056
|
+
const trackedResult = spawnSync("git", trackedArgs, {
|
|
1057
|
+
cwd: repoRoot,
|
|
1058
|
+
encoding: "utf-8",
|
|
1059
|
+
});
|
|
1060
|
+
if (trackedResult.status !== 0) {
|
|
1061
|
+
return {
|
|
1062
|
+
ok: false,
|
|
1063
|
+
level: "error",
|
|
1064
|
+
message: `Failed to inspect tracked files: ${formatStudioGitSpawnFailure(trackedResult, trackedArgs)}`,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
const trackedPaths = splitStudioGitPathOutput(trackedResult.stdout ?? "");
|
|
1069
|
+
const currentTreePaths = Array.from(new Set([...trackedPaths, ...untrackedPaths])).sort();
|
|
1070
|
+
currentTreeFileCount = currentTreePaths.length;
|
|
1071
|
+
diffOutput = currentTreePaths
|
|
1072
|
+
.map((filePath) => {
|
|
1073
|
+
const content = readStudioTextFileIfPossible(join(repoRoot, filePath));
|
|
1074
|
+
if (content == null) return "";
|
|
1075
|
+
return buildStudioSyntheticNewFileDiff(filePath, content);
|
|
1076
|
+
})
|
|
1077
|
+
.filter((section) => section.length > 0)
|
|
1078
|
+
.join("\n\n");
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
const untrackedSections = hasHead
|
|
1082
|
+
? untrackedPaths
|
|
1083
|
+
.map((filePath) => {
|
|
1084
|
+
const content = readStudioTextFileIfPossible(join(repoRoot, filePath));
|
|
1085
|
+
if (content == null) return "";
|
|
1086
|
+
return buildStudioSyntheticNewFileDiff(filePath, content);
|
|
1087
|
+
})
|
|
1088
|
+
.filter((section) => section.length > 0)
|
|
1089
|
+
: [];
|
|
1090
|
+
|
|
1091
|
+
const fullDiff = [diffOutput.trimEnd(), ...untrackedSections].filter(Boolean).join("\n\n");
|
|
1092
|
+
if (!fullDiff.trim()) {
|
|
1093
|
+
return {
|
|
1094
|
+
ok: false,
|
|
1095
|
+
level: "info",
|
|
1096
|
+
message: "No uncommitted git changes to load.",
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
const summaryParts: string[] = [];
|
|
1101
|
+
if (hasHead && statSummary) {
|
|
1102
|
+
summaryParts.push(statSummary);
|
|
1103
|
+
}
|
|
1104
|
+
if (!hasHead && currentTreeFileCount > 0) {
|
|
1105
|
+
summaryParts.push(`${currentTreeFileCount} file${currentTreeFileCount === 1 ? "" : "s"} in current tree`);
|
|
1106
|
+
}
|
|
1107
|
+
if (untrackedPaths.length > 0) {
|
|
1108
|
+
summaryParts.push(`${untrackedPaths.length} untracked file${untrackedPaths.length === 1 ? "" : "s"}`);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
const labelBase = hasHead ? "git diff HEAD" : "git diff (no commits yet)";
|
|
1112
|
+
const label = summaryParts.length > 0 ? `${labelBase} (${summaryParts.join(", ")})` : labelBase;
|
|
1113
|
+
return { ok: true, text: fullDiff, label };
|
|
1114
|
+
}
|
|
1115
|
+
|
|
907
1116
|
function readLocalPackageMetadata(): { name: string; version: string } | null {
|
|
908
1117
|
try {
|
|
909
1118
|
const raw = readFileSync(new URL("./package.json", import.meta.url), "utf-8");
|
|
@@ -1904,6 +2113,20 @@ function parseIncomingMessage(data: RawData): IncomingStudioMessage | null {
|
|
|
1904
2113
|
};
|
|
1905
2114
|
}
|
|
1906
2115
|
|
|
2116
|
+
if (
|
|
2117
|
+
msg.type === "load_git_diff_request"
|
|
2118
|
+
&& typeof msg.requestId === "string"
|
|
2119
|
+
&& (msg.sourcePath === undefined || typeof msg.sourcePath === "string")
|
|
2120
|
+
&& (msg.resourceDir === undefined || typeof msg.resourceDir === "string")
|
|
2121
|
+
) {
|
|
2122
|
+
return {
|
|
2123
|
+
type: "load_git_diff_request",
|
|
2124
|
+
requestId: msg.requestId,
|
|
2125
|
+
sourcePath: typeof msg.sourcePath === "string" ? msg.sourcePath : undefined,
|
|
2126
|
+
resourceDir: typeof msg.resourceDir === "string" ? msg.resourceDir : undefined,
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
2129
|
+
|
|
1907
2130
|
if (msg.type === "cancel_request" && typeof msg.requestId === "string") {
|
|
1908
2131
|
return {
|
|
1909
2132
|
type: "cancel_request",
|
|
@@ -3258,6 +3481,8 @@ ${cssVarsBlock}
|
|
|
3258
3481
|
<button id="saveAsBtn" type="button" title="Save editor content to a new file path.">Save editor as…</button>
|
|
3259
3482
|
<button id="saveOverBtn" type="button" title="Overwrite current file with editor content." disabled>Save editor</button>
|
|
3260
3483
|
<label class="file-label" title="Load a local file into editor text.">Load file content<input id="fileInput" type="file" accept=".md,.markdown,.mdx,.js,.mjs,.cjs,.jsx,.ts,.mts,.cts,.tsx,.py,.pyw,.sh,.bash,.zsh,.json,.jsonc,.json5,.rs,.c,.h,.cpp,.cxx,.cc,.hpp,.hxx,.jl,.f90,.f95,.f03,.f,.for,.r,.R,.m,.tex,.latex,.diff,.patch,.java,.go,.rb,.swift,.html,.htm,.css,.xml,.yaml,.yml,.toml,.lua,.txt,.rst,.adoc" /></label>
|
|
3484
|
+
<button id="loadGitDiffBtn" type="button" title="Load the current git diff from the Studio context into the editor.">Load git diff</button>
|
|
3485
|
+
<button id="getEditorBtn" type="button" title="Load the current terminal editor draft into Studio.">Load from pi editor</button>
|
|
3261
3486
|
</div>
|
|
3262
3487
|
</header>
|
|
3263
3488
|
|
|
@@ -3286,7 +3511,6 @@ ${cssVarsBlock}
|
|
|
3286
3511
|
<button id="sendRunBtn" type="button" title="Send editor text directly to the model as-is. Shortcut: Cmd/Ctrl+Enter when editor pane is active.">Run editor text</button>
|
|
3287
3512
|
<button id="copyDraftBtn" type="button">Copy editor text</button>
|
|
3288
3513
|
<button id="sendEditorBtn" type="button">Send to pi editor</button>
|
|
3289
|
-
<button id="getEditorBtn" type="button" title="Load the current terminal editor draft into Studio.">Load from pi editor</button>
|
|
3290
3514
|
</div>
|
|
3291
3515
|
<div class="source-actions-row">
|
|
3292
3516
|
<button id="insertHeaderBtn" type="button" title="Insert annotated-reply protocol header (source metadata, [an: ...] syntax hint, precedence note, and end marker).">Insert annotated reply header</button>
|
|
@@ -3483,6 +3707,7 @@ ${cssVarsBlock}
|
|
|
3483
3707
|
const saveOverBtn = document.getElementById("saveOverBtn");
|
|
3484
3708
|
const sendEditorBtn = document.getElementById("sendEditorBtn");
|
|
3485
3709
|
const getEditorBtn = document.getElementById("getEditorBtn");
|
|
3710
|
+
const loadGitDiffBtn = document.getElementById("loadGitDiffBtn");
|
|
3486
3711
|
const sendRunBtn = document.getElementById("sendRunBtn");
|
|
3487
3712
|
const copyDraftBtn = document.getElementById("copyDraftBtn");
|
|
3488
3713
|
const saveAnnotatedBtn = document.getElementById("saveAnnotatedBtn");
|
|
@@ -3773,6 +3998,7 @@ ${cssVarsBlock}
|
|
|
3773
3998
|
if (kind === "compact") return "compacting context";
|
|
3774
3999
|
if (kind === "send_to_editor") return "sending to pi editor";
|
|
3775
4000
|
if (kind === "get_from_editor") return "loading from pi editor";
|
|
4001
|
+
if (kind === "load_git_diff") return "loading git diff";
|
|
3776
4002
|
if (kind === "save_as" || kind === "save_over") return "saving editor text";
|
|
3777
4003
|
return "submitting request";
|
|
3778
4004
|
}
|
|
@@ -5163,6 +5389,7 @@ ${cssVarsBlock}
|
|
|
5163
5389
|
saveOverBtn.disabled = uiBusy || !canSaveOver;
|
|
5164
5390
|
sendEditorBtn.disabled = uiBusy;
|
|
5165
5391
|
if (getEditorBtn) getEditorBtn.disabled = uiBusy;
|
|
5392
|
+
if (loadGitDiffBtn) loadGitDiffBtn.disabled = uiBusy;
|
|
5166
5393
|
syncRunAndCritiqueButtons();
|
|
5167
5394
|
copyDraftBtn.disabled = uiBusy;
|
|
5168
5395
|
if (highlightSelect) highlightSelect.disabled = uiBusy;
|
|
@@ -6362,6 +6589,31 @@ ${cssVarsBlock}
|
|
|
6362
6589
|
return;
|
|
6363
6590
|
}
|
|
6364
6591
|
|
|
6592
|
+
if (message.type === "git_diff_snapshot") {
|
|
6593
|
+
if (typeof message.requestId === "string" && pendingRequestId === message.requestId) {
|
|
6594
|
+
pendingRequestId = null;
|
|
6595
|
+
pendingKind = null;
|
|
6596
|
+
}
|
|
6597
|
+
|
|
6598
|
+
const content = typeof message.content === "string" ? message.content : "";
|
|
6599
|
+
const label = typeof message.label === "string" && message.label.trim()
|
|
6600
|
+
? message.label.trim()
|
|
6601
|
+
: "git diff";
|
|
6602
|
+
setEditorText(content, { preserveScroll: false, preserveSelection: false });
|
|
6603
|
+
setSourceState({ source: "blank", label, path: null });
|
|
6604
|
+
setEditorLanguage("diff");
|
|
6605
|
+
setBusy(false);
|
|
6606
|
+
setWsState("Ready");
|
|
6607
|
+
refreshResponseUi();
|
|
6608
|
+
setStatus(
|
|
6609
|
+
typeof message.message === "string" && message.message.trim()
|
|
6610
|
+
? message.message
|
|
6611
|
+
: "Loaded current git diff.",
|
|
6612
|
+
"success",
|
|
6613
|
+
);
|
|
6614
|
+
return;
|
|
6615
|
+
}
|
|
6616
|
+
|
|
6365
6617
|
if (message.type === "studio_state") {
|
|
6366
6618
|
const busy = Boolean(message.busy);
|
|
6367
6619
|
agentBusyFromServer = Boolean(message.agentBusy);
|
|
@@ -6458,8 +6710,17 @@ ${cssVarsBlock}
|
|
|
6458
6710
|
}
|
|
6459
6711
|
|
|
6460
6712
|
if (message.type === "info") {
|
|
6713
|
+
if (typeof message.requestId === "string" && pendingRequestId === message.requestId) {
|
|
6714
|
+
pendingRequestId = null;
|
|
6715
|
+
pendingKind = null;
|
|
6716
|
+
setBusy(false);
|
|
6717
|
+
setWsState("Ready");
|
|
6718
|
+
}
|
|
6461
6719
|
if (typeof message.message === "string") {
|
|
6462
|
-
setStatus(
|
|
6720
|
+
setStatus(
|
|
6721
|
+
message.message,
|
|
6722
|
+
typeof message.level === "string" ? message.level : undefined,
|
|
6723
|
+
);
|
|
6463
6724
|
}
|
|
6464
6725
|
}
|
|
6465
6726
|
|
|
@@ -7099,6 +7360,29 @@ ${cssVarsBlock}
|
|
|
7099
7360
|
});
|
|
7100
7361
|
}
|
|
7101
7362
|
|
|
7363
|
+
if (loadGitDiffBtn) {
|
|
7364
|
+
loadGitDiffBtn.addEventListener("click", () => {
|
|
7365
|
+
const requestId = beginUiAction("load_git_diff");
|
|
7366
|
+
if (!requestId) return;
|
|
7367
|
+
|
|
7368
|
+
const effectivePath = getEffectiveSavePath();
|
|
7369
|
+
const sent = sendMessage({
|
|
7370
|
+
type: "load_git_diff_request",
|
|
7371
|
+
requestId,
|
|
7372
|
+
sourcePath: effectivePath || sourceState.path || undefined,
|
|
7373
|
+
resourceDir: resourceDirInput && resourceDirInput.value.trim()
|
|
7374
|
+
? resourceDirInput.value.trim()
|
|
7375
|
+
: undefined,
|
|
7376
|
+
});
|
|
7377
|
+
|
|
7378
|
+
if (!sent) {
|
|
7379
|
+
pendingRequestId = null;
|
|
7380
|
+
pendingKind = null;
|
|
7381
|
+
setBusy(false);
|
|
7382
|
+
}
|
|
7383
|
+
});
|
|
7384
|
+
}
|
|
7385
|
+
|
|
7102
7386
|
sendRunBtn.addEventListener("click", () => {
|
|
7103
7387
|
if (getAbortablePendingKind() === "direct") {
|
|
7104
7388
|
requestCancelForPendingRequest("direct");
|
|
@@ -7709,6 +7993,43 @@ export default function (pi: ExtensionAPI) {
|
|
|
7709
7993
|
return;
|
|
7710
7994
|
}
|
|
7711
7995
|
|
|
7996
|
+
if (msg.type === "load_git_diff_request") {
|
|
7997
|
+
if (!isValidRequestId(msg.requestId)) {
|
|
7998
|
+
sendToClient(client, { type: "error", requestId: msg.requestId, message: "Invalid request ID." });
|
|
7999
|
+
return;
|
|
8000
|
+
}
|
|
8001
|
+
if (isStudioBusy()) {
|
|
8002
|
+
sendToClient(client, { type: "busy", requestId: msg.requestId, message: "Studio is busy." });
|
|
8003
|
+
return;
|
|
8004
|
+
}
|
|
8005
|
+
|
|
8006
|
+
const baseDir = resolveStudioGitDiffBaseDir(msg.sourcePath, msg.resourceDir, studioCwd);
|
|
8007
|
+
const diffResult = readStudioGitDiff(baseDir);
|
|
8008
|
+
if (!diffResult.ok) {
|
|
8009
|
+
sendToClient(client, {
|
|
8010
|
+
type: "info",
|
|
8011
|
+
requestId: msg.requestId,
|
|
8012
|
+
message: diffResult.message,
|
|
8013
|
+
level: diffResult.level,
|
|
8014
|
+
});
|
|
8015
|
+
return;
|
|
8016
|
+
}
|
|
8017
|
+
|
|
8018
|
+
initialStudioDocument = {
|
|
8019
|
+
text: diffResult.text,
|
|
8020
|
+
label: diffResult.label,
|
|
8021
|
+
source: "blank",
|
|
8022
|
+
};
|
|
8023
|
+
sendToClient(client, {
|
|
8024
|
+
type: "git_diff_snapshot",
|
|
8025
|
+
requestId: msg.requestId,
|
|
8026
|
+
content: diffResult.text,
|
|
8027
|
+
label: diffResult.label,
|
|
8028
|
+
message: "Loaded current git diff into Studio.",
|
|
8029
|
+
});
|
|
8030
|
+
return;
|
|
8031
|
+
}
|
|
8032
|
+
|
|
7712
8033
|
if (msg.type === "cancel_request") {
|
|
7713
8034
|
if (!isValidRequestId(msg.requestId)) {
|
|
7714
8035
|
sendToClient(client, { type: "error", requestId: msg.requestId, message: "Invalid request ID." });
|