@oh-story/dsh 0.1.0 → 0.1.2
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 +610 -214
- package/lib/client.js.map +3 -3
- package/lib/index.js +190 -172
- package/lib/index.js.map +4 -4
- package/lib/types/client/file-activity.d.ts +11 -6
- package/lib/types/client/file-activity.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +9 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/native-hooks.d.ts +4 -1
- package/lib/types/native-hooks.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 +14 -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
|
@@ -24,10 +24,21 @@ __export(index_exports, {
|
|
|
24
24
|
name: () => name
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
-
var import_react = require("react"), import_react_dom = require("react-dom");
|
|
27
|
+
var import_client = require("@deepseek-ai/dsh-client-runtime/client"), 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
|
+
function streamingAssistant(timeline) {
|
|
32
|
+
for (let turnNumber of timeline.turnOrder.toReversed()) {
|
|
33
|
+
let turn = timeline.turns.get(turnNumber);
|
|
34
|
+
if (turn !== void 0)
|
|
35
|
+
for (let step of turn.steps.toReversed()) {
|
|
36
|
+
let assistant = step.data.get("assistant-step");
|
|
37
|
+
if (assistant?.status === "running") return assistant;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
31
42
|
function decodeEscape(character) {
|
|
32
43
|
switch (character) {
|
|
33
44
|
case '"':
|
|
@@ -80,7 +91,16 @@ function completedString(raw, key) {
|
|
|
80
91
|
let value = jsonStringPrefix(raw, key);
|
|
81
92
|
return value?.complete === !0 ? value.value : void 0;
|
|
82
93
|
}
|
|
83
|
-
function
|
|
94
|
+
function parsedArgs(raw) {
|
|
95
|
+
try {
|
|
96
|
+
let value = JSON.parse(raw);
|
|
97
|
+
return typeof value == "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
98
|
+
} catch {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function mutationFromArgs(name2, callId, argsRaw, stage) {
|
|
103
|
+
let complete = parsedArgs(argsRaw);
|
|
84
104
|
if (name2 === "write")
|
|
85
105
|
return {
|
|
86
106
|
callId,
|
|
@@ -90,7 +110,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
90
110
|
path: jsonStringPrefix(argsRaw, "file_path")?.value,
|
|
91
111
|
operation: "replace-file",
|
|
92
112
|
oldText: void 0,
|
|
93
|
-
newText: jsonStringPrefix(argsRaw, "content")?.value
|
|
113
|
+
newText: jsonStringPrefix(argsRaw, "content")?.value,
|
|
114
|
+
replaceAll: !1
|
|
94
115
|
};
|
|
95
116
|
if (name2 === "edit")
|
|
96
117
|
return {
|
|
@@ -101,7 +122,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
101
122
|
path: jsonStringPrefix(argsRaw, "file_path")?.value,
|
|
102
123
|
operation: "replace-text",
|
|
103
124
|
oldText: completedString(argsRaw, "old_string"),
|
|
104
|
-
newText: jsonStringPrefix(argsRaw, "new_string")?.value
|
|
125
|
+
newText: jsonStringPrefix(argsRaw, "new_string")?.value,
|
|
126
|
+
replaceAll: complete?.replace_all === !0
|
|
105
127
|
};
|
|
106
128
|
if (name2 !== "str_replace_editor") return;
|
|
107
129
|
let command = completedString(argsRaw, "command");
|
|
@@ -115,7 +137,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
115
137
|
path,
|
|
116
138
|
operation: "replace-file",
|
|
117
139
|
oldText: void 0,
|
|
118
|
-
newText: jsonStringPrefix(argsRaw, "file_text")?.value
|
|
140
|
+
newText: jsonStringPrefix(argsRaw, "file_text")?.value,
|
|
141
|
+
replaceAll: !1
|
|
119
142
|
} : command === "str_replace" ? {
|
|
120
143
|
callId,
|
|
121
144
|
name: name2,
|
|
@@ -124,7 +147,8 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
124
147
|
path,
|
|
125
148
|
operation: "replace-text",
|
|
126
149
|
oldText: completedString(argsRaw, "old_str"),
|
|
127
|
-
newText: jsonStringPrefix(argsRaw, "new_str")?.value
|
|
150
|
+
newText: jsonStringPrefix(argsRaw, "new_str")?.value ?? (complete !== void 0 ? "" : void 0),
|
|
151
|
+
replaceAll: complete?.replace_all === !0
|
|
128
152
|
} : command === "insert" ? {
|
|
129
153
|
callId,
|
|
130
154
|
name: name2,
|
|
@@ -133,27 +157,71 @@ function mutation(name2, callId, argsRaw, stage) {
|
|
|
133
157
|
path,
|
|
134
158
|
operation: "insert-text",
|
|
135
159
|
oldText: void 0,
|
|
136
|
-
newText: jsonStringPrefix(argsRaw, "new_str")?.value
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
160
|
+
newText: jsonStringPrefix(argsRaw, "new_str")?.value,
|
|
161
|
+
replaceAll: !1
|
|
162
|
+
} : { callId, name: name2, argsRaw, stage, path, operation: void 0, oldText: void 0, newText: void 0, replaceAll: !1 };
|
|
163
|
+
}
|
|
164
|
+
function mutationsFromRunning(call) {
|
|
165
|
+
let direct = mutationFromArgs(call.name, call.callId, call.argsRaw, "running");
|
|
166
|
+
if (direct === void 0) return [];
|
|
167
|
+
let view = call.callView;
|
|
168
|
+
return view?.card !== "diff" || view.diffs.length === 0 ? [direct] : view.diffs.map((diff, index) => ({
|
|
169
|
+
...direct,
|
|
170
|
+
callId: view.diffs.length === 1 ? call.callId : `${call.callId}:${String(index)}`,
|
|
171
|
+
path: diff.path,
|
|
172
|
+
operation: diff.oldText === null ? "replace-file" : "replace-text",
|
|
173
|
+
oldText: diff.oldText ?? void 0,
|
|
174
|
+
newText: diff.newText
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
function visitRunning(blocks, visit) {
|
|
178
|
+
for (let block of blocks)
|
|
179
|
+
"kind" in block || visit(block), visitRunning(block.subCalls, visit);
|
|
180
|
+
}
|
|
181
|
+
function fileMutations(runningCalls, partial = null) {
|
|
182
|
+
let values = [];
|
|
183
|
+
visitRunning(runningCalls, (call) => {
|
|
184
|
+
values.push(...mutationsFromRunning(call));
|
|
185
|
+
});
|
|
186
|
+
for (let block of partial?.blocks ?? []) {
|
|
187
|
+
if (block.kind !== "tool-call") continue;
|
|
188
|
+
let value = mutationFromArgs(block.name, block.callId, block.argsRaw, "streaming");
|
|
189
|
+
value !== void 0 && !values.some((candidate) => candidate.callId === value.callId) && values.push(value);
|
|
145
190
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
191
|
+
return values;
|
|
192
|
+
}
|
|
193
|
+
function mutatingCallIds(runningCalls) {
|
|
194
|
+
let ids = /* @__PURE__ */ new Set();
|
|
195
|
+
return visitRunning(runningCalls, (call) => {
|
|
196
|
+
MUTATING_CALLS.has(call.name) && ids.add(call.callId);
|
|
197
|
+
}), ids;
|
|
198
|
+
}
|
|
199
|
+
function settledMutationSignals(block) {
|
|
200
|
+
let nested = block.subCalls.flatMap(settledMutationSignals);
|
|
201
|
+
if (!("kind" in block) || block.isError) return nested;
|
|
202
|
+
let diffs = block.resultView?.card === "diff" ? block.resultView.diffs : block.callView?.card === "diff" ? block.callView.diffs : void 0;
|
|
203
|
+
if (diffs !== void 0) return [
|
|
204
|
+
...diffs.map((diff, index) => `${block.callId}:${String(index)}\0${diff.path}`),
|
|
205
|
+
...nested
|
|
206
|
+
];
|
|
207
|
+
if (block.call === null) return nested;
|
|
208
|
+
let mutation = mutationFromArgs(block.call.name, block.callId, block.call.argsRaw, "running");
|
|
209
|
+
return mutation?.path === void 0 ? nested : [`${block.callId}\0${mutation.path}`, ...nested];
|
|
210
|
+
}
|
|
211
|
+
function latestSettledMutation(chat) {
|
|
212
|
+
for (let key of chat.order.toReversed()) {
|
|
213
|
+
let node = chat.nodes.get(key);
|
|
214
|
+
if (node?.kind !== "tool-call") continue;
|
|
215
|
+
let root = node.data.root, signal = root === void 0 ? void 0 : settledMutationSignals(root).at(-1);
|
|
216
|
+
if (signal !== void 0) return signal;
|
|
151
217
|
}
|
|
152
218
|
}
|
|
153
219
|
function creativeRelativePath(path, cwd) {
|
|
154
220
|
if (path === void 0 || path === "") return;
|
|
155
|
-
let normalized = path.replaceAll("\\", "/"), root = cwd?.replaceAll("\\", "/").replace(/\/$/u, ""),
|
|
156
|
-
if (
|
|
221
|
+
let normalized = path.replaceAll("\\", "/"), root = cwd?.replaceAll("\\", "/").replace(/\/$/u, ""), insideRoot = root !== void 0 && normalized.startsWith(`${root}/`);
|
|
222
|
+
if ((normalized.startsWith("/") || /^[a-z]:\//iu.test(normalized) || normalized.startsWith("file:")) && !insideRoot) return;
|
|
223
|
+
let relative = insideRoot ? normalized.slice(root.length + 1) : normalized.replace(/^\.\//u, ""), [directory2] = relative.split("/", 1);
|
|
224
|
+
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
225
|
return relative;
|
|
158
226
|
}
|
|
159
227
|
function workbenchModeForPath(path) {
|
|
@@ -165,7 +233,8 @@ function workbenchModeForPath(path) {
|
|
|
165
233
|
function previewMutation(activity, base) {
|
|
166
234
|
if (activity.operation === "replace-file") return activity.newText;
|
|
167
235
|
if (activity.operation === "replace-text") {
|
|
168
|
-
if (activity.oldText === void 0 || activity.newText === void 0) return;
|
|
236
|
+
if (activity.oldText === void 0 || activity.newText === void 0 || activity.oldText === "") return;
|
|
237
|
+
if (activity.replaceAll) return base.includes(activity.oldText) ? base.split(activity.oldText).join(activity.newText) : void 0;
|
|
169
238
|
let at = base.indexOf(activity.oldText);
|
|
170
239
|
return at < 0 ? void 0 : `${base.slice(0, at)}${activity.newText}${base.slice(at + activity.oldText.length)}`;
|
|
171
240
|
}
|
|
@@ -457,16 +526,16 @@ function MarkdownPreview({ content, label }) {
|
|
|
457
526
|
|
|
458
527
|
// inline-css:/home/runner/work/oh-story-dsh/oh-story-dsh/packages/dsh-plugin/src/client/plugin.css
|
|
459
528
|
var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
460
|
-
.oh-story-split-surface { display: contents; }
|
|
529
|
+
.oh-story-split-surface { display: contents; font-family: var(--dsw-font-family); }
|
|
461
530
|
|
|
462
531
|
/* DSH documents every [data-slot] wrapper as a stable addressable styling
|
|
463
532
|
seam. The official Session body and composer stay mounted; this only turns
|
|
464
533
|
their scroll host into a three-column writing surface. */
|
|
465
534
|
[data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
|
|
466
535
|
--os-border: var(--dsw-alias-border-l2);
|
|
467
|
-
--os-muted: var(--dsw-alias-label-
|
|
536
|
+
--os-muted: var(--dsw-alias-label-secondary);
|
|
468
537
|
display: grid;
|
|
469
|
-
grid-template-columns: clamp(
|
|
538
|
+
grid-template-columns: clamp(184px, 16%, 200px) minmax(240px, 1fr) clamp(408px, 40%, 520px);
|
|
470
539
|
grid-template-rows: minmax(0, 1fr);
|
|
471
540
|
min-height: 0;
|
|
472
541
|
overflow-x: hidden;
|
|
@@ -534,7 +603,10 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
534
603
|
gap: 12px;
|
|
535
604
|
}
|
|
536
605
|
|
|
537
|
-
.oh-story-brand { min-height: 28px; padding: 0 5px
|
|
606
|
+
.oh-story-brand { min-height: 28px; gap: 8px; padding: 0 5px 8px 7px; font-size: 14px; font-weight: 500; white-space: nowrap; }
|
|
607
|
+
.oh-story-brand-cluster { display: flex; min-width: 0; align-items: center; gap: 6px; }
|
|
608
|
+
.oh-story-brand-cluster strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: inherit; }
|
|
609
|
+
.oh-story-kind { flex: none; padding: 1px 6px; border-radius: 5px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-button-ghost-active-fill); font-size: 11px; line-height: 16px; font-weight: 500; }
|
|
538
610
|
|
|
539
611
|
.oh-story-brand button,
|
|
540
612
|
.oh-story-save,
|
|
@@ -560,39 +632,26 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
560
632
|
.oh-story-role button:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -2px; }
|
|
561
633
|
.oh-story-save:disabled { opacity: .48; cursor: default; }
|
|
562
634
|
|
|
563
|
-
.oh-story-mode-tabs {
|
|
564
|
-
display: grid;
|
|
565
|
-
grid-template-columns: 1fr 1fr;
|
|
566
|
-
margin: 0 4px 10px;
|
|
567
|
-
border-bottom: 1px solid var(--os-border);
|
|
568
|
-
}
|
|
635
|
+
.oh-story-mode-tabs { display: flex; margin: 0 4px 8px; padding: 2px; border: 1px solid var(--os-border); border-radius: 7px; background: var(--dsw-alias-bg-layer-1); }
|
|
569
636
|
|
|
570
637
|
.oh-story-mode-tabs button,
|
|
571
638
|
.oh-story-editor-tabs button {
|
|
572
639
|
position: relative;
|
|
573
|
-
min-height:
|
|
640
|
+
min-height: 24px;
|
|
641
|
+
flex: 1;
|
|
574
642
|
border: 0;
|
|
575
643
|
color: var(--os-muted);
|
|
576
644
|
background: transparent;
|
|
645
|
+
border-radius: 5px;
|
|
577
646
|
cursor: pointer;
|
|
578
647
|
font: inherit;
|
|
579
|
-
font-size:
|
|
648
|
+
font-size: 11px;
|
|
580
649
|
}
|
|
581
650
|
|
|
582
651
|
.oh-story-mode-tabs button:hover,
|
|
583
652
|
.oh-story-editor-tabs button:hover { color: var(--dsw-alias-label-primary); }
|
|
584
653
|
.oh-story-mode-tabs button[aria-selected="true"],
|
|
585
|
-
.oh-story-editor-tabs button[aria-selected="true"] { color: var(--dsw-alias-label-primary); font-weight: 500; }
|
|
586
|
-
.oh-story-mode-tabs button[aria-selected="true"]::after {
|
|
587
|
-
position: absolute;
|
|
588
|
-
right: 14px;
|
|
589
|
-
bottom: -1px;
|
|
590
|
-
left: 14px;
|
|
591
|
-
height: 2px;
|
|
592
|
-
border-radius: 2px 2px 0 0;
|
|
593
|
-
background: var(--dsw-alias-state-business-primary);
|
|
594
|
-
content: "";
|
|
595
|
-
}
|
|
654
|
+
.oh-story-editor-tabs button[aria-selected="true"] { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-base); box-shadow: 0 1px 2px rgb(0 0 0 / 8%); font-weight: 500; }
|
|
596
655
|
|
|
597
656
|
.oh-story-file-group,
|
|
598
657
|
.oh-story-file-folder { margin: 0; }
|
|
@@ -610,6 +669,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
610
669
|
font-size: 11px;
|
|
611
670
|
font-weight: 600;
|
|
612
671
|
}
|
|
672
|
+
.oh-story-file-folder > summary { padding-left: min(calc(7px + var(--oh-story-indent, 0px)), 49px); }
|
|
613
673
|
.oh-story-file-group > summary { margin-top: 3px; }
|
|
614
674
|
.oh-story-file-group > summary::-webkit-details-marker,
|
|
615
675
|
.oh-story-file-folder > summary::-webkit-details-marker { display: none; }
|
|
@@ -620,13 +680,13 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
620
680
|
.oh-story-file-group > summary:hover,
|
|
621
681
|
.oh-story-file-folder > summary:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
|
|
622
682
|
.oh-story-file-group > summary span,
|
|
623
|
-
.oh-story-file-folder > summary span { margin-left: auto; color: var(--dsw-alias-label-
|
|
683
|
+
.oh-story-file-folder > summary span { margin-left: auto; color: var(--dsw-alias-label-secondary); font-weight: 400; }
|
|
624
684
|
|
|
625
685
|
.oh-story-tree nav button {
|
|
626
686
|
display: block;
|
|
627
687
|
width: 100%;
|
|
628
688
|
overflow: hidden;
|
|
629
|
-
padding: 6px 8px;
|
|
689
|
+
padding: 6px 8px 6px min(calc(14px + var(--oh-story-indent, 0px)), 56px);
|
|
630
690
|
border: 0;
|
|
631
691
|
border-radius: 6px;
|
|
632
692
|
color: inherit;
|
|
@@ -649,13 +709,17 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
649
709
|
border-bottom: 1px solid var(--os-border);
|
|
650
710
|
}
|
|
651
711
|
|
|
652
|
-
.oh-story-editor
|
|
712
|
+
.oh-story-editor-path {
|
|
653
713
|
overflow: hidden;
|
|
714
|
+
min-width: 0;
|
|
715
|
+
flex: 1;
|
|
654
716
|
text-overflow: ellipsis;
|
|
655
717
|
white-space: nowrap;
|
|
656
718
|
font-size: 12px;
|
|
657
719
|
color: var(--os-muted);
|
|
658
720
|
}
|
|
721
|
+
.oh-story-editor-path > span { overflow: hidden; display: block; text-overflow: ellipsis; }
|
|
722
|
+
.oh-story-editor-path > strong { display: none; overflow: hidden; text-overflow: ellipsis; font: inherit; }
|
|
659
723
|
|
|
660
724
|
.oh-story-editor-actions { display: flex; flex: none; align-items: center; gap: 8px; }
|
|
661
725
|
.oh-story-editor-tabs {
|
|
@@ -666,7 +730,6 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
666
730
|
background: var(--dsw-alias-bg-layer-1);
|
|
667
731
|
}
|
|
668
732
|
.oh-story-editor-tabs button { min-height: 24px; padding: 0 9px; border-radius: 5px; font-size: 11px; }
|
|
669
|
-
.oh-story-editor-tabs button[aria-selected="true"] { background: var(--dsw-alias-bg-base); box-shadow: 0 1px 2px rgb(0 0 0 / 8%); }
|
|
670
733
|
.oh-story-save { min-height: 28px; }
|
|
671
734
|
|
|
672
735
|
.oh-story-editor textarea {
|
|
@@ -677,7 +740,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
677
740
|
resize: none;
|
|
678
741
|
border: 0;
|
|
679
742
|
outline: 0;
|
|
680
|
-
padding: clamp(20px,
|
|
743
|
+
padding: clamp(20px, 6%, 48px) clamp(22px, 10%, 84px) 48px;
|
|
681
744
|
color: var(--dsw-alias-label-primary);
|
|
682
745
|
background: transparent;
|
|
683
746
|
font: 16px/1.9 ui-serif, "Songti SC", "STSong", Georgia, serif;
|
|
@@ -693,7 +756,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
693
756
|
min-height: 0;
|
|
694
757
|
flex: 1;
|
|
695
758
|
overflow: auto;
|
|
696
|
-
padding: clamp(24px,
|
|
759
|
+
padding: clamp(24px, 8%, 56px) clamp(24px, 10%, 92px) 64px;
|
|
697
760
|
color: var(--dsw-alias-label-primary);
|
|
698
761
|
font: 16px/1.85 ui-serif, "Songti SC", "STSong", Georgia, serif;
|
|
699
762
|
overflow-wrap: anywhere;
|
|
@@ -705,7 +768,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
705
768
|
.oh-story-markdown h3,
|
|
706
769
|
.oh-story-markdown h4,
|
|
707
770
|
.oh-story-markdown h5,
|
|
708
|
-
.oh-story-markdown h6 { margin: 1.45em 0 .6em; font-family:
|
|
771
|
+
.oh-story-markdown h6 { margin: 1.45em 0 .6em; font-family: var(--dsw-font-family); line-height: 1.35; letter-spacing: -.01em; }
|
|
709
772
|
.oh-story-markdown h1 { font-size: 1.75em; }
|
|
710
773
|
.oh-story-markdown h2 { padding-bottom: .35em; border-bottom: 1px solid var(--os-border); font-size: 1.35em; }
|
|
711
774
|
.oh-story-markdown h3 { font-size: 1.15em; }
|
|
@@ -750,7 +813,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
750
813
|
.oh-story-jsonl-records { overflow: auto; padding: 14px 18px 36px; }
|
|
751
814
|
.oh-story-jsonl details,
|
|
752
815
|
.oh-story-jsonl-error { overflow: hidden; margin-bottom: 10px; border: 1px solid var(--os-border); border-radius: 10px; background: var(--dsw-alias-bg-layer-1); }
|
|
753
|
-
.oh-story-jsonl summary { display: flex; min-height: 42px; align-items: center; gap: 9px; padding: 0 12px; cursor: pointer; list-style: none; font: 12px/1.4
|
|
816
|
+
.oh-story-jsonl summary { display: flex; min-height: 42px; align-items: center; gap: 9px; padding: 0 12px; cursor: pointer; list-style: none; font: 12px/1.4 var(--dsw-font-family); }
|
|
754
817
|
.oh-story-jsonl summary::-webkit-details-marker { display: none; }
|
|
755
818
|
.oh-story-jsonl summary::before { content: "\u203A"; color: var(--os-muted); font-size: 16px; transition: transform .12s ease; }
|
|
756
819
|
.oh-story-jsonl details[open] summary::before { transform: rotate(90deg); }
|
|
@@ -765,7 +828,8 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
765
828
|
.oh-story-jsonl-error pre { margin: 3px -12px -12px; }
|
|
766
829
|
|
|
767
830
|
.oh-story-stream,
|
|
768
|
-
.oh-story-conflict
|
|
831
|
+
.oh-story-conflict,
|
|
832
|
+
.oh-story-warning {
|
|
769
833
|
flex: none;
|
|
770
834
|
padding: 7px 12px;
|
|
771
835
|
border-bottom: 1px solid var(--os-border);
|
|
@@ -776,6 +840,18 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
776
840
|
.oh-story-stream { color: var(--dsw-alias-state-business-primary); background: var(--dsw-alias-button-ghost-active-fill); }
|
|
777
841
|
.oh-story-stream[data-stage="streaming"] { animation: oh-story-pulse 1.2s ease-in-out infinite alternate; }
|
|
778
842
|
.oh-story-conflict { color: var(--dsw-alias-state-warn-label); background: var(--dsw-specific-tip); }
|
|
843
|
+
.oh-story-conflict > div { display: flex; gap: 6px; margin-top: 6px; }
|
|
844
|
+
.oh-story-conflict button,
|
|
845
|
+
.oh-story-empty button {
|
|
846
|
+
border: 1px solid var(--os-border);
|
|
847
|
+
border-radius: 6px;
|
|
848
|
+
color: inherit;
|
|
849
|
+
background: var(--dsw-alias-bg-base);
|
|
850
|
+
padding: 3px 8px;
|
|
851
|
+
cursor: pointer;
|
|
852
|
+
font: inherit;
|
|
853
|
+
}
|
|
854
|
+
.oh-story-warning { color: var(--dsw-alias-state-warn-label); background: var(--dsw-specific-tip); }
|
|
779
855
|
|
|
780
856
|
@keyframes oh-story-pulse { to { opacity: .62; } }
|
|
781
857
|
@media (prefers-reduced-motion: reduce) { .oh-story-stream[data-stage="streaming"] { animation: none; } }
|
|
@@ -793,19 +869,104 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
|
|
|
793
869
|
.oh-story-role pre { max-height: 260px; overflow: auto; margin: 4px 0 4px 4px; padding: 12px 16px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 12px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-markdown-code-block); white-space: pre-wrap; font: var(--dsw-font-markdown-code-block-small); }
|
|
794
870
|
.oh-story-role > button { align-self: flex-start; margin: 4px 0 2px 4px; font-size: 11px; }
|
|
795
871
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
872
|
+
[data-conversation-scroll][data-oh-story-layout="medium"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
|
|
873
|
+
grid-template-columns: clamp(104px, 18%, 184px) minmax(200px, 1fr) clamp(300px, 45%, 408px);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
[data-conversation-scroll][data-oh-story-layout="compact"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
|
|
877
|
+
grid-template-columns: clamp(80px, 16%, 104px) minmax(0, 1fr) clamp(228px, 48%, 300px);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
[data-oh-story-layout="medium"] .oh-story-file-folder > summary { padding-left: min(calc(7px + var(--oh-story-indent, 0px)), 35px); }
|
|
881
|
+
[data-oh-story-layout="medium"] .oh-story-tree nav button { padding-left: min(calc(14px + var(--oh-story-indent, 0px)), 42px); }
|
|
882
|
+
[data-oh-story-layout="medium"] .oh-story-editor textarea { padding-right: 28px; padding-left: 28px; }
|
|
883
|
+
|
|
884
|
+
[data-oh-story-layout="compact"] .oh-story-tree { padding-inline: 4px; }
|
|
885
|
+
[data-oh-story-layout="compact"] .oh-story-brand { gap: 4px; padding-inline: 2px; font-size: 11px; }
|
|
886
|
+
[data-oh-story-layout="compact"] .oh-story-brand-cluster { gap: 4px; }
|
|
887
|
+
[data-oh-story-layout="compact"] .oh-story-brand-cluster strong > span { display: none; }
|
|
888
|
+
[data-oh-story-layout="compact"] .oh-story-kind { padding-inline: 4px; font-size: 11px; }
|
|
889
|
+
[data-oh-story-layout="compact"] .oh-story-brand button { width: 24px; height: 24px; }
|
|
890
|
+
[data-oh-story-layout="compact"] .oh-story-mode-tabs { margin-inline: 0; }
|
|
891
|
+
[data-oh-story-layout="compact"] .oh-story-mode-tabs button { padding-inline: 3px; font-size: 11px; }
|
|
892
|
+
[data-oh-story-layout="compact"] .oh-story-file-folder > summary { padding-left: min(calc(5px + var(--oh-story-indent, 0px)), 19px); }
|
|
893
|
+
[data-oh-story-layout="compact"] .oh-story-tree nav button { padding-right: 4px; padding-left: min(calc(7px + var(--oh-story-indent, 0px)), 21px); }
|
|
894
|
+
[data-oh-story-layout="compact"] .oh-story-editor header {
|
|
895
|
+
display: grid;
|
|
896
|
+
min-height: 68px;
|
|
897
|
+
grid-template-columns: minmax(0, 1fr);
|
|
898
|
+
grid-template-rows: 24px 36px;
|
|
899
|
+
align-content: center;
|
|
900
|
+
gap: 0;
|
|
901
|
+
padding: 4px 3px;
|
|
801
902
|
}
|
|
903
|
+
[data-oh-story-layout="compact"] .oh-story-editor-path > span { display: none; }
|
|
904
|
+
[data-oh-story-layout="compact"] .oh-story-editor-path > strong { display: block; font-size: 11px; line-height: 24px; }
|
|
905
|
+
[data-oh-story-layout="compact"] .oh-story-editor-actions { width: 100%; min-width: 0; justify-content: flex-end; gap: 4px; }
|
|
906
|
+
[data-oh-story-layout="compact"] .oh-story-editor-tabs { min-width: 0; flex: 1; }
|
|
907
|
+
[data-oh-story-layout="compact"] .oh-story-editor-tabs button { min-width: 0; padding-inline: 2px; white-space: nowrap; }
|
|
908
|
+
[data-oh-story-layout="compact"] .oh-story-save { flex: none; padding-inline: 4px; white-space: nowrap; font-size: 11px; }
|
|
909
|
+
[data-oh-story-layout="compact"] .oh-story-editor textarea { padding: 16px 12px 40px; }
|
|
910
|
+
[data-oh-story-layout="compact"] .oh-story-markdown { padding: 18px 12px 48px; }
|
|
911
|
+
[data-oh-story-layout="compact"] .oh-story-jsonl-summary { padding-inline: 10px; }
|
|
912
|
+
[data-oh-story-layout="compact"] .oh-story-jsonl-records { padding: 8px 7px 28px; }
|
|
913
|
+
[data-oh-story-layout="compact"] .oh-story-jsonl summary { gap: 6px; padding-inline: 7px; }
|
|
914
|
+
[data-oh-story-layout="compact"] .oh-story-jsonl summary > span { display: none; }
|
|
915
|
+
[data-oh-story-layout="compact"] .oh-story-jsonl summary > strong { min-width: 32px; }
|
|
916
|
+
[data-oh-story-layout="compact"] .oh-story-jsonl summary > code,
|
|
917
|
+
[data-oh-story-layout="compact"] .oh-story-jsonl summary > em { display: none; }
|
|
802
918
|
`;
|
|
803
919
|
|
|
804
920
|
// src/client/index.tsx
|
|
805
|
-
var import_jsx_runtime3 = require("react/jsx-runtime"), name = "oh-story", inject = ["slots"]
|
|
921
|
+
var import_jsx_runtime3 = require("react/jsx-runtime"), name = "oh-story", inject = ["slots"];
|
|
922
|
+
function applyUpdate(current, update) {
|
|
923
|
+
return typeof update == "function" ? update(current) : update;
|
|
924
|
+
}
|
|
925
|
+
function createWorkbenchStore() {
|
|
926
|
+
return (0, import_client.defineStore)({
|
|
927
|
+
init: () => ({
|
|
928
|
+
buffers: {},
|
|
929
|
+
editorMode: "preview",
|
|
930
|
+
expanded: {},
|
|
931
|
+
selected: void 0,
|
|
932
|
+
workbench: "story"
|
|
933
|
+
}),
|
|
934
|
+
actions: {
|
|
935
|
+
setBuffers: (draft, update) => {
|
|
936
|
+
draft.buffers = applyUpdate(draft.buffers, update);
|
|
937
|
+
},
|
|
938
|
+
setEditorMode: (draft, update) => {
|
|
939
|
+
draft.editorMode = applyUpdate(draft.editorMode, update);
|
|
940
|
+
},
|
|
941
|
+
setExpanded: (draft, update) => {
|
|
942
|
+
draft.expanded = applyUpdate(draft.expanded, update);
|
|
943
|
+
},
|
|
944
|
+
setSelected: (draft, update) => {
|
|
945
|
+
draft.selected = applyUpdate(draft.selected, update);
|
|
946
|
+
},
|
|
947
|
+
setWorkbench: (draft, update) => {
|
|
948
|
+
draft.workbench = applyUpdate(draft.workbench, update);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
var WorkspaceRequestError = class extends Error {
|
|
954
|
+
constructor(status, message) {
|
|
955
|
+
super(message);
|
|
956
|
+
this.status = status;
|
|
957
|
+
}
|
|
958
|
+
status;
|
|
959
|
+
}, GROUP_ORDER = {
|
|
806
960
|
story: ["\u6B63\u6587", "\u5927\u7EB2", "\u8BBE\u5B9A", "\u8FFD\u8E2A", "\u5BF9\u6807", "\u53C2\u8003\u8D44\u6599"],
|
|
807
961
|
drama: ["\u9879\u76EE", "\u8F93\u5165", "\u9879\u76EE\u5F00\u53D1", "\u8BBE\u5B9A\u96C6", "\u5267\u96C6", "\u5BA1\u67E5", "\u521B\u4F5C\u8005\u51B3\u7B56", "\u4EA4\u4ED8"]
|
|
808
|
-
};
|
|
962
|
+
}, WORKBENCH_MODES = ["story", "drama"], EDITOR_MODES = ["preview", "source"];
|
|
963
|
+
function handleTabKey(event, values, current, select) {
|
|
964
|
+
let index;
|
|
965
|
+
if (event.key === "Home" ? index = 0 : event.key === "End" ? index = values.length - 1 : event.key === "ArrowRight" ? index = (values.indexOf(current) + 1) % values.length : event.key === "ArrowLeft" && (index = (values.indexOf(current) - 1 + values.length) % values.length), index === void 0) return;
|
|
966
|
+
event.preventDefault();
|
|
967
|
+
let value = values[index];
|
|
968
|
+
value !== void 0 && (select(value), event.currentTarget.parentElement?.querySelectorAll("[role='tab']")[index]?.focus());
|
|
969
|
+
}
|
|
809
970
|
function groupForPath(path) {
|
|
810
971
|
return path === "short-drama.json" ? "\u9879\u76EE" : path.split("/", 1)[0] ?? "\u5176\u4ED6";
|
|
811
972
|
}
|
|
@@ -817,14 +978,13 @@ function preferredFile(files, mode) {
|
|
|
817
978
|
}
|
|
818
979
|
return matching[0]?.path;
|
|
819
980
|
}
|
|
820
|
-
var EMPTY_BLOCKS = [], EMPTY_CALLS = [];
|
|
821
981
|
function endpoint(path, sessionId, file) {
|
|
822
982
|
let url = new URL(`/oh-story/${path}`, globalThis.location.origin);
|
|
823
983
|
return url.searchParams.set("sessionId", sessionId), file !== void 0 && url.searchParams.set("path", file), url.toString();
|
|
824
984
|
}
|
|
825
985
|
async function json(response) {
|
|
826
986
|
let value = await response.json();
|
|
827
|
-
if (!response.ok) throw new
|
|
987
|
+
if (!response.ok) throw new WorkspaceRequestError(response.status, value.error ?? `HTTP ${String(response.status)}`);
|
|
828
988
|
return value;
|
|
829
989
|
}
|
|
830
990
|
function FileTreeNodes({
|
|
@@ -841,7 +1001,9 @@ function FileTreeNodes({
|
|
|
841
1001
|
"button",
|
|
842
1002
|
{
|
|
843
1003
|
type: "button",
|
|
844
|
-
style: {
|
|
1004
|
+
style: { "--oh-story-indent": `${String(depth * 14)}px` },
|
|
1005
|
+
title: node.path,
|
|
1006
|
+
"aria-label": node.path,
|
|
845
1007
|
"data-file-path": node.path,
|
|
846
1008
|
"data-agent-target": node.path === activityPath || void 0,
|
|
847
1009
|
"aria-current": node.path === selected ? "page" : void 0,
|
|
@@ -852,11 +1014,11 @@ function FileTreeNodes({
|
|
|
852
1014
|
},
|
|
853
1015
|
node.path
|
|
854
1016
|
);
|
|
855
|
-
let open =
|
|
1017
|
+
let open = selected?.startsWith(`${node.path}/`) === !0 || expanded[node.path] === !0;
|
|
856
1018
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "oh-story-file-folder", open, onToggle: (event) => {
|
|
857
1019
|
onToggle(node.path, event.currentTarget.open);
|
|
858
1020
|
}, children: [
|
|
859
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("summary", { style: {
|
|
1021
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("summary", { style: { "--oh-story-indent": `${String(depth * 14)}px` }, title: node.path, children: [
|
|
860
1022
|
node.name,
|
|
861
1023
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: node.fileCount })
|
|
862
1024
|
] }),
|
|
@@ -876,89 +1038,182 @@ function FileTreeNodes({
|
|
|
876
1038
|
}) });
|
|
877
1039
|
}
|
|
878
1040
|
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);
|
|
1041
|
+
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)(() => {
|
|
1042
|
+
setLoading(!0), setVersion((value) => value + 1);
|
|
881
1043
|
}, []);
|
|
882
1044
|
return (0, import_react.useEffect)(() => {
|
|
883
1045
|
let controller = new AbortController();
|
|
884
1046
|
return setError(void 0), fetch(endpoint("workspace", sessionId), { signal: controller.signal }).then((response) => json(response)).then(setWorkspace).catch((reason) => {
|
|
885
1047
|
controller.signal.aborted || setError(reason instanceof Error ? reason.message : String(reason));
|
|
1048
|
+
}).finally(() => {
|
|
1049
|
+
controller.signal.aborted || setLoading(!1);
|
|
886
1050
|
}), () => {
|
|
887
1051
|
controller.abort();
|
|
888
1052
|
};
|
|
889
|
-
}, [sessionId, version]), { workspace, error, reload };
|
|
1053
|
+
}, [sessionId, version]), { workspace, error, loading, reload };
|
|
890
1054
|
}
|
|
891
|
-
function CreativeWorkbench({
|
|
892
|
-
|
|
1055
|
+
function CreativeWorkbench({
|
|
1056
|
+
sessionId,
|
|
1057
|
+
runningCalls,
|
|
1058
|
+
partial,
|
|
1059
|
+
settledMutation,
|
|
1060
|
+
useStore,
|
|
1061
|
+
actions
|
|
1062
|
+
}) {
|
|
1063
|
+
let { workspace, error, loading: workspaceLoading, reload } = useWorkspace(sessionId), activities = (0, import_react.useMemo)(
|
|
1064
|
+
() => fileMutations(runningCalls, partial),
|
|
1065
|
+
[partial, runningCalls]
|
|
1066
|
+
), normalizedActivities = (0, import_react.useMemo)(() => activities.flatMap((activity2) => {
|
|
1067
|
+
let path = creativeRelativePath(activity2.path, workspace?.cwd);
|
|
1068
|
+
return path === void 0 ? [] : [{ activity: activity2, path }];
|
|
1069
|
+
}), [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, workbench = useStore((memory) => memory.workbench), setWorkbench = actions.setWorkbench, initializedWorkbench = (0, import_react.useRef)(!1), selected = useStore((memory) => memory.selected), setSelected = actions.setSelected, buffers = useStore((memory) => memory.buffers), setBuffers = actions.setBuffers, buffersRef = (0, import_react.useRef)({}), expanded = useStore((memory) => memory.expanded), setExpanded = actions.setExpanded, 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()), previousSettledMutation = (0, import_react.useRef)(settledMutation), 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 = useStore((memory) => memory.editorMode), setEditorMode = actions.setEditorMode, modeSelection = (0, import_react.useRef)(selected), textareaRef = (0, import_react.useRef)(null), editorPositions = (0, import_react.useRef)(/* @__PURE__ */ new Map()), editorReady = buffer !== void 0 && buffer.missing !== !0, availableModes = (0, import_react.useMemo)(() => {
|
|
1070
|
+
let value = /* @__PURE__ */ new Set();
|
|
1071
|
+
for (let file of workspace?.files ?? []) {
|
|
1072
|
+
let mode = workbenchModeForPath(file.path);
|
|
1073
|
+
mode !== void 0 && value.add(mode);
|
|
1074
|
+
}
|
|
1075
|
+
return WORKBENCH_MODES.filter((mode) => value.has(mode));
|
|
1076
|
+
}, [workspace?.files]), showModeTabs = workspace !== void 0 && availableModes.length !== 1, workspaceKind = availableModes.length === 1 ? availableModes[0] : void 0;
|
|
893
1077
|
(0, import_react.useEffect)(() => {
|
|
894
1078
|
buffersRef.current = buffers;
|
|
895
|
-
}, [buffers])
|
|
896
|
-
|
|
897
|
-
let
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
}, [
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
let
|
|
912
|
-
|
|
1079
|
+
}, [buffers]);
|
|
1080
|
+
let rememberEditorPosition = (0, import_react.useCallback)(() => {
|
|
1081
|
+
let element = textareaRef.current;
|
|
1082
|
+
element === null || selected === void 0 || element.getAttribute("aria-label") !== selected || editorPositions.current.set(selected, {
|
|
1083
|
+
scrollTop: element.scrollTop,
|
|
1084
|
+
selectionStart: element.selectionStart,
|
|
1085
|
+
selectionEnd: element.selectionEnd
|
|
1086
|
+
});
|
|
1087
|
+
}, [selected]);
|
|
1088
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
1089
|
+
if (editorMode !== "source" || selected === void 0 || !editorReady) return;
|
|
1090
|
+
let element = textareaRef.current, position = editorPositions.current.get(selected);
|
|
1091
|
+
if (element === null || position === void 0) return;
|
|
1092
|
+
let end = Math.min(position.selectionEnd, element.value.length);
|
|
1093
|
+
element.setSelectionRange(Math.min(position.selectionStart, end), end), element.scrollTop = position.scrollTop;
|
|
1094
|
+
}, [editorMode, editorReady, selected]), (0, import_react.useEffect)(() => {
|
|
1095
|
+
let warn = (event) => {
|
|
1096
|
+
Object.values(buffersRef.current).some((value) => value.source === "human" && value.content !== value.saved) && event.preventDefault();
|
|
1097
|
+
};
|
|
1098
|
+
return globalThis.addEventListener("beforeunload", warn), () => {
|
|
1099
|
+
globalThis.removeEventListener("beforeunload", warn);
|
|
1100
|
+
};
|
|
1101
|
+
}, []);
|
|
1102
|
+
let expandPath = (0, import_react.useCallback)((path) => {
|
|
1103
|
+
let segments = path.split("/"), ancestors = [groupForPath(path)];
|
|
1104
|
+
for (let index = 1; index < segments.length - 1; index += 1) ancestors.push(segments.slice(0, index + 1).join("/"));
|
|
1105
|
+
setExpanded((current) => {
|
|
1106
|
+
let next = { ...current };
|
|
1107
|
+
for (let ancestor of ancestors) next[ancestor] = !0;
|
|
1108
|
+
return next;
|
|
1109
|
+
});
|
|
1110
|
+
}, []), revealPath = (0, import_react.useCallback)((path) => {
|
|
1111
|
+
rememberEditorPosition(), setWorkbench(workbenchModeForPath(path) ?? "story"), setSelected(path), expandPath(path);
|
|
1112
|
+
}, [expandPath, rememberEditorPosition]), followAgentPath = (0, import_react.useCallback)((path) => {
|
|
1113
|
+
expandPath(path);
|
|
1114
|
+
let current = selected === void 0 ? void 0 : buffersRef.current[selected];
|
|
1115
|
+
path !== selected && current?.source === "human" && current.content !== current.saved && surfaceRef.current?.ownerDocument.activeElement === textareaRef.current || revealPath(path);
|
|
1116
|
+
}, [expandPath, revealPath, selected]);
|
|
1117
|
+
(0, import_react.useEffect)(() => {
|
|
1118
|
+
workspace === void 0 || initializedWorkbench.current || (availableModes.length === 1 && setWorkbench(availableModes[0] ?? "story"), initializedWorkbench.current = !0);
|
|
1119
|
+
}, [availableModes, workspace]), (0, import_react.useEffect)(() => {
|
|
1120
|
+
activityPath !== void 0 && activityPath === selected && setEditorMode("source");
|
|
1121
|
+
}, [activityPath, selected]), (0, import_react.useEffect)(() => {
|
|
1122
|
+
modeSelection.current !== selected && (modeSelection.current = selected, setEditorMode(activityPath === selected ? "source" : previewable ? "preview" : "source"));
|
|
1123
|
+
}, [activityPath, previewable, selected]), (0, import_react.useEffect)(() => {
|
|
1124
|
+
workspaceLoading || activityPath === void 0 && (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)));
|
|
1125
|
+
}, [activityPath, buffers, selected, workbench, workspace, workspaceLoading]), (0, import_react.useEffect)(() => {
|
|
1126
|
+
if (workspace === void 0 || workspaceLoading) return;
|
|
1127
|
+
let paths = new Set(workspace.files.map((file) => file.path));
|
|
1128
|
+
setBuffers((current) => {
|
|
1129
|
+
let changed = !1, next = { ...current };
|
|
1130
|
+
for (let [path, value] of Object.entries(current))
|
|
1131
|
+
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));
|
|
1132
|
+
return changed ? next : current;
|
|
1133
|
+
});
|
|
1134
|
+
}, [activityPaths, workspace, workspaceLoading]), (0, import_react.useEffect)(() => {
|
|
1135
|
+
if (selected === void 0 || activityPaths.has(selected) || !(workspace?.files.some((file) => file.path === selected) ?? !1)) return;
|
|
913
1136
|
let controller = new AbortController();
|
|
914
|
-
return
|
|
915
|
-
let existing =
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1137
|
+
return setBuffers((current) => {
|
|
1138
|
+
let existing = current[selected];
|
|
1139
|
+
return existing === void 0 ? current : { ...current, [selected]: { ...existing, error: void 0 } };
|
|
1140
|
+
}), fetch(endpoint("file", sessionId, selected), { signal: controller.signal }).then((response) => json(response)).then((file) => {
|
|
1141
|
+
setBuffers((current) => {
|
|
1142
|
+
let existing = current[file.path];
|
|
1143
|
+
return existing?.source === "human" && existing.content !== existing.saved ? existing.version === file.version ? { ...current, [file.path]: { ...existing, missing: !1, error: void 0 } } : {
|
|
1144
|
+
...current,
|
|
1145
|
+
[file.path]: {
|
|
1146
|
+
...existing,
|
|
1147
|
+
missing: !1,
|
|
1148
|
+
error: void 0,
|
|
1149
|
+
conflict: {
|
|
1150
|
+
message: `${file.path} \u5DF2\u5728\u78C1\u76D8\u4E0A\u66F4\u65B0\uFF1B\u4F60\u7684\u672C\u5730\u8349\u7A3F\u6CA1\u6709\u88AB\u8986\u76D6\u3002`,
|
|
1151
|
+
theirs: file.content,
|
|
1152
|
+
theirsVersion: file.version
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
} : {
|
|
1156
|
+
...current,
|
|
1157
|
+
[file.path]: { content: file.content, saved: file.content, source: "disk", version: file.version }
|
|
1158
|
+
};
|
|
1159
|
+
});
|
|
924
1160
|
}).catch((reason) => {
|
|
925
|
-
controller.signal.aborted ||
|
|
1161
|
+
controller.signal.aborted || setBuffers((current) => {
|
|
1162
|
+
let existing = current[selected];
|
|
1163
|
+
return existing === void 0 ? current : {
|
|
1164
|
+
...current,
|
|
1165
|
+
[selected]: { ...existing, error: reason instanceof Error ? reason.message : String(reason) }
|
|
1166
|
+
};
|
|
1167
|
+
});
|
|
926
1168
|
}), () => {
|
|
927
1169
|
controller.abort();
|
|
928
1170
|
};
|
|
929
|
-
}, [
|
|
930
|
-
if (
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1171
|
+
}, [activityPaths, selected, sessionId, workspace?.files]), (0, import_react.useEffect)(() => {
|
|
1172
|
+
if (normalizedActivities.length !== 0) {
|
|
1173
|
+
for (let { path } of normalizedActivities) expandPath(path);
|
|
1174
|
+
activityPath !== void 0 && followAgentPath(activityPath), setBuffers((current) => {
|
|
1175
|
+
let next = current;
|
|
1176
|
+
for (let { activity: currentActivity, path } of normalizedActivities) {
|
|
1177
|
+
let existing = next[path];
|
|
1178
|
+
if (existing?.source === "human" && existing.content !== existing.saved) {
|
|
1179
|
+
next = {
|
|
1180
|
+
...next,
|
|
1181
|
+
[path]: {
|
|
1182
|
+
...existing,
|
|
1183
|
+
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` }
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
let basis = activityBases.current.get(currentActivity.callId);
|
|
1189
|
+
(basis === void 0 || basis.path !== path) && (basis = { path, base: existing?.content ?? "" }, activityBases.current.set(currentActivity.callId, basis));
|
|
1190
|
+
let preview = previewMutation(currentActivity, basis.base);
|
|
1191
|
+
preview === void 0 || existing?.source === "agent" && existing.content === preview || (next = {
|
|
1192
|
+
...next,
|
|
1193
|
+
[path]: {
|
|
1194
|
+
content: preview,
|
|
1195
|
+
saved: existing?.saved ?? "",
|
|
1196
|
+
source: "agent",
|
|
1197
|
+
version: existing?.version ?? ""
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
947
1200
|
}
|
|
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;
|
|
1201
|
+
return next;
|
|
1202
|
+
});
|
|
954
1203
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1204
|
+
}, [activityPath, expandPath, followAgentPath, normalizedActivities]), (0, import_react.useEffect)(() => {
|
|
1205
|
+
let signals = new Set(mutatingCallIds(runningCalls));
|
|
1206
|
+
for (let { activity: currentActivity } of normalizedActivities) signals.add(currentActivity.callId.split(":", 1)[0] ?? currentActivity.callId);
|
|
1207
|
+
let settled = [...previousSignals.current].some((callId) => !signals.has(callId));
|
|
1208
|
+
for (let callId of activityBases.current.keys())
|
|
1209
|
+
signals.has(callId.split(":", 1)[0] ?? callId) || activityBases.current.delete(callId);
|
|
1210
|
+
previousSignals.current = signals, settled && reload();
|
|
1211
|
+
}, [normalizedActivities, reload, runningCalls]), (0, import_react.useEffect)(() => {
|
|
1212
|
+
if (settledMutation === void 0 || settledMutation === previousSettledMutation.current) return;
|
|
1213
|
+
previousSettledMutation.current = settledMutation;
|
|
1214
|
+
let path = creativeRelativePath(settledMutation.slice(settledMutation.indexOf("\0") + 1), workspace?.cwd);
|
|
1215
|
+
path !== void 0 && followAgentPath(path), reload();
|
|
1216
|
+
}, [followAgentPath, reload, settledMutation, workspace?.cwd]), (0, import_react.useEffect)(() => {
|
|
962
1217
|
if (selected !== void 0) {
|
|
963
1218
|
for (let button of navRef.current?.querySelectorAll("button[data-file-path]") ?? [])
|
|
964
1219
|
if (button.dataset.filePath === selected) {
|
|
@@ -967,7 +1222,7 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
967
1222
|
}
|
|
968
1223
|
}
|
|
969
1224
|
}, [selected]), (0, import_react.useEffect)(() => {
|
|
970
|
-
if (
|
|
1225
|
+
if (normalizedActivities.length > 0 || workspace === void 0) return;
|
|
971
1226
|
let sessionSurface = surfaceRef.current?.parentElement;
|
|
972
1227
|
if (sessionSurface == null) return;
|
|
973
1228
|
let knownPaths = new Set(workspace.files.map((file) => file.path)), followOfficialFileLink = (event) => {
|
|
@@ -977,9 +1232,9 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
977
1232
|
if (control === null || control.closest(".oh-story-split-surface") !== null) return;
|
|
978
1233
|
let candidates = [control.title, control.getAttribute("aria-label"), control.textContent];
|
|
979
1234
|
for (let candidate of candidates) {
|
|
980
|
-
let path = creativeRelativePath(candidate?.trim().replace(/^Open\s+/u, ""), workspace.cwd);
|
|
1235
|
+
let path = creativeRelativePath(candidate?.trim().replace(/^(?:Open|打开)\s+/u, ""), workspace.cwd);
|
|
981
1236
|
if (!(path === void 0 || !knownPaths.has(path))) {
|
|
982
|
-
event.preventDefault(), event.stopPropagation(),
|
|
1237
|
+
event.preventDefault(), event.stopPropagation(), revealPath(path);
|
|
983
1238
|
break;
|
|
984
1239
|
}
|
|
985
1240
|
}
|
|
@@ -987,39 +1242,88 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
987
1242
|
return sessionSurface.addEventListener("click", followOfficialFileLink, !0), () => {
|
|
988
1243
|
sessionSurface.removeEventListener("click", followOfficialFileLink, !0);
|
|
989
1244
|
};
|
|
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
|
-
|
|
1245
|
+
}, [normalizedActivities.length, revealPath, workspace]);
|
|
1246
|
+
let savePath = (0, import_react.useCallback)(async (path) => {
|
|
1247
|
+
if (saveLocks.current.has(path)) return;
|
|
1248
|
+
let submitted = buffersRef.current[path];
|
|
1249
|
+
if (!(submitted === void 0 || submitted.missing === !0 || submitted.content === submitted.saved)) {
|
|
1250
|
+
saveLocks.current.add(path), setBuffers((current) => {
|
|
1251
|
+
let existing = current[path];
|
|
1252
|
+
return existing === void 0 ? current : { ...current, [path]: { ...existing, saving: !0, error: void 0 } };
|
|
1253
|
+
});
|
|
1254
|
+
try {
|
|
1255
|
+
let file = await json(await fetch(endpoint("file", sessionId, path), {
|
|
1256
|
+
method: "PUT",
|
|
1257
|
+
headers: { "content-type": "application/json" },
|
|
1258
|
+
body: JSON.stringify({ content: submitted.content, baseVersion: submitted.version })
|
|
1259
|
+
}));
|
|
1260
|
+
setBuffers((current) => {
|
|
1261
|
+
let latest = current[path];
|
|
1262
|
+
if (latest === void 0) return current;
|
|
1263
|
+
let unchanged = latest.content === submitted.content;
|
|
1264
|
+
return {
|
|
1265
|
+
...current,
|
|
1266
|
+
[path]: {
|
|
1267
|
+
content: unchanged ? file.content : latest.content,
|
|
1268
|
+
saved: file.content,
|
|
1269
|
+
source: unchanged ? "disk" : "human",
|
|
1270
|
+
version: file.version,
|
|
1271
|
+
saving: !1
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
}), reload();
|
|
1275
|
+
} catch (reason) {
|
|
1276
|
+
if (reason instanceof WorkspaceRequestError && reason.status === 412)
|
|
1277
|
+
try {
|
|
1278
|
+
let theirs = await json(await fetch(endpoint("file", sessionId, path)));
|
|
1279
|
+
setBuffers((current) => {
|
|
1280
|
+
let latest = current[path];
|
|
1281
|
+
return latest === void 0 ? current : {
|
|
1282
|
+
...current,
|
|
1283
|
+
[path]: {
|
|
1284
|
+
...latest,
|
|
1285
|
+
saving: !1,
|
|
1286
|
+
conflict: {
|
|
1287
|
+
message: `${path} \u5DF2\u5728\u78C1\u76D8\u4E0A\u66F4\u65B0\uFF1B\u8BF7\u9009\u62E9\u4FDD\u7559\u54EA\u4E00\u7248\u3002`,
|
|
1288
|
+
theirs: theirs.content,
|
|
1289
|
+
theirsVersion: theirs.version
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
};
|
|
1293
|
+
});
|
|
1294
|
+
} catch (refreshError) {
|
|
1295
|
+
setBuffers((current) => {
|
|
1296
|
+
let existing = current[path];
|
|
1297
|
+
return existing === void 0 ? current : {
|
|
1298
|
+
...current,
|
|
1299
|
+
[path]: { ...existing, saving: !1, error: refreshError instanceof Error ? refreshError.message : String(refreshError) }
|
|
1300
|
+
};
|
|
1301
|
+
});
|
|
1012
1302
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1303
|
+
else
|
|
1304
|
+
setBuffers((current) => {
|
|
1305
|
+
let existing = current[path];
|
|
1306
|
+
return existing === void 0 ? current : {
|
|
1307
|
+
...current,
|
|
1308
|
+
[path]: { ...existing, saving: !1, error: reason instanceof Error ? reason.message : String(reason) }
|
|
1309
|
+
};
|
|
1310
|
+
});
|
|
1311
|
+
} finally {
|
|
1312
|
+
saveLocks.current.delete(path);
|
|
1313
|
+
}
|
|
1019
1314
|
}
|
|
1020
|
-
}, [
|
|
1315
|
+
}, [reload, sessionId]);
|
|
1316
|
+
(0, import_react.useEffect)(() => {
|
|
1317
|
+
let saveShortcut = (event) => {
|
|
1318
|
+
!(event.metaKey || event.ctrlKey) || event.key.toLocaleLowerCase() !== "s" || (event.preventDefault(), selected !== void 0 && savePath(selected));
|
|
1319
|
+
};
|
|
1320
|
+
return globalThis.addEventListener("keydown", saveShortcut), () => {
|
|
1321
|
+
globalThis.removeEventListener("keydown", saveShortcut);
|
|
1322
|
+
};
|
|
1323
|
+
}, [savePath, selected]);
|
|
1324
|
+
let groups = (0, import_react.useMemo)(() => {
|
|
1021
1325
|
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"));
|
|
1326
|
+
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
1327
|
for (let file of all) {
|
|
1024
1328
|
let directory2 = groupForPath(file.path), files = value.get(directory2) ?? [];
|
|
1025
1329
|
files.push(file), value.set(directory2, files);
|
|
@@ -1030,30 +1334,58 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1030
1334
|
return (leftIndex < 0 ? order.length : leftIndex) - (rightIndex < 0 ? order.length : rightIndex) || left.localeCompare(right, "zh-Hans-CN");
|
|
1031
1335
|
});
|
|
1032
1336
|
}, [activityPath, workbench, workspace]), selectWorkbench = (next) => {
|
|
1033
|
-
setWorkbench(next)
|
|
1337
|
+
setWorkbench(next);
|
|
1034
1338
|
let target = workspace === void 0 ? void 0 : preferredFile(workspace.files, next);
|
|
1035
|
-
setSelected(target);
|
|
1036
|
-
},
|
|
1339
|
+
target === void 0 ? setSelected(void 0) : revealPath(target);
|
|
1340
|
+
}, selectEditorMode = (next) => {
|
|
1341
|
+
next === "preview" && rememberEditorPosition(), setEditorMode(next);
|
|
1342
|
+
}, selectedLabel = selected ?? `\u5728\u5F53\u524D DSH workspace \u4E2D\u9009\u62E9${workbench === "story" ? "\u5C0F\u8BF4" : "\u77ED\u5267"}\u6587\u4EF6`, selectedBasename = selected?.split("/").at(-1) ?? selectedLabel, selectedGroup = selected === void 0 ? void 0 : groupForPath(selected), toggleGroup = (key, open) => {
|
|
1037
1343
|
setExpanded((current) => ({ ...current, [key]: open }));
|
|
1344
|
+
}, resolveConflict = (keepLocal) => {
|
|
1345
|
+
if (selected === void 0 || conflict?.theirs === void 0 || conflict.theirsVersion === void 0) return;
|
|
1346
|
+
let theirs = conflict.theirs, theirsVersion = conflict.theirsVersion;
|
|
1347
|
+
setBuffers((current) => {
|
|
1348
|
+
let existing = current[selected];
|
|
1349
|
+
return existing === void 0 ? current : {
|
|
1350
|
+
...current,
|
|
1351
|
+
[selected]: keepLocal ? { ...existing, saved: theirs, version: theirsVersion, source: "human", conflict: void 0 } : { content: theirs, saved: theirs, source: "disk", version: theirsVersion }
|
|
1352
|
+
};
|
|
1353
|
+
});
|
|
1038
1354
|
};
|
|
1039
1355
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: surfaceRef, className: "oh-story-split-surface", children: [
|
|
1040
1356
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: plugin_default }),
|
|
1041
1357
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("aside", { className: "oh-story-tree", children: [
|
|
1042
1358
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-brand", children: [
|
|
1043
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button",
|
|
1051
|
-
selectWorkbench("drama");
|
|
1052
|
-
}, children: "\u77ED\u5267" })
|
|
1359
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "oh-story-brand-cluster", children: [
|
|
1360
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("strong", { children: [
|
|
1361
|
+
"\u2726 ",
|
|
1362
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Oh Story" })
|
|
1363
|
+
] }),
|
|
1364
|
+
workspaceKind !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "oh-story-kind", children: workspaceKind === "story" ? "\u5C0F\u8BF4" : "\u77ED\u5267" })
|
|
1365
|
+
] }),
|
|
1366
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: reload, title: "\u5237\u65B0", "aria-label": "\u5237\u65B0\u9879\u76EE\u6587\u4EF6", children: "\u21BB" })
|
|
1053
1367
|
] }),
|
|
1368
|
+
showModeTabs && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-mode-tabs", role: "tablist", "aria-label": "\u521B\u4F5C\u5DE5\u4F5C\u53F0", children: WORKBENCH_MODES.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1369
|
+
"button",
|
|
1370
|
+
{
|
|
1371
|
+
type: "button",
|
|
1372
|
+
role: "tab",
|
|
1373
|
+
tabIndex: workbench === mode ? 0 : -1,
|
|
1374
|
+
"aria-selected": workbench === mode,
|
|
1375
|
+
onKeyDown: (event) => {
|
|
1376
|
+
handleTabKey(event, WORKBENCH_MODES, workbench, selectWorkbench);
|
|
1377
|
+
},
|
|
1378
|
+
onClick: () => {
|
|
1379
|
+
selectWorkbench(mode);
|
|
1380
|
+
},
|
|
1381
|
+
children: mode === "story" ? "\u5C0F\u8BF4" : "\u77ED\u5267"
|
|
1382
|
+
},
|
|
1383
|
+
mode
|
|
1384
|
+
)) }),
|
|
1054
1385
|
error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-error", children: error }),
|
|
1386
|
+
workspace?.metadataErrors.map((message) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-warning", children: message }, message)),
|
|
1055
1387
|
/* @__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]
|
|
1388
|
+
let groupOpen = selectedGroup === directory2 || expanded[directory2] === !0;
|
|
1057
1389
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "oh-story-file-group", open: groupOpen, onToggle: (event) => {
|
|
1058
1390
|
toggleGroup(directory2, event.currentTarget.open);
|
|
1059
1391
|
}, children: [
|
|
@@ -1070,7 +1402,7 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1070
1402
|
selected,
|
|
1071
1403
|
activityPath,
|
|
1072
1404
|
onToggle: toggleGroup,
|
|
1073
|
-
onSelect:
|
|
1405
|
+
onSelect: revealPath
|
|
1074
1406
|
}
|
|
1075
1407
|
)
|
|
1076
1408
|
] }, directory2);
|
|
@@ -1078,26 +1410,48 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1078
1410
|
] }),
|
|
1079
1411
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("main", { className: "oh-story-editor", children: [
|
|
1080
1412
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("header", { children: [
|
|
1081
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1413
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "oh-story-editor-path", title: selected, children: [
|
|
1414
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: selectedLabel }),
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: selectedBasename })
|
|
1416
|
+
] }),
|
|
1082
1417
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-editor-actions", children: [
|
|
1083
|
-
previewable && /* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1418
|
+
previewable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-editor-tabs", role: "tablist", "aria-label": markdown ? "Markdown \u67E5\u770B\u65B9\u5F0F" : "JSONL \u67E5\u770B\u65B9\u5F0F", children: EDITOR_MODES.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1419
|
+
"button",
|
|
1420
|
+
{
|
|
1421
|
+
type: "button",
|
|
1422
|
+
role: "tab",
|
|
1423
|
+
tabIndex: editorMode === mode ? 0 : -1,
|
|
1424
|
+
"aria-selected": editorMode === mode,
|
|
1425
|
+
onKeyDown: (event) => {
|
|
1426
|
+
handleTabKey(event, EDITOR_MODES, editorMode, selectEditorMode);
|
|
1427
|
+
},
|
|
1428
|
+
onClick: () => {
|
|
1429
|
+
selectEditorMode(mode);
|
|
1430
|
+
},
|
|
1431
|
+
children: mode === "preview" ? "\u9884\u89C8" : "\u6E90\u7801"
|
|
1432
|
+
},
|
|
1433
|
+
mode
|
|
1434
|
+
)) }),
|
|
1435
|
+
(dirty || saving) && selected !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "oh-story-save", type: "button", disabled: saving || buffer?.missing === !0, onClick: () => {
|
|
1436
|
+
savePath(selected);
|
|
1093
1437
|
}, children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
|
|
1094
1438
|
] })
|
|
1095
1439
|
] }),
|
|
1096
|
-
activityPath === selected && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-stream", "data-stage": activity
|
|
1440
|
+
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
1441
|
"\u25CF ",
|
|
1098
|
-
activity
|
|
1442
|
+
activity.stage === "running" ? "Agent \u6B63\u5728\u5E94\u7528\u4FEE\u6539" : "Agent \u6B63\u5728\u751F\u6210\u6587\u4EF6\u5185\u5BB9"
|
|
1443
|
+
] }),
|
|
1444
|
+
conflict !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-conflict", role: "alert", children: [
|
|
1445
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: conflict.message }),
|
|
1446
|
+
conflict.theirs !== void 0 && conflict.theirsVersion !== void 0 && selected !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1447
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: () => {
|
|
1448
|
+
resolveConflict(!1);
|
|
1449
|
+
}, children: "\u8F7D\u5165\u78C1\u76D8\u7248\u672C" }),
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: () => {
|
|
1451
|
+
resolveConflict(!0);
|
|
1452
|
+
}, children: "\u4FDD\u7559\u672C\u5730\u8349\u7A3F" })
|
|
1453
|
+
] })
|
|
1099
1454
|
] }),
|
|
1100
|
-
conflict !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-conflict", children: conflict }),
|
|
1101
1455
|
fileError !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "oh-story-error", children: fileError }),
|
|
1102
1456
|
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
1457
|
"\u5F53\u524D workspace \u8FD8\u6CA1\u6709\u5C0F\u8BF4\u6587\u4EF6\u3002\u53EF\u5728\u53F3\u4FA7 Chat \u4E2D\u8FD0\u884C ",
|
|
@@ -1111,11 +1465,23 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1111
1465
|
"\u6B63\u5728\u52A0\u8F7D ",
|
|
1112
1466
|
selected,
|
|
1113
1467
|
"\u2026"
|
|
1468
|
+
] }) : buffer.missing === !0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-empty", children: [
|
|
1469
|
+
"\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",
|
|
1470
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: () => {
|
|
1471
|
+
setBuffers((current) => {
|
|
1472
|
+
let next = { ...current };
|
|
1473
|
+
return delete next[selected], next;
|
|
1474
|
+
}), setSelected(workspace === void 0 ? void 0 : preferredFile(workspace.files, workbench));
|
|
1475
|
+
}, children: "\u653E\u5F03\u672C\u5730\u8349\u7A3F" })
|
|
1114
1476
|
] }) : 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
1477
|
"textarea",
|
|
1116
1478
|
{
|
|
1479
|
+
ref: textareaRef,
|
|
1117
1480
|
value: buffer.content,
|
|
1118
1481
|
"data-format": structured ? "structured" : "prose",
|
|
1482
|
+
onBlur: rememberEditorPosition,
|
|
1483
|
+
onScroll: rememberEditorPosition,
|
|
1484
|
+
onSelect: rememberEditorPosition,
|
|
1119
1485
|
onChange: (event) => {
|
|
1120
1486
|
let content = event.target.value;
|
|
1121
1487
|
setBuffers((current) => ({
|
|
@@ -1124,13 +1490,12 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1124
1490
|
content,
|
|
1125
1491
|
saved: current[selected]?.saved ?? "",
|
|
1126
1492
|
source: "human",
|
|
1127
|
-
version: current[selected]?.version ?? ""
|
|
1493
|
+
version: current[selected]?.version ?? "",
|
|
1494
|
+
conflict: current[selected]?.conflict,
|
|
1495
|
+
saving: current[selected]?.saving
|
|
1128
1496
|
}
|
|
1129
1497
|
}));
|
|
1130
1498
|
},
|
|
1131
|
-
onKeyDown: (event) => {
|
|
1132
|
-
(event.metaKey || event.ctrlKey) && event.key.toLocaleLowerCase() === "s" && (event.preventDefault(), save());
|
|
1133
|
-
},
|
|
1134
1499
|
spellCheck: !structured,
|
|
1135
1500
|
"aria-label": selected
|
|
1136
1501
|
}
|
|
@@ -1138,27 +1503,51 @@ function CreativeWorkbench({ sessionId, useSession }) {
|
|
|
1138
1503
|
] })
|
|
1139
1504
|
] });
|
|
1140
1505
|
}
|
|
1141
|
-
function CreativeSplitBridge(
|
|
1142
|
-
let marker = (0, import_react.useRef)(null), [target, setTarget] = (0, import_react.useState)();
|
|
1506
|
+
function CreativeSplitBridge({ sessionId, useSession, useStore, actions }) {
|
|
1507
|
+
let marker = (0, import_react.useRef)(null), [target, setTarget] = (0, import_react.useState)(), runningCalls = useSession((snapshot) => snapshot.runningCalls), partial = useSession((snapshot) => streamingAssistant(snapshot.chat.timeline)), settledMutation = useSession((snapshot) => latestSettledMutation(snapshot.chat));
|
|
1143
1508
|
return (0, import_react.useLayoutEffect)(() => {
|
|
1144
|
-
let
|
|
1145
|
-
|
|
1146
|
-
|
|
1509
|
+
let document = marker.current?.ownerDocument;
|
|
1510
|
+
if (document === void 0) return;
|
|
1511
|
+
let locate = () => {
|
|
1512
|
+
let anchor = document.querySelector("[data-conversation-scroll] > [data-slot='conversation.session']");
|
|
1513
|
+
setTarget((current) => current === anchor ? current : anchor ?? void 0);
|
|
1514
|
+
};
|
|
1515
|
+
locate();
|
|
1516
|
+
let observer = new MutationObserver(locate);
|
|
1517
|
+
return observer.observe(document.body, { childList: !0, subtree: !0 }), () => {
|
|
1518
|
+
observer.disconnect();
|
|
1519
|
+
};
|
|
1520
|
+
}, [sessionId]), (0, import_react.useLayoutEffect)(() => {
|
|
1147
1521
|
let scroller = target?.parentElement;
|
|
1148
1522
|
if (scroller == null) return;
|
|
1149
|
-
let
|
|
1523
|
+
let publishLayout = () => {
|
|
1150
1524
|
scroller.style.setProperty("--oh-story-scroll-height", `${String(scroller.clientHeight)}px`);
|
|
1525
|
+
let layout = scroller.clientWidth < 620 ? "compact" : scroller.clientWidth < 900 ? "medium" : "wide";
|
|
1526
|
+
scroller.dataset.ohStoryLayout !== layout && (scroller.dataset.ohStoryLayout = layout);
|
|
1151
1527
|
};
|
|
1152
|
-
|
|
1153
|
-
let observer = new ResizeObserver(
|
|
1528
|
+
publishLayout();
|
|
1529
|
+
let observer = new ResizeObserver(publishLayout);
|
|
1154
1530
|
return observer.observe(scroller), () => {
|
|
1155
|
-
observer.disconnect(), scroller.style.removeProperty("--oh-story-scroll-height");
|
|
1531
|
+
observer.disconnect(), scroller.style.removeProperty("--oh-story-scroll-height"), delete scroller.dataset.ohStoryLayout;
|
|
1156
1532
|
};
|
|
1157
1533
|
}, [target]), /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1158
1534
|
/* @__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)(
|
|
1535
|
+
target === void 0 ? null : (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1536
|
+
CreativeWorkbench,
|
|
1537
|
+
{
|
|
1538
|
+
sessionId,
|
|
1539
|
+
runningCalls,
|
|
1540
|
+
partial,
|
|
1541
|
+
settledMutation,
|
|
1542
|
+
useStore,
|
|
1543
|
+
actions
|
|
1544
|
+
}
|
|
1545
|
+
), target)
|
|
1160
1546
|
] });
|
|
1161
1547
|
}
|
|
1548
|
+
function WorkbenchSeat({ SessionProvider, renderSlot }) {
|
|
1549
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SessionProvider, { children: () => renderSlot("oh-story.workspace", {}) });
|
|
1550
|
+
}
|
|
1162
1551
|
function argsOf(block) {
|
|
1163
1552
|
let raw = ("kind" in block ? block.call?.argsRaw : block.argsRaw) ?? "{}";
|
|
1164
1553
|
try {
|
|
@@ -1187,11 +1576,18 @@ function RoleToolView({ block, inspect }) {
|
|
|
1187
1576
|
] });
|
|
1188
1577
|
}
|
|
1189
1578
|
function apply(context) {
|
|
1190
|
-
context.slots.inject("
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1579
|
+
context.slots.inject("shell.overlay", () => {
|
|
1580
|
+
let disposeSeat = context.slots.register({
|
|
1581
|
+
name: "shell.overlay",
|
|
1582
|
+
id: "oh-story-workspace",
|
|
1583
|
+
order: -100,
|
|
1584
|
+
children: { "oh-story.workspace": { kind: "single", scope: "session" } }
|
|
1585
|
+
}, WorkbenchSeat), disposeWorkbench = context.slots.register({
|
|
1586
|
+
name: "oh-story.workspace",
|
|
1587
|
+
store: createWorkbenchStore
|
|
1588
|
+
}, CreativeSplitBridge);
|
|
1589
|
+
return [disposeSeat, disposeWorkbench];
|
|
1590
|
+
}), context.slots.inject("tool.call.toolview", () => context.slots.register({
|
|
1195
1591
|
name: "tool.call.toolview",
|
|
1196
1592
|
key: "oh_story_role"
|
|
1197
1593
|
}, RoleToolView));
|