@oh-story/dsh 0.1.0 → 0.1.1
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 +3 -3
- package/lib/client.js +390 -144
- package/lib/client.js.map +4 -4
- package/lib/index.js +14742 -167
- package/lib/index.js.map +4 -4
- package/lib/types/client/file-activity.d.ts +8 -6
- package/lib/types/client/file-activity.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/file-activity-projection-types.d.ts +11 -0
- package/lib/types/file-activity-projection-types.d.ts.map +1 -0
- package/lib/types/file-activity-projection.d.ts +24 -0
- package/lib/types/file-activity-projection.d.ts.map +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/workspace-route.d.ts +1 -2
- package/lib/types/workspace-route.d.ts.map +1 -1
- package/package.json +16 -3
- package/lib/types/workspace-security.d.ts +0 -9
- package/lib/types/workspace-security.d.ts.map +0 -1
package/lib/client.js
CHANGED
|
@@ -27,7 +27,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
27
27
|
var import_react = require("react"), import_react_dom = require("react-dom");
|
|
28
28
|
|
|
29
29
|
// src/client/file-activity.ts
|
|
30
|
-
var STORY_DIRECTORIES = /* @__PURE__ */ new Set(["\u6B63\u6587", "\u5927\u7EB2", "\u8BBE\u5B9A", "\u8FFD\u8E2A", "\u5BF9\u6807", "\u53C2\u8003\u8D44\u6599"]), DRAMA_DIRECTORIES = /* @__PURE__ */ new Set(["\u8F93\u5165", "\u9879\u76EE\u5F00\u53D1", "\u8BBE\u5B9A\u96C6", "\u5267\u96C6", "\u4EA4\u4ED8", "\u521B\u4F5C\u8005\u51B3\u7B56", "\u5BA1\u67E5"]), EDITABLE_EXTENSION = /\.(?:md|txt|json|jsonl)$/iu;
|
|
30
|
+
var STORY_DIRECTORIES = /* @__PURE__ */ new Set(["\u6B63\u6587", "\u5927\u7EB2", "\u8BBE\u5B9A", "\u8FFD\u8E2A", "\u5BF9\u6807", "\u53C2\u8003\u8D44\u6599"]), DRAMA_DIRECTORIES = /* @__PURE__ */ new Set(["\u8F93\u5165", "\u9879\u76EE\u5F00\u53D1", "\u8BBE\u5B9A\u96C6", "\u5267\u96C6", "\u4EA4\u4ED8", "\u521B\u4F5C\u8005\u51B3\u7B56", "\u5BA1\u67E5"]), EDITABLE_EXTENSION = /\.(?:md|txt|json|jsonl)$/iu, MUTATING_CALLS = /* @__PURE__ */ new Set(["write", "edit", "str_replace_editor", "bash", "run_code", "oh_story_role"]);
|
|
31
31
|
function decodeEscape(character) {
|
|
32
32
|
switch (character) {
|
|
33
33
|
case '"':
|
|
@@ -80,7 +80,16 @@ function completedString(raw, key) {
|
|
|
80
80
|
let value = jsonStringPrefix(raw, key);
|
|
81
81
|
return value?.complete === !0 ? value.value : void 0;
|
|
82
82
|
}
|
|
83
|
-
function
|
|
83
|
+
function parsedArgs(raw) {
|
|
84
|
+
try {
|
|
85
|
+
let value = JSON.parse(raw);
|
|
86
|
+
return typeof value == "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
87
|
+
} catch {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function mutationFromArgs(name2, callId, argsRaw, stage) {
|
|
92
|
+
let complete = parsedArgs(argsRaw);
|
|
84
93
|
if (name2 === "write")
|
|
85
94
|
return {
|
|
86
95
|
callId,
|
|
@@ -90,7 +99,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
90
99
|
path: jsonStringPrefix(argsRaw, "file_path")?.value,
|
|
91
100
|
operation: "replace-file",
|
|
92
101
|
oldText: void 0,
|
|
93
|
-
newText: jsonStringPrefix(argsRaw, "content")?.value
|
|
102
|
+
newText: jsonStringPrefix(argsRaw, "content")?.value,
|
|
103
|
+
replaceAll: !1
|
|
94
104
|
};
|
|
95
105
|
if (name2 === "edit")
|
|
96
106
|
return {
|
|
@@ -101,7 +111,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
101
111
|
path: jsonStringPrefix(argsRaw, "file_path")?.value,
|
|
102
112
|
operation: "replace-text",
|
|
103
113
|
oldText: completedString(argsRaw, "old_string"),
|
|
104
|
-
newText: jsonStringPrefix(argsRaw, "new_string")?.value
|
|
114
|
+
newText: jsonStringPrefix(argsRaw, "new_string")?.value,
|
|
115
|
+
replaceAll: complete?.replace_all === !0
|
|
105
116
|
};
|
|
106
117
|
if (name2 !== "str_replace_editor") return;
|
|
107
118
|
let command = completedString(argsRaw, "command");
|
|
@@ -115,7 +126,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
115
126
|
path,
|
|
116
127
|
operation: "replace-file",
|
|
117
128
|
oldText: void 0,
|
|
118
|
-
newText: jsonStringPrefix(argsRaw, "file_text")?.value
|
|
129
|
+
newText: jsonStringPrefix(argsRaw, "file_text")?.value,
|
|
130
|
+
replaceAll: !1
|
|
119
131
|
} : command === "str_replace" ? {
|
|
120
132
|
callId,
|
|
121
133
|
name: name2,
|
|
@@ -124,7 +136,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
124
136
|
path,
|
|
125
137
|
operation: "replace-text",
|
|
126
138
|
oldText: completedString(argsRaw, "old_str"),
|
|
127
|
-
newText: jsonStringPrefix(argsRaw, "new_str")?.value
|
|
139
|
+
newText: jsonStringPrefix(argsRaw, "new_str")?.value ?? (complete !== void 0 ? "" : void 0),
|
|
140
|
+
replaceAll: complete?.replace_all === !0
|
|
128
141
|
} : command === "insert" ? {
|
|
129
142
|
callId,
|
|
130
143
|
name: name2,
|
|
@@ -133,27 +146,50 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
133
146
|
path,
|
|
134
147
|
operation: "insert-text",
|
|
135
148
|
oldText: void 0,
|
|
136
|
-
newText: jsonStringPrefix(argsRaw, "new_str")?.value
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
newText: jsonStringPrefix(argsRaw, "new_str")?.value,
|
|
150
|
+
replaceAll: !1
|
|
151
|
+
} : { callId, name: name2, argsRaw, stage, path, operation: void 0, oldText: void 0, newText: void 0, replaceAll: !1 };
|
|
152
|
+
}
|
|
153
|
+
function mutationsFromRunning(call) {
|
|
154
|
+
let direct = mutationFromArgs(call.name, call.callId, call.argsRaw, "running");
|
|
155
|
+
if (direct === void 0) return [];
|
|
156
|
+
let view = call.callView;
|
|
157
|
+
return view?.card !== "diff" || view.diffs.length === 0 ? [direct] : view.diffs.map((diff, index) => ({
|
|
158
|
+
...direct,
|
|
159
|
+
callId: view.diffs.length === 1 ? call.callId : `${call.callId}:${String(index)}`,
|
|
160
|
+
path: diff.path,
|
|
161
|
+
operation: diff.oldText === null ? "replace-file" : "replace-text",
|
|
162
|
+
oldText: diff.oldText ?? void 0,
|
|
163
|
+
newText: diff.newText
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
function visitRunning(blocks, visit) {
|
|
167
|
+
for (let block of blocks)
|
|
168
|
+
"kind" in block || visit(block), visitRunning(block.subCalls, visit);
|
|
169
|
+
}
|
|
170
|
+
function fileMutations(runningCalls, projectedCalls = []) {
|
|
171
|
+
let values = [];
|
|
172
|
+
visitRunning(runningCalls, (call) => {
|
|
173
|
+
values.push(...mutationsFromRunning(call));
|
|
174
|
+
});
|
|
175
|
+
for (let call of projectedCalls) {
|
|
176
|
+
let value = mutationFromArgs(call.name, call.callId, call.argsRaw, "streaming");
|
|
177
|
+
value !== void 0 && !values.some((candidate) => candidate.callId === value.callId) && values.push(value);
|
|
151
178
|
}
|
|
179
|
+
return values;
|
|
180
|
+
}
|
|
181
|
+
function mutatingCallIds(runningCalls) {
|
|
182
|
+
let ids = /* @__PURE__ */ new Set();
|
|
183
|
+
return visitRunning(runningCalls, (call) => {
|
|
184
|
+
MUTATING_CALLS.has(call.name) && ids.add(call.callId);
|
|
185
|
+
}), ids;
|
|
152
186
|
}
|
|
153
187
|
function creativeRelativePath(path, cwd) {
|
|
154
188
|
if (path === void 0 || path === "") return;
|
|
155
|
-
let normalized = path.replaceAll("\\", "/"), root = cwd?.replaceAll("\\", "/").replace(/\/$/u, ""),
|
|
156
|
-
if (
|
|
189
|
+
let normalized = path.replaceAll("\\", "/"), root = cwd?.replaceAll("\\", "/").replace(/\/$/u, ""), insideRoot = root !== void 0 && normalized.startsWith(`${root}/`);
|
|
190
|
+
if ((normalized.startsWith("/") || /^[a-z]:\//iu.test(normalized) || normalized.startsWith("file:")) && !insideRoot) return;
|
|
191
|
+
let relative = insideRoot ? normalized.slice(root.length + 1) : normalized.replace(/^\.\//u, ""), [directory2] = relative.split("/", 1);
|
|
192
|
+
if (!(!(directory2 !== void 0 && (STORY_DIRECTORIES.has(directory2) || DRAMA_DIRECTORIES.has(directory2))) && relative !== "short-drama.json" || !EDITABLE_EXTENSION.test(relative)) && !relative.split("/").some((part) => part === ".." || part === "." || part === ""))
|
|
157
193
|
return relative;
|
|
158
194
|
}
|
|
159
195
|
function workbenchModeForPath(path) {
|
|
@@ -165,7 +201,8 @@ function workbenchModeForPath(path) {
|
|
|
165
201
|
function previewMutation(activity, base) {
|
|
166
202
|
if (activity.operation === "replace-file") return activity.newText;
|
|
167
203
|
if (activity.operation === "replace-text") {
|
|
168
|
-
if (activity.oldText === void 0 || activity.newText === void 0) return;
|
|
204
|
+
if (activity.oldText === void 0 || activity.newText === void 0 || activity.oldText === "") return;
|
|
205
|
+
if (activity.replaceAll) return base.includes(activity.oldText) ? base.split(activity.oldText).join(activity.newText) : void 0;
|
|
169
206
|
let at = base.indexOf(activity.oldText);
|
|
170
207
|
return at < 0 ? void 0 : `${base.slice(0, at)}${activity.newText}${base.slice(at + activity.oldText.length)}`;
|
|
171
208
|
}
|
|
@@ -466,7 +503,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
466
503
|
--os-border: var(--dsw-alias-border-l2);
|
|
467
504
|
--os-muted: var(--dsw-alias-label-tertiary);
|
|
468
505
|
display: grid;
|
|
469
|
-
grid-template-columns: clamp(
|
|
506
|
+
grid-template-columns: clamp(96px, 16%, 190px) minmax(180px, 1fr) minmax(252px, 38%);
|
|
470
507
|
grid-template-rows: minmax(0, 1fr);
|
|
471
508
|
min-height: 0;
|
|
472
509
|
overflow-x: hidden;
|
|
@@ -765,7 +802,8 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
765
802
|
.oh-story-jsonl-error pre { margin: 3px -12px -12px; }
|
|
766
803
|
|
|
767
804
|
.oh-story-stream,
|
|
768
|
-
.oh-story-conflict
|
|
805
|
+
.oh-story-conflict,
|
|
806
|
+
.oh-story-warning {
|
|
769
807
|
flex: none;
|
|
770
808
|
padding: 7px 12px;
|
|
771
809
|
border-bottom: 1px solid var(--os-border);
|
|
@@ -776,6 +814,18 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
776
814
|
.oh-story-stream { color: var(--dsw-alias-state-business-primary); background: var(--dsw-alias-button-ghost-active-fill); }
|
|
777
815
|
.oh-story-stream[data-stage="streaming"] { animation: oh-story-pulse 1.2s ease-in-out infinite alternate; }
|
|
778
816
|
.oh-story-conflict { color: var(--dsw-alias-state-warn-label); background: var(--dsw-specific-tip); }
|
|
817
|
+
.oh-story-conflict > div { display: flex; gap: 6px; margin-top: 6px; }
|
|
818
|
+
.oh-story-conflict button,
|
|
819
|
+
.oh-story-empty button {
|
|
820
|
+
border: 1px solid var(--os-border);
|
|
821
|
+
border-radius: 6px;
|
|
822
|
+
color: inherit;
|
|
823
|
+
background: var(--dsw-alias-bg-base);
|
|
824
|
+
padding: 3px 8px;
|
|
825
|
+
cursor: pointer;
|
|
826
|
+
font: inherit;
|
|
827
|
+
}
|
|
828
|
+
.oh-story-warning { color: var(--dsw-alias-state-warn-label); background: var(--dsw-specific-tip); }
|
|
779
829
|
|
|
780
830
|
@keyframes oh-story-pulse { to { opacity: .62; } }
|
|
781
831
|
@media (prefers-reduced-motion: reduce) { .oh-story-stream[data-stage="streaming"] { animation: none; } }
|
|
@@ -799,10 +849,40 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
799
849
|
}
|
|
800
850
|
.oh-story-editor textarea { padding-right: 28px; padding-left: 28px; }
|
|
801
851
|
}
|
|
852
|
+
|
|
853
|
+
@media (max-width: 700px) {
|
|
854
|
+
[data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
|
|
855
|
+
grid-template-columns: 72px minmax(0, 1fr) 236px;
|
|
856
|
+
}
|
|
857
|
+
.oh-story-tree { padding-inline: 5px; }
|
|
858
|
+
.oh-story-brand { padding-inline: 3px; font-size: 11px; }
|
|
859
|
+
.oh-story-brand button { width: 24px; }
|
|
860
|
+
.oh-story-mode-tabs { margin-inline: 0; }
|
|
861
|
+
.oh-story-mode-tabs button { font-size: 10px; }
|
|
862
|
+
.oh-story-editor header { padding-inline: 7px; }
|
|
863
|
+
.oh-story-editor header > span { display: none; }
|
|
864
|
+
.oh-story-editor-tabs button { padding-inline: 6px; }
|
|
865
|
+
.oh-story-jsonl summary > code,
|
|
866
|
+
.oh-story-jsonl summary > em { display: none; }
|
|
867
|
+
}
|
|
802
868
|
`;
|
|
803
869
|
|
|
870
|
+
// src/file-activity-projection-types.ts
|
|
871
|
+
var FILE_ACTIVITY_PROJECTION_KEY = "ohStoryFileActivity";
|
|
872
|
+
|
|
804
873
|
// src/client/index.tsx
|
|
805
|
-
var import_jsx_runtime3 = require("react/jsx-runtime"), name = "oh-story", inject = ["slots"],
|
|
874
|
+
var import_jsx_runtime3 = require("react/jsx-runtime"), name = "oh-story", inject = ["sessions", "slots"], EMPTY_FILE_ACTIVITY_STORE = {
|
|
875
|
+
subscribe: () => () => {
|
|
876
|
+
},
|
|
877
|
+
getSnapshot: () => {
|
|
878
|
+
}
|
|
879
|
+
}, WorkspaceRequestError = class extends Error {
|
|
880
|
+
constructor(status, message) {
|
|
881
|
+
super(message);
|
|
882
|
+
this.status = status;
|
|
883
|
+
}
|
|
884
|
+
status;
|
|
885
|
+
}, workbenchMemory = /* @__PURE__ */ new Map(), GROUP_ORDER = {
|
|
806
886
|
story: ["\u6B63\u6587", "\u5927\u7EB2", "\u8BBE\u5B9A", "\u8FFD\u8E2A", "\u5BF9\u6807", "\u53C2\u8003\u8D44\u6599"],
|
|
807
887
|
drama: ["\u9879\u76EE", "\u8F93\u5165", "\u9879\u76EE\u5F00\u53D1", "\u8BBE\u5B9A\u96C6", "\u5267\u96C6", "\u5BA1\u67E5", "\u521B\u4F5C\u8005\u51B3\u7B56", "\u4EA4\u4ED8"]
|
|
808
888
|
};
|
|
@@ -817,14 +897,14 @@ function preferredFile(files, mode) {
|
|
|
817
897
|
}
|
|
818
898
|
return matching[0]?.path;
|
|
819
899
|
}
|
|
820
|
-
var
|
|
900
|
+
var EMPTY_CALLS = [];
|
|
821
901
|
function endpoint(path, sessionId, file) {
|
|
822
902
|
let url = new URL(`/oh-story/${path}`, globalThis.location.origin);
|
|
823
903
|
return url.searchParams.set("sessionId", sessionId), file !== void 0 && url.searchParams.set("path", file), url.toString();
|
|
824
904
|
}
|
|
825
905
|
async function json(response) {
|
|
826
906
|
let value = await response.json();
|
|
827
|
-
if (!response.ok) throw new
|
|
907
|
+
if (!response.ok) throw new WorkspaceRequestError(response.status, value.error ?? `HTTP ${String(response.status)}`);
|
|
828
908
|
return value;
|
|
829
909
|
}
|
|
830
910
|
function FileTreeNodes({
|
|
@@ -852,7 +932,7 @@ function FileTreeNodes({
|
|
|
852
932
|
},
|
|
853
933
|
node.path
|
|
854
934
|
);
|
|
855
|
-
let open =
|
|
935
|
+
let open = selected?.startsWith(`${node.path}/`) === !0 || expanded[node.path] === !0;
|
|
856
936
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "oh-story-file-folder", open, onToggle: (event) => {
|
|
857
937
|
onToggle(node.path, event.currentTarget.open);
|
|
858
938
|
}, children: [
|
|
@@ -876,89 +956,157 @@ function FileTreeNodes({
|
|
|
876
956
|
}) });
|
|
877
957
|
}
|
|
878
958
|
function useWorkspace(sessionId) {
|
|
879
|
-
let [version, setVersion] = (0, import_react.useState)(0), [workspace, setWorkspace] = (0, import_react.useState)(), [error, setError] = (0, import_react.useState)(), reload = (0, import_react.useCallback)(() => {
|
|
880
|
-
setVersion((value) => value + 1);
|
|
959
|
+
let [version, setVersion] = (0, import_react.useState)(0), [workspace, setWorkspace] = (0, import_react.useState)(), [error, setError] = (0, import_react.useState)(), [loading, setLoading] = (0, import_react.useState)(!0), reload = (0, import_react.useCallback)(() => {
|
|
960
|
+
setLoading(!0), setVersion((value) => value + 1);
|
|
881
961
|
}, []);
|
|
882
962
|
return (0, import_react.useEffect)(() => {
|
|
883
963
|
let controller = new AbortController();
|
|
884
964
|
return setError(void 0), fetch(endpoint("workspace", sessionId), { signal: controller.signal }).then((response) => json(response)).then(setWorkspace).catch((reason) => {
|
|
885
965
|
controller.signal.aborted || setError(reason instanceof Error ? reason.message : String(reason));
|
|
966
|
+
}).finally(() => {
|
|
967
|
+
controller.signal.aborted || setLoading(!1);
|
|
886
968
|
}), () => {
|
|
887
969
|
controller.abort();
|
|
888
970
|
};
|
|
889
|
-
}, [sessionId, version]), { workspace, error, reload };
|
|
971
|
+
}, [sessionId, version]), { workspace, error, loading, reload };
|
|
890
972
|
}
|
|
891
|
-
function CreativeWorkbench({
|
|
892
|
-
|
|
973
|
+
function CreativeWorkbench({
|
|
974
|
+
sessionId,
|
|
975
|
+
runningCalls,
|
|
976
|
+
projectedCalls
|
|
977
|
+
}) {
|
|
978
|
+
let { workspace, error, loading: workspaceLoading, reload } = useWorkspace(sessionId), activities = (0, import_react.useMemo)(
|
|
979
|
+
() => fileMutations(runningCalls, projectedCalls),
|
|
980
|
+
[projectedCalls, runningCalls]
|
|
981
|
+
), normalizedActivities = (0, import_react.useMemo)(() => activities.flatMap((activity2) => {
|
|
982
|
+
let path = creativeRelativePath(activity2.path, workspace?.cwd);
|
|
983
|
+
return path === void 0 ? [] : [{ activity: activity2, path }];
|
|
984
|
+
}), [activities, workspace?.cwd]), primaryActivity = normalizedActivities.at(-1), activityPaths = (0, import_react.useMemo)(() => new Set(normalizedActivities.map((value) => value.path)), [normalizedActivities]), activity = primaryActivity?.activity, activityPath = primaryActivity?.path, remembered = (0, import_react.useMemo)(() => workbenchMemory.get(sessionId), [sessionId]), [workbench, setWorkbench] = (0, import_react.useState)(remembered?.workbench ?? "story"), initializedWorkbench = (0, import_react.useRef)(!1), [selected, setSelected] = (0, import_react.useState)(remembered?.selected), [buffers, setBuffers] = (0, import_react.useState)(remembered?.buffers ?? {}), buffersRef = (0, import_react.useRef)({}), [expanded, setExpanded] = (0, import_react.useState)(remembered?.expanded ?? {}), surfaceRef = (0, import_react.useRef)(null), navRef = (0, import_react.useRef)(null), activityBases = (0, import_react.useRef)(/* @__PURE__ */ new Map()), previousSignals = (0, import_react.useRef)(/* @__PURE__ */ new Set()), saveLocks = (0, import_react.useRef)(/* @__PURE__ */ new Set()), buffer = selected === void 0 ? void 0 : buffers[selected], dirty = buffer?.source === "human" && buffer.content !== buffer.saved, saving = buffer?.saving === !0, fileError = buffer?.error, conflict = buffer?.conflict, selectedLower = selected?.toLocaleLowerCase(), markdown = selectedLower?.endsWith(".md") === !0, jsonl = selectedLower?.endsWith(".jsonl") === !0, structured = jsonl || selectedLower?.endsWith(".json") === !0, previewable = markdown || jsonl, [editorMode, setEditorMode] = (0, import_react.useState)(remembered?.editorMode ?? "preview"), modeSelection = (0, import_react.useRef)(selected);
|
|
893
985
|
(0, import_react.useEffect)(() => {
|
|
894
986
|
buffersRef.current = buffers;
|
|
895
987
|
}, [buffers]), (0, import_react.useEffect)(() => {
|
|
988
|
+
workbenchMemory.set(sessionId, { buffers, editorMode, expanded, selected, workbench });
|
|
989
|
+
}, [buffers, editorMode, expanded, selected, sessionId, workbench]), (0, import_react.useEffect)(() => {
|
|
990
|
+
let warn = (event) => {
|
|
991
|
+
Object.values(buffersRef.current).some((value) => value.source === "human" && value.content !== value.saved) && event.preventDefault();
|
|
992
|
+
};
|
|
993
|
+
return globalThis.addEventListener("beforeunload", warn), () => {
|
|
994
|
+
globalThis.removeEventListener("beforeunload", warn);
|
|
995
|
+
};
|
|
996
|
+
}, []);
|
|
997
|
+
let revealPath = (0, import_react.useCallback)((path) => {
|
|
998
|
+
setWorkbench(workbenchModeForPath(path) ?? "story"), setSelected(path);
|
|
999
|
+
let segments = path.split("/"), ancestors = [groupForPath(path)];
|
|
1000
|
+
for (let index = 1; index < segments.length - 1; index += 1) ancestors.push(segments.slice(0, index + 1).join("/"));
|
|
1001
|
+
setExpanded((current) => {
|
|
1002
|
+
let next = { ...current };
|
|
1003
|
+
for (let ancestor of ancestors) next[ancestor] = !0;
|
|
1004
|
+
return next;
|
|
1005
|
+
});
|
|
1006
|
+
}, []);
|
|
1007
|
+
(0, import_react.useEffect)(() => {
|
|
896
1008
|
if (workspace === void 0 || initializedWorkbench.current) return;
|
|
897
1009
|
let hasStory = workspace.files.some((file) => workbenchModeForPath(file.path) === "story");
|
|
898
1010
|
workspace.shortDrama !== null && !hasStory && setWorkbench("drama"), initializedWorkbench.current = !0;
|
|
899
1011
|
}, [workspace]), (0, import_react.useEffect)(() => {
|
|
900
|
-
|
|
901
|
-
}, [
|
|
902
|
-
setEditorMode(previewable ? "preview" : "source");
|
|
903
|
-
}, [previewable, selected]), (0, import_react.useEffect)(() => {
|
|
904
|
-
if (
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
}
|
|
908
|
-
selected !== void 0 && ((workspace?.files.some((file) => file.path === selected) ?? !1) || buffers[selected] !== void 0) && workbenchModeForPath(selected) === workbench || setSelected(workspace === void 0 ? void 0 : preferredFile(workspace.files, workbench));
|
|
909
|
-
}, [activityPath, buffers, selected, workbench, workspace]), (0, import_react.useEffect)(() => {
|
|
910
|
-
if (selected === void 0) return;
|
|
911
|
-
let exists = workspace?.files.some((file) => file.path === selected) ?? !1;
|
|
912
|
-
if (activityPath === selected && !exists) return;
|
|
913
|
-
let controller = new AbortController();
|
|
914
|
-
return setFileError(void 0), fetch(endpoint("file", sessionId, selected), { signal: controller.signal }).then((response) => json(response)).then((file) => {
|
|
915
|
-
let existing = buffersRef.current[file.path];
|
|
916
|
-
if (existing?.source === "human" && existing.content !== existing.saved) {
|
|
917
|
-
setConflict(`${file.path} \u5DF2\u88AB Agent \u66F4\u65B0\uFF1B\u4F60\u7684\u672A\u4FDD\u5B58\u7248\u672C\u4ECD\u4FDD\u7559\u3002`);
|
|
1012
|
+
activityPath !== void 0 && setEditorMode("source");
|
|
1013
|
+
}, [activityPath]), (0, import_react.useEffect)(() => {
|
|
1014
|
+
modeSelection.current !== selected && (modeSelection.current = selected, setEditorMode(activityPath === selected ? "source" : previewable ? "preview" : "source"));
|
|
1015
|
+
}, [activityPath, previewable, selected]), (0, import_react.useEffect)(() => {
|
|
1016
|
+
if (!workspaceLoading) {
|
|
1017
|
+
if (activityPath !== void 0) {
|
|
1018
|
+
revealPath(activityPath);
|
|
918
1019
|
return;
|
|
919
1020
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1021
|
+
selected !== void 0 && ((workspace?.files.some((file) => file.path === selected) ?? !1) || buffers[selected] !== void 0) && workbenchModeForPath(selected) === workbench || setSelected(workspace === void 0 ? void 0 : preferredFile(workspace.files, workbench));
|
|
1022
|
+
}
|
|
1023
|
+
}, [activityPath, buffers, revealPath, selected, workbench, workspace, workspaceLoading]), (0, import_react.useEffect)(() => {
|
|
1024
|
+
if (workspace === void 0 || workspaceLoading) return;
|
|
1025
|
+
let paths = new Set(workspace.files.map((file) => file.path));
|
|
1026
|
+
setBuffers((current) => {
|
|
1027
|
+
let changed = !1, next = { ...current };
|
|
1028
|
+
for (let [path, value] of Object.entries(current))
|
|
1029
|
+
paths.has(path) || activityPaths.has(path) || (value.source === "human" && value.content !== value.saved ? value.missing !== !0 && (next[path] = { ...value, missing: !0, error: "\u6587\u4EF6\u5DF2\u4ECE workspace \u79FB\u9664\u3002\u672C\u5730\u8349\u7A3F\u4ECD\u4FDD\u7559\uFF0C\u53EF\u590D\u5236\u540E\u653E\u5F03\u8349\u7A3F\u3002" }, changed = !0) : (delete next[path], changed = !0));
|
|
1030
|
+
return changed ? next : current;
|
|
1031
|
+
});
|
|
1032
|
+
}, [activityPaths, workspace, workspaceLoading]), (0, import_react.useEffect)(() => {
|
|
1033
|
+
if (selected === void 0 || activityPaths.has(selected) || !(workspace?.files.some((file) => file.path === selected) ?? !1)) return;
|
|
1034
|
+
let controller = new AbortController();
|
|
1035
|
+
return setBuffers((current) => {
|
|
1036
|
+
let existing = current[selected];
|
|
1037
|
+
return existing === void 0 ? current : { ...current, [selected]: { ...existing, error: void 0 } };
|
|
1038
|
+
}), fetch(endpoint("file", sessionId, selected), { signal: controller.signal }).then((response) => json(response)).then((file) => {
|
|
1039
|
+
setBuffers((current) => {
|
|
1040
|
+
let existing = current[file.path];
|
|
1041
|
+
return existing?.source === "human" && existing.content !== existing.saved ? existing.version === file.version ? { ...current, [file.path]: { ...existing, missing: !1, error: void 0 } } : {
|
|
1042
|
+
...current,
|
|
1043
|
+
[file.path]: {
|
|
1044
|
+
...existing,
|
|
1045
|
+
missing: !1,
|
|
1046
|
+
error: void 0,
|
|
1047
|
+
conflict: {
|
|
1048
|
+
message: `${file.path} \u5DF2\u5728\u78C1\u76D8\u4E0A\u66F4\u65B0\uFF1B\u4F60\u7684\u672C\u5730\u8349\u7A3F\u6CA1\u6709\u88AB\u8986\u76D6\u3002`,
|
|
1049
|
+
theirs: file.content,
|
|
1050
|
+
theirsVersion: file.version
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
} : {
|
|
1054
|
+
...current,
|
|
1055
|
+
[file.path]: { content: file.content, saved: file.content, source: "disk", version: file.version }
|
|
1056
|
+
};
|
|
1057
|
+
});
|
|
924
1058
|
}).catch((reason) => {
|
|
925
|
-
controller.signal.aborted ||
|
|
1059
|
+
controller.signal.aborted || setBuffers((current) => {
|
|
1060
|
+
let existing = current[selected];
|
|
1061
|
+
return existing === void 0 ? current : {
|
|
1062
|
+
...current,
|
|
1063
|
+
[selected]: { ...existing, error: reason instanceof Error ? reason.message : String(reason) }
|
|
1064
|
+
};
|
|
1065
|
+
});
|
|
926
1066
|
}), () => {
|
|
927
1067
|
controller.abort();
|
|
928
1068
|
};
|
|
929
|
-
}, [
|
|
930
|
-
if (
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1069
|
+
}, [activityPaths, selected, sessionId, workspace?.files]), (0, import_react.useEffect)(() => {
|
|
1070
|
+
if (normalizedActivities.length !== 0) {
|
|
1071
|
+
for (let { path } of normalizedActivities) revealPath(path);
|
|
1072
|
+
setBuffers((current) => {
|
|
1073
|
+
let next = current;
|
|
1074
|
+
for (let { activity: currentActivity, path } of normalizedActivities) {
|
|
1075
|
+
let existing = next[path];
|
|
1076
|
+
if (existing?.source === "human" && existing.content !== existing.saved) {
|
|
1077
|
+
next = {
|
|
1078
|
+
...next,
|
|
1079
|
+
[path]: {
|
|
1080
|
+
...existing,
|
|
1081
|
+
conflict: { message: `${path} \u6B63\u7531 Agent \u4FEE\u6539\uFF1B\u4F60\u7684\u672C\u5730\u8349\u7A3F\u5DF2\u9501\u5B9A\uFF0C\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002` }
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
continue;
|
|
1085
|
+
}
|
|
1086
|
+
let basis = activityBases.current.get(currentActivity.callId);
|
|
1087
|
+
(basis === void 0 || basis.path !== path) && (basis = { path, base: existing?.content ?? "" }, activityBases.current.set(currentActivity.callId, basis));
|
|
1088
|
+
let preview = previewMutation(currentActivity, basis.base);
|
|
1089
|
+
preview === void 0 || existing?.source === "agent" && existing.content === preview || (next = {
|
|
1090
|
+
...next,
|
|
1091
|
+
[path]: {
|
|
1092
|
+
content: preview,
|
|
1093
|
+
saved: existing?.saved ?? "",
|
|
1094
|
+
source: "agent",
|
|
1095
|
+
version: existing?.version ?? ""
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
947
1098
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
}, [activity, activityPath, buffers]), (0, import_react.useEffect)(() => {
|
|
951
|
-
if (activity !== void 0) {
|
|
952
|
-
settleTimer.current !== void 0 && clearTimeout(settleTimer.current), lastActivity.current = activity;
|
|
953
|
-
return;
|
|
1099
|
+
return next;
|
|
1100
|
+
});
|
|
954
1101
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1102
|
+
}, [normalizedActivities, revealPath]), (0, import_react.useEffect)(() => {
|
|
1103
|
+
let signals = new Set(mutatingCallIds(runningCalls));
|
|
1104
|
+
for (let { activity: currentActivity } of normalizedActivities) signals.add(currentActivity.callId.split(":", 1)[0] ?? currentActivity.callId);
|
|
1105
|
+
let settled = [...previousSignals.current].some((callId) => !signals.has(callId));
|
|
1106
|
+
for (let callId of activityBases.current.keys())
|
|
1107
|
+
signals.has(callId.split(":", 1)[0] ?? callId) || activityBases.current.delete(callId);
|
|
1108
|
+
previousSignals.current = signals, settled && reload();
|
|
1109
|
+
}, [normalizedActivities, reload, runningCalls]), (0, import_react.useEffect)(() => {
|
|
962
1110
|
if (selected !== void 0) {
|
|
963
1111
|
for (let button of navRef.current?.querySelectorAll("button[data-file-path]") ?? [])
|
|
964
1112
|
if (button.dataset.filePath === selected) {
|
|
@@ -967,7 +1115,7 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
967
1115
|
}
|
|
968
1116
|
}
|
|
969
1117
|
}, [selected]), (0, import_react.useEffect)(() => {
|
|
970
|
-
if (
|
|
1118
|
+
if (normalizedActivities.length > 0 || workspace === void 0) return;
|
|
971
1119
|
let sessionSurface = surfaceRef.current?.parentElement;
|
|
972
1120
|
if (sessionSurface == null) return;
|
|
973
1121
|
let knownPaths = new Set(workspace.files.map((file) => file.path)), followOfficialFileLink = (event) => {
|
|
@@ -977,9 +1125,9 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
977
1125
|
if (control === null || control.closest(".oh-story-split-surface") !== null) return;
|
|
978
1126
|
let candidates = [control.title, control.getAttribute("aria-label"), control.textContent];
|
|
979
1127
|
for (let candidate of candidates) {
|
|
980
|
-
let path = creativeRelativePath(candidate?.trim().replace(/^Open\s+/u, ""), workspace.cwd);
|
|
1128
|
+
let path = creativeRelativePath(candidate?.trim().replace(/^(?:Open|打开)\s+/u, ""), workspace.cwd);
|
|
981
1129
|
if (!(path === void 0 || !knownPaths.has(path))) {
|
|
982
|
-
event.preventDefault(), event.stopPropagation(),
|
|
1130
|
+
event.preventDefault(), event.stopPropagation(), revealPath(path);
|
|
983
1131
|
break;
|
|
984
1132
|
}
|
|
985
1133
|
}
|
|
@@ -987,39 +1135,88 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
987
1135
|
return sessionSurface.addEventListener("click", followOfficialFileLink, !0), () => {
|
|
988
1136
|
sessionSurface.removeEventListener("click", followOfficialFileLink, !0);
|
|
989
1137
|
};
|
|
990
|
-
}, [
|
|
991
|
-
let
|
|
992
|
-
if (
|
|
993
|
-
let submitted =
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1138
|
+
}, [normalizedActivities.length, revealPath, workspace]);
|
|
1139
|
+
let savePath = (0, import_react.useCallback)(async (path) => {
|
|
1140
|
+
if (saveLocks.current.has(path)) return;
|
|
1141
|
+
let submitted = buffersRef.current[path];
|
|
1142
|
+
if (!(submitted === void 0 || submitted.missing === !0 || submitted.content === submitted.saved)) {
|
|
1143
|
+
saveLocks.current.add(path), setBuffers((current) => {
|
|
1144
|
+
let existing = current[path];
|
|
1145
|
+
return existing === void 0 ? current : { ...current, [path]: { ...existing, saving: !0, error: void 0 } };
|
|
1146
|
+
});
|
|
1147
|
+
try {
|
|
1148
|
+
let file = await json(await fetch(endpoint("file", sessionId, path), {
|
|
1149
|
+
method: "PUT",
|
|
1150
|
+
headers: { "content-type": "application/json" },
|
|
1151
|
+
body: JSON.stringify({ content: submitted.content, baseVersion: submitted.version })
|
|
1152
|
+
}));
|
|
1153
|
+
setBuffers((current) => {
|
|
1154
|
+
let latest = current[path];
|
|
1155
|
+
if (latest === void 0) return current;
|
|
1156
|
+
let unchanged = latest.content === submitted.content;
|
|
1157
|
+
return {
|
|
1158
|
+
...current,
|
|
1159
|
+
[path]: {
|
|
1160
|
+
content: unchanged ? file.content : latest.content,
|
|
1161
|
+
saved: file.content,
|
|
1162
|
+
source: unchanged ? "disk" : "human",
|
|
1163
|
+
version: file.version,
|
|
1164
|
+
saving: !1
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
}), reload();
|
|
1168
|
+
} catch (reason) {
|
|
1169
|
+
if (reason instanceof WorkspaceRequestError && reason.status === 412)
|
|
1170
|
+
try {
|
|
1171
|
+
let theirs = await json(await fetch(endpoint("file", sessionId, path)));
|
|
1172
|
+
setBuffers((current) => {
|
|
1173
|
+
let latest = current[path];
|
|
1174
|
+
return latest === void 0 ? current : {
|
|
1175
|
+
...current,
|
|
1176
|
+
[path]: {
|
|
1177
|
+
...latest,
|
|
1178
|
+
saving: !1,
|
|
1179
|
+
conflict: {
|
|
1180
|
+
message: `${path} \u5DF2\u5728\u78C1\u76D8\u4E0A\u66F4\u65B0\uFF1B\u8BF7\u9009\u62E9\u4FDD\u7559\u54EA\u4E00\u7248\u3002`,
|
|
1181
|
+
theirs: theirs.content,
|
|
1182
|
+
theirsVersion: theirs.version
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
});
|
|
1187
|
+
} catch (refreshError) {
|
|
1188
|
+
setBuffers((current) => {
|
|
1189
|
+
let existing = current[path];
|
|
1190
|
+
return existing === void 0 ? current : {
|
|
1191
|
+
...current,
|
|
1192
|
+
[path]: { ...existing, saving: !1, error: refreshError instanceof Error ? refreshError.message : String(refreshError) }
|
|
1193
|
+
};
|
|
1194
|
+
});
|
|
1012
1195
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1196
|
+
else
|
|
1197
|
+
setBuffers((current) => {
|
|
1198
|
+
let existing = current[path];
|
|
1199
|
+
return existing === void 0 ? current : {
|
|
1200
|
+
...current,
|
|
1201
|
+
[path]: { ...existing, saving: !1, error: reason instanceof Error ? reason.message : String(reason) }
|
|
1202
|
+
};
|
|
1203
|
+
});
|
|
1204
|
+
} finally {
|
|
1205
|
+
saveLocks.current.delete(path);
|
|
1206
|
+
}
|
|
1019
1207
|
}
|
|
1020
|
-
}, [
|
|
1208
|
+
}, [reload, sessionId]);
|
|
1209
|
+
(0, import_react.useEffect)(() => {
|
|
1210
|
+
let saveShortcut = (event) => {
|
|
1211
|
+
!(event.metaKey || event.ctrlKey) || event.key.toLocaleLowerCase() !== "s" || (event.preventDefault(), selected !== void 0 && savePath(selected));
|
|
1212
|
+
};
|
|
1213
|
+
return globalThis.addEventListener("keydown", saveShortcut), () => {
|
|
1214
|
+
globalThis.removeEventListener("keydown", saveShortcut);
|
|
1215
|
+
};
|
|
1216
|
+
}, [savePath, selected]);
|
|
1217
|
+
let groups = (0, import_react.useMemo)(() => {
|
|
1021
1218
|
let value = /* @__PURE__ */ new Map(), all = [...workspace?.files ?? []].filter((file) => workbenchModeForPath(file.path) === workbench);
|
|
1022
|
-
activityPath !== void 0 && !all.some((file) => file.path === activityPath) && all.push({ path: activityPath, bytes: 0 }), all.sort((left, right) => left.path.localeCompare(right.path, "zh-Hans-CN"));
|
|
1219
|
+
activityPath !== void 0 && !all.some((file) => file.path === activityPath) && all.push({ path: activityPath, bytes: 0, version: "" }), all.sort((left, right) => left.path.localeCompare(right.path, "zh-Hans-CN"));
|
|
1023
1220
|
for (let file of all) {
|
|
1024
1221
|
let directory2 = groupForPath(file.path), files = value.get(directory2) ?? [];
|
|
1025
1222
|
files.push(file), value.set(directory2, files);
|
|
@@ -1030,11 +1227,21 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1030
1227
|
return (leftIndex < 0 ? order.length : leftIndex) - (rightIndex < 0 ? order.length : rightIndex) || left.localeCompare(right, "zh-Hans-CN");
|
|
1031
1228
|
});
|
|
1032
1229
|
}, [activityPath, workbench, workspace]), selectWorkbench = (next) => {
|
|
1033
|
-
setWorkbench(next)
|
|
1230
|
+
setWorkbench(next);
|
|
1034
1231
|
let target = workspace === void 0 ? void 0 : preferredFile(workspace.files, next);
|
|
1035
|
-
setSelected(target);
|
|
1232
|
+
target === void 0 ? setSelected(void 0) : revealPath(target);
|
|
1036
1233
|
}, selectedGroup = selected === void 0 ? void 0 : groupForPath(selected), toggleGroup = (key, open) => {
|
|
1037
1234
|
setExpanded((current) => ({ ...current, [key]: open }));
|
|
1235
|
+
}, resolveConflict = (keepLocal) => {
|
|
1236
|
+
if (selected === void 0 || conflict?.theirs === void 0 || conflict.theirsVersion === void 0) return;
|
|
1237
|
+
let theirs = conflict.theirs, theirsVersion = conflict.theirsVersion;
|
|
1238
|
+
setBuffers((current) => {
|
|
1239
|
+
let existing = current[selected];
|
|
1240
|
+
return existing === void 0 ? current : {
|
|
1241
|
+
...current,
|
|
1242
|
+
[selected]: keepLocal ? { ...existing, saved: theirs, version: theirsVersion, source: "human", conflict: void 0 } : { content: theirs, saved: theirs, source: "disk", version: theirsVersion }
|
|
1243
|
+
};
|
|
1244
|
+
});
|
|
1038
1245
|
};
|
|
1039
1246
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: surfaceRef, className: "oh-story-split-surface", children: [
|
|
1040
1247
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: plugin_default }),
|
|
@@ -1052,8 +1259,9 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1052
1259
|
}, children: "\u77ED\u5267" })
|
|
1053
1260
|
] }),
|
|
1054
1261
|
error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-error", children: error }),
|
|
1262
|
+
workspace?.metadataErrors.map((message) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-warning", children: message }, message)),
|
|
1055
1263
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("nav", { ref: navRef, "aria-label": workbench === "story" ? "\u5C0F\u8BF4\u9879\u76EE\u6587\u4EF6" : "\u77ED\u5267\u9879\u76EE\u6587\u4EF6", children: groups.map(([directory2, files]) => {
|
|
1056
|
-
let groupOpen = expanded[directory2]
|
|
1264
|
+
let groupOpen = selectedGroup === directory2 || expanded[directory2] === !0;
|
|
1057
1265
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "oh-story-file-group", open: groupOpen, onToggle: (event) => {
|
|
1058
1266
|
toggleGroup(directory2, event.currentTarget.open);
|
|
1059
1267
|
}, children: [
|
|
@@ -1070,7 +1278,7 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1070
1278
|
selected,
|
|
1071
1279
|
activityPath,
|
|
1072
1280
|
onToggle: toggleGroup,
|
|
1073
|
-
onSelect:
|
|
1281
|
+
onSelect: revealPath
|
|
1074
1282
|
}
|
|
1075
1283
|
)
|
|
1076
1284
|
] }, directory2);
|
|
@@ -1088,16 +1296,26 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1088
1296
|
setEditorMode("source");
|
|
1089
1297
|
}, children: "\u6E90\u7801" })
|
|
1090
1298
|
] }),
|
|
1091
|
-
(dirty || saving) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "oh-story-save", type: "button", disabled: saving, onClick: () => {
|
|
1092
|
-
|
|
1299
|
+
(dirty || saving) && selected !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "oh-story-save", type: "button", disabled: saving || buffer?.missing === !0, onClick: () => {
|
|
1300
|
+
savePath(selected);
|
|
1093
1301
|
}, children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
|
|
1094
1302
|
] })
|
|
1095
1303
|
] }),
|
|
1096
|
-
activityPath === selected && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-stream", "data-stage": activity
|
|
1304
|
+
activity !== void 0 && activityPath !== void 0 && activityPath === selected && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-stream", "data-stage": activity.stage, role: "status", "aria-live": "polite", children: [
|
|
1097
1305
|
"\u25CF ",
|
|
1098
|
-
activity
|
|
1306
|
+
activity.stage === "running" ? "Agent \u6B63\u5728\u5E94\u7528\u4FEE\u6539" : "Agent \u6B63\u5728\u751F\u6210\u6587\u4EF6\u5185\u5BB9"
|
|
1307
|
+
] }),
|
|
1308
|
+
conflict !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-conflict", role: "alert", children: [
|
|
1309
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: conflict.message }),
|
|
1310
|
+
conflict.theirs !== void 0 && conflict.theirsVersion !== void 0 && selected !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: () => {
|
|
1312
|
+
resolveConflict(!1);
|
|
1313
|
+
}, children: "\u8F7D\u5165\u78C1\u76D8\u7248\u672C" }),
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: () => {
|
|
1315
|
+
resolveConflict(!0);
|
|
1316
|
+
}, children: "\u4FDD\u7559\u672C\u5730\u8349\u7A3F" })
|
|
1317
|
+
] })
|
|
1099
1318
|
] }),
|
|
1100
|
-
conflict !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-conflict", children: conflict }),
|
|
1101
1319
|
fileError !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-error", children: fileError }),
|
|
1102
1320
|
selected === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-empty", children: workbench === "story" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1103
1321
|
"\u5F53\u524D workspace \u8FD8\u6CA1\u6709\u5C0F\u8BF4\u6587\u4EF6\u3002\u53EF\u5728\u53F3\u4FA7 Chat \u4E2D\u8FD0\u884C ",
|
|
@@ -1111,6 +1329,14 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1111
1329
|
"\u6B63\u5728\u52A0\u8F7D ",
|
|
1112
1330
|
selected,
|
|
1113
1331
|
"\u2026"
|
|
1332
|
+
] }) : buffer.missing === !0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-empty", children: [
|
|
1333
|
+
"\u6587\u4EF6\u5DF2\u4ECE workspace \u79FB\u9664\uFF0C\u672C\u5730\u8349\u7A3F\u4ECD\u4FDD\u7559\u3002\u8BF7\u5148\u590D\u5236\u9700\u8981\u7684\u5185\u5BB9\uFF0C\u518D\u653E\u5F03\u8349\u7A3F\u3002",
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: () => {
|
|
1335
|
+
setBuffers((current) => {
|
|
1336
|
+
let next = { ...current };
|
|
1337
|
+
return delete next[selected], next;
|
|
1338
|
+
}), setSelected(workspace === void 0 ? void 0 : preferredFile(workspace.files, workbench));
|
|
1339
|
+
}, children: "\u653E\u5F03\u672C\u5730\u8349\u7A3F" })
|
|
1114
1340
|
] }) : previewable && editorMode === "preview" ? markdown ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MarkdownPreview, { content: buffer.content, label: selected }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(JsonlPreview, { content: buffer.content, label: selected }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1115
1341
|
"textarea",
|
|
1116
1342
|
{
|
|
@@ -1124,13 +1350,12 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1124
1350
|
content,
|
|
1125
1351
|
saved: current[selected]?.saved ?? "",
|
|
1126
1352
|
source: "human",
|
|
1127
|
-
version: current[selected]?.version ?? ""
|
|
1353
|
+
version: current[selected]?.version ?? "",
|
|
1354
|
+
conflict: current[selected]?.conflict,
|
|
1355
|
+
saving: current[selected]?.saving
|
|
1128
1356
|
}
|
|
1129
1357
|
}));
|
|
1130
1358
|
},
|
|
1131
|
-
onKeyDown: (event) => {
|
|
1132
|
-
(event.metaKey || event.ctrlKey) && event.key.toLocaleLowerCase() === "s" && (event.preventDefault(), save());
|
|
1133
|
-
},
|
|
1134
1359
|
spellCheck: !structured,
|
|
1135
1360
|
"aria-label": selected
|
|
1136
1361
|
}
|
|
@@ -1138,12 +1363,25 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1138
1363
|
] })
|
|
1139
1364
|
] });
|
|
1140
1365
|
}
|
|
1141
|
-
function CreativeSplitBridge(
|
|
1142
|
-
let marker = (0, import_react.useRef)(null), [target, setTarget] = (0, import_react.useState)()
|
|
1366
|
+
function CreativeSplitBridge({ context }) {
|
|
1367
|
+
let marker = (0, import_react.useRef)(null), [target, setTarget] = (0, import_react.useState)(), provideFace = context.sessions.currentProvideInfo, subscribeProvide = (0, import_react.useCallback)((listener) => provideFace.subscribe(listener), [provideFace]), getProvide = (0, import_react.useCallback)(() => provideFace.getSnapshot(), [provideFace]), provide = (0, import_react.useSyncExternalStore)(subscribeProvide, getProvide, getProvide), sessionId = provide.sessionId, source = provide.hooks.session, subscribe = (0, import_react.useCallback)((listener) => source?.subscribe(listener) ?? (() => {
|
|
1368
|
+
}), [source]), getSnapshot = (0, import_react.useCallback)(() => source?.getSnapshot(), [source]), snapshot = (0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot), projectionSource = (0, import_react.useMemo)(
|
|
1369
|
+
() => provide.projections?.faceOf(FILE_ACTIVITY_PROJECTION_KEY) ?? EMPTY_FILE_ACTIVITY_STORE,
|
|
1370
|
+
[provide.projections]
|
|
1371
|
+
), subscribeProjection = (0, import_react.useCallback)((listener) => projectionSource.subscribe(listener), [projectionSource]), getProjection = (0, import_react.useCallback)(() => projectionSource.getSnapshot(), [projectionSource]), projection = (0, import_react.useSyncExternalStore)(subscribeProjection, getProjection, getProjection);
|
|
1143
1372
|
return (0, import_react.useLayoutEffect)(() => {
|
|
1144
|
-
let
|
|
1145
|
-
|
|
1146
|
-
|
|
1373
|
+
let document = marker.current?.ownerDocument;
|
|
1374
|
+
if (document === void 0) return;
|
|
1375
|
+
let locate = () => {
|
|
1376
|
+
let anchor = document.querySelector("[data-conversation-scroll] > [data-slot='conversation.session']");
|
|
1377
|
+
setTarget((current) => current === anchor ? current : anchor ?? void 0);
|
|
1378
|
+
};
|
|
1379
|
+
locate();
|
|
1380
|
+
let observer = new MutationObserver(locate);
|
|
1381
|
+
return observer.observe(document.body, { childList: !0, subtree: !0 }), () => {
|
|
1382
|
+
observer.disconnect();
|
|
1383
|
+
};
|
|
1384
|
+
}, [sessionId]), (0, import_react.useLayoutEffect)(() => {
|
|
1147
1385
|
let scroller = target?.parentElement;
|
|
1148
1386
|
if (scroller == null) return;
|
|
1149
1387
|
let publishHeight = () => {
|
|
@@ -1156,7 +1394,15 @@ function CreativeSplitBridge(props) {
|
|
|
1156
1394
|
};
|
|
1157
1395
|
}, [target]), /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1158
1396
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { ref: marker, className: "oh-story-bridge-marker", "aria-hidden": !0 }),
|
|
1159
|
-
target === void 0 ? null : (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1397
|
+
target === void 0 || sessionId === void 0 ? null : (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1398
|
+
CreativeWorkbench,
|
|
1399
|
+
{
|
|
1400
|
+
sessionId,
|
|
1401
|
+
runningCalls: snapshot?.runningCalls ?? EMPTY_CALLS,
|
|
1402
|
+
projectedCalls: projection?.calls ?? []
|
|
1403
|
+
},
|
|
1404
|
+
sessionId
|
|
1405
|
+
), target)
|
|
1160
1406
|
] });
|
|
1161
1407
|
}
|
|
1162
1408
|
function argsOf(block) {
|
|
@@ -1187,11 +1433,11 @@ function RoleToolView({ block, inspect }) {
|
|
|
1187
1433
|
] });
|
|
1188
1434
|
}
|
|
1189
1435
|
function apply(context) {
|
|
1190
|
-
context.slots.inject("
|
|
1191
|
-
name: "
|
|
1436
|
+
context.slots.inject("shell.overlay", () => context.slots.register({
|
|
1437
|
+
name: "shell.overlay",
|
|
1192
1438
|
id: "oh-story-workspace",
|
|
1193
1439
|
order: -100
|
|
1194
|
-
}, CreativeSplitBridge)), context.slots.inject("tool.call.toolview", () => context.slots.register({
|
|
1440
|
+
}, () => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CreativeSplitBridge, { context }))), context.slots.inject("tool.call.toolview", () => context.slots.register({
|
|
1195
1441
|
name: "tool.call.toolview",
|
|
1196
1442
|
key: "oh_story_role"
|
|
1197
1443
|
}, RoleToolView));
|