@syncended/dsh-automations 0.2.2 → 0.3.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 +2 -2
- package/docs/architecture.md +2 -2
- package/lib/client.js +168 -158
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A DeepSeek Harness plugin for durable, configurable cron jobs. Each occurrence s
|
|
|
8
8
|
|
|
9
9
|
- Standard five-field cron expressions with `UTC` or IANA timezones.
|
|
10
10
|
- Per-job project directory, provider/model, reasoning effort, agent preset, permission preset, and timeout.
|
|
11
|
-
- Enable/disable, Run now, edit, delete, cancel, and recent run history from the main **Automations** sidebar action or **Settings → Automations**.
|
|
11
|
+
- Enable/disable, Run now, edit, delete, cancel, and recent run history from a full center workspace opened by the main **Automations** sidebar action, or from **Settings → Automations**.
|
|
12
12
|
- Overlap policies:
|
|
13
13
|
- `skip` — record and skip an occurrence while the job has queued/running work.
|
|
14
14
|
- `queue` — serialize occurrences for the same job.
|
|
@@ -42,7 +42,7 @@ pnpm build
|
|
|
42
42
|
dsh plugin --profile web add .
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
The package declares a DSH bundle, so `dsh plugin` appends it to the Web profile automatically. Restart the running Web Harness after the initial install, then refresh the page. Open **Automations** from the main sidebar, or use **Settings → Automations**.
|
|
45
|
+
The package declares a DSH bundle, so `dsh plugin` appends it to the Web profile automatically. Restart the running Web Harness after the initial install, then refresh the page. Open the full **Automations** workspace from the main sidebar, or use **Settings → Automations**.
|
|
46
46
|
|
|
47
47
|
To remove it:
|
|
48
48
|
|
package/docs/architecture.md
CHANGED
|
@@ -15,7 +15,7 @@ Non-goals for the first release:
|
|
|
15
15
|
## Components
|
|
16
16
|
|
|
17
17
|
```text
|
|
18
|
-
Sidebar / Settings UI / HTTP API
|
|
18
|
+
Sidebar / Center workspace / Settings UI / HTTP API
|
|
19
19
|
│
|
|
20
20
|
▼
|
|
21
21
|
AutomationService ─── ProjectPolicy
|
|
@@ -30,7 +30,7 @@ Sidebar / Settings UI / HTTP API
|
|
|
30
30
|
|
|
31
31
|
### Browser surfaces
|
|
32
32
|
|
|
33
|
-
The same automation page is available through
|
|
33
|
+
The same automation page is available through Settings and a dedicated center workspace. `settings.section` keeps configuration available inside Settings; `sidebar.footer.action` activates a temporary, higher-priority `conversation` entry that replaces the current center occupant. This provides a split-screen-like full-center experience while using the single-slot election directly rather than Split Screen's internal view contributions. Closing Automations disposes its entry immediately, revealing whichever center surface was previously active. A small client-only disclosure store coordinates the sidebar trigger and dynamic registration; neither surface owns scheduler state, and both read the same package HTTP API.
|
|
34
34
|
|
|
35
35
|
Interactive chrome uses the ambient `@deepseek-ai/dsh-client-ui-primitives` `Button`, `Menu`, and icon components. Package CSS is limited to the automation-specific layout and composes only public DSH semantic tokens, so theme, menu, focus, and button behavior stay aligned with the host UI.
|
|
36
36
|
|
package/lib/client.js
CHANGED
|
@@ -21,7 +21,7 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
IconBrowseOutline16,
|
|
22
22
|
IconCheckOutline16,
|
|
23
23
|
IconChevronDownOutline14,
|
|
24
|
-
|
|
24
|
+
IconChevronLeftOutline14,
|
|
25
25
|
IconEditOutline16,
|
|
26
26
|
IconPlayOutline16,
|
|
27
27
|
IconPlusOutline16,
|
|
@@ -40,6 +40,7 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
const MIN_TIMEOUT_MS = 1000;
|
|
41
41
|
const MAX_TIMEOUT_MS = 86400000;
|
|
42
42
|
const JOB_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
43
|
+
let formInstanceSerial = 0;
|
|
43
44
|
|
|
44
45
|
const BROWSER_TIMEZONE = (() => {
|
|
45
46
|
try {
|
|
@@ -327,12 +328,12 @@ window.__ModuleLoader__.load({
|
|
|
327
328
|
|
|
328
329
|
function focusAfterPickerTab(trigger, backwards) {
|
|
329
330
|
requestAnimationFrame(() => {
|
|
330
|
-
const
|
|
331
|
-
if (!
|
|
331
|
+
const focusBoundary = trigger?.closest(".dsh-auto-form") || trigger?.closest('[role="dialog"]');
|
|
332
|
+
if (!focusBoundary) {
|
|
332
333
|
trigger?.focus();
|
|
333
334
|
return;
|
|
334
335
|
}
|
|
335
|
-
const focusables =
|
|
336
|
+
const focusables = visibleFocusables(focusBoundary);
|
|
336
337
|
const index = focusables.indexOf(trigger);
|
|
337
338
|
const target = index < 0 ? trigger : focusables[index + (backwards ? -1 : 1)];
|
|
338
339
|
(target || trigger)?.focus();
|
|
@@ -406,10 +407,14 @@ window.__ModuleLoader__.load({
|
|
|
406
407
|
});
|
|
407
408
|
});
|
|
408
409
|
const onKeyDown = (event) => {
|
|
409
|
-
if (event.key !== "Tab") return;
|
|
410
410
|
const dialog = riskDialog();
|
|
411
411
|
if (!dialog) return;
|
|
412
|
-
|
|
412
|
+
if (event.key === "Escape" && dialog.contains(event.target)) {
|
|
413
|
+
event.__dshAutomationsNested = true;
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (event.key !== "Tab") return;
|
|
417
|
+
const focusables = visibleFocusables(dialog);
|
|
413
418
|
if (focusables.length === 0) return;
|
|
414
419
|
const index = focusables.indexOf(event.target);
|
|
415
420
|
const next = event.shiftKey
|
|
@@ -596,6 +601,11 @@ window.__ModuleLoader__.load({
|
|
|
596
601
|
return h("span", { className: "dsh-auto-status dsh-auto-status-" + props.status }, props.status);
|
|
597
602
|
}
|
|
598
603
|
|
|
604
|
+
function nextFormInstancePrefix(reactFormId) {
|
|
605
|
+
formInstanceSerial += 1;
|
|
606
|
+
return "dsh-auto-form-" + formInstanceSerial + "-" + reactFormId;
|
|
607
|
+
}
|
|
608
|
+
|
|
599
609
|
function JobForm(props) {
|
|
600
610
|
const { meta, draft, editing, saving, error, onChange, onIdTouched, onSubmit, onCancel } = props;
|
|
601
611
|
const providers = meta && Array.isArray(meta.providers) ? meta.providers : [];
|
|
@@ -607,6 +617,12 @@ window.__ModuleLoader__.load({
|
|
|
607
617
|
: ["workspace-write"];
|
|
608
618
|
const agentPresets = meta && Array.isArray(meta.agentPresets) ? meta.agentPresets : [];
|
|
609
619
|
const creating = editing === null;
|
|
620
|
+
const reactFormId = String(useId()).replace(/[^A-Za-z0-9_-]/g, "");
|
|
621
|
+
const formPrefixRef = useRef(null);
|
|
622
|
+
if (formPrefixRef.current === null) {
|
|
623
|
+
formPrefixRef.current = nextFormInstancePrefix(reactFormId);
|
|
624
|
+
}
|
|
625
|
+
const fieldId = (name) => formPrefixRef.current + "-" + name;
|
|
610
626
|
|
|
611
627
|
return h(
|
|
612
628
|
"form",
|
|
@@ -622,9 +638,9 @@ window.__ModuleLoader__.load({
|
|
|
622
638
|
{ className: "dsh-auto-formgrid" },
|
|
623
639
|
h(
|
|
624
640
|
Field,
|
|
625
|
-
{ label: "Name", htmlFor: "
|
|
641
|
+
{ label: "Name", htmlFor: fieldId("name"), required: true },
|
|
626
642
|
h("input", {
|
|
627
|
-
id: "
|
|
643
|
+
id: fieldId("name"),
|
|
628
644
|
className: "dsh-auto-input",
|
|
629
645
|
type: "text",
|
|
630
646
|
value: draft.name,
|
|
@@ -636,9 +652,9 @@ window.__ModuleLoader__.load({
|
|
|
636
652
|
creating
|
|
637
653
|
? h(
|
|
638
654
|
Field,
|
|
639
|
-
{ label: "Job id", htmlFor: "
|
|
655
|
+
{ label: "Job id", htmlFor: fieldId("id"), hint: "Lowercase letters, digits and hyphens; auto-derived from the name. Leave blank to let the server generate one." },
|
|
640
656
|
h("input", {
|
|
641
|
-
id: "
|
|
657
|
+
id: fieldId("id"),
|
|
642
658
|
className: "dsh-auto-input",
|
|
643
659
|
type: "text",
|
|
644
660
|
value: draft.id,
|
|
@@ -652,9 +668,9 @@ window.__ModuleLoader__.load({
|
|
|
652
668
|
)
|
|
653
669
|
: h(
|
|
654
670
|
Field,
|
|
655
|
-
{ label: "Job id", htmlFor: "
|
|
671
|
+
{ label: "Job id", htmlFor: fieldId("id"), hint: "Fixed after creation." },
|
|
656
672
|
h("input", {
|
|
657
|
-
id: "
|
|
673
|
+
id: fieldId("id"),
|
|
658
674
|
className: "dsh-auto-input",
|
|
659
675
|
type: "text",
|
|
660
676
|
value: draft.id,
|
|
@@ -664,9 +680,9 @@ window.__ModuleLoader__.load({
|
|
|
664
680
|
),
|
|
665
681
|
h(
|
|
666
682
|
Field,
|
|
667
|
-
{ label: "Cron", htmlFor: "
|
|
683
|
+
{ label: "Cron", htmlFor: fieldId("cron"), required: true, hint: "Five-field cron (minute hour day-of-month month day-of-week)." },
|
|
668
684
|
h("input", {
|
|
669
|
-
id: "
|
|
685
|
+
id: fieldId("cron"),
|
|
670
686
|
className: "dsh-auto-input",
|
|
671
687
|
type: "text",
|
|
672
688
|
value: draft.cron,
|
|
@@ -676,30 +692,30 @@ window.__ModuleLoader__.load({
|
|
|
676
692
|
),
|
|
677
693
|
h(
|
|
678
694
|
Field,
|
|
679
|
-
{ label: "Timezone", htmlFor: "
|
|
695
|
+
{ label: "Timezone", htmlFor: fieldId("timezone"), required: true },
|
|
680
696
|
h("input", {
|
|
681
|
-
id: "
|
|
697
|
+
id: fieldId("timezone"),
|
|
682
698
|
className: "dsh-auto-input",
|
|
683
699
|
type: "text",
|
|
684
|
-
list: "
|
|
700
|
+
list: fieldId("timezone-list"),
|
|
685
701
|
value: draft.timezone,
|
|
686
702
|
spellCheck: false,
|
|
687
703
|
onChange: (event) => onChange("timezone", event.target.value),
|
|
688
704
|
}),
|
|
689
705
|
h(
|
|
690
706
|
"datalist",
|
|
691
|
-
{ id: "
|
|
707
|
+
{ id: fieldId("timezone-list") },
|
|
692
708
|
TIMEZONES.map((zone) => h("option", { key: zone, value: zone })),
|
|
693
709
|
),
|
|
694
710
|
),
|
|
695
711
|
h(
|
|
696
712
|
Field,
|
|
697
|
-
{ label: "Enabled", htmlFor: "
|
|
713
|
+
{ label: "Enabled", htmlFor: fieldId("enabled") },
|
|
698
714
|
h(
|
|
699
715
|
"label",
|
|
700
716
|
{ className: "dsh-auto-check" },
|
|
701
717
|
h("input", {
|
|
702
|
-
id: "
|
|
718
|
+
id: fieldId("enabled"),
|
|
703
719
|
type: "checkbox",
|
|
704
720
|
checked: draft.enabled,
|
|
705
721
|
onChange: (event) => onChange("enabled", event.target.checked),
|
|
@@ -709,9 +725,9 @@ window.__ModuleLoader__.load({
|
|
|
709
725
|
),
|
|
710
726
|
h(
|
|
711
727
|
Field,
|
|
712
|
-
{ label: "Timeout (ms)", htmlFor: "
|
|
728
|
+
{ label: "Timeout (ms)", htmlFor: fieldId("timeout"), required: true, hint: "Wall-clock limit for each run (1s to 24h)." },
|
|
713
729
|
h("input", {
|
|
714
|
-
id: "
|
|
730
|
+
id: fieldId("timeout"),
|
|
715
731
|
className: "dsh-auto-input",
|
|
716
732
|
type: "number",
|
|
717
733
|
min: MIN_TIMEOUT_MS,
|
|
@@ -723,12 +739,12 @@ window.__ModuleLoader__.load({
|
|
|
723
739
|
),
|
|
724
740
|
h(
|
|
725
741
|
Field,
|
|
726
|
-
{ label: "Provider", htmlFor: "
|
|
742
|
+
{ label: "Provider", htmlFor: fieldId("provider"), hint: "Blank uses the current Harness default. You may type an unlisted provider route." },
|
|
727
743
|
h("input", {
|
|
728
|
-
id: "
|
|
744
|
+
id: fieldId("provider"),
|
|
729
745
|
className: "dsh-auto-input",
|
|
730
746
|
type: "text",
|
|
731
|
-
list: "
|
|
747
|
+
list: fieldId("provider-list"),
|
|
732
748
|
value: draft.provider,
|
|
733
749
|
spellCheck: false,
|
|
734
750
|
placeholder: "Harness default",
|
|
@@ -736,7 +752,7 @@ window.__ModuleLoader__.load({
|
|
|
736
752
|
}),
|
|
737
753
|
h(
|
|
738
754
|
"datalist",
|
|
739
|
-
{ id: "
|
|
755
|
+
{ id: fieldId("provider-list") },
|
|
740
756
|
providers.map((provider) => h("option", { key: provider.id, value: provider.id })),
|
|
741
757
|
),
|
|
742
758
|
),
|
|
@@ -744,17 +760,17 @@ window.__ModuleLoader__.load({
|
|
|
744
760
|
Field,
|
|
745
761
|
{
|
|
746
762
|
label: "Model",
|
|
747
|
-
htmlFor: "
|
|
763
|
+
htmlFor: fieldId("model"),
|
|
748
764
|
required: draft.provider !== "",
|
|
749
765
|
hint: draft.provider === ""
|
|
750
766
|
? "Set a provider first, or leave both blank for the Harness default."
|
|
751
767
|
: "Choose a discovered model or type an adapter-supported model id.",
|
|
752
768
|
},
|
|
753
769
|
h("input", {
|
|
754
|
-
id: "
|
|
770
|
+
id: fieldId("model"),
|
|
755
771
|
className: "dsh-auto-input",
|
|
756
772
|
type: "text",
|
|
757
|
-
list: "
|
|
773
|
+
list: fieldId("model-list"),
|
|
758
774
|
value: draft.model,
|
|
759
775
|
spellCheck: false,
|
|
760
776
|
placeholder: draft.provider === "" ? "Harness default" : "Model id",
|
|
@@ -763,18 +779,18 @@ window.__ModuleLoader__.load({
|
|
|
763
779
|
}),
|
|
764
780
|
h(
|
|
765
781
|
"datalist",
|
|
766
|
-
{ id: "
|
|
782
|
+
{ id: fieldId("model-list") },
|
|
767
783
|
models.map((model) => h("option", { key: model, value: model })),
|
|
768
784
|
),
|
|
769
785
|
),
|
|
770
786
|
h(
|
|
771
787
|
Field,
|
|
772
|
-
{ label: "Reasoning effort", htmlFor: "
|
|
788
|
+
{ label: "Reasoning effort", htmlFor: fieldId("effort"), hint: "Blank uses the provider default." },
|
|
773
789
|
h("input", {
|
|
774
|
-
id: "
|
|
790
|
+
id: fieldId("effort"),
|
|
775
791
|
className: "dsh-auto-input",
|
|
776
792
|
type: "text",
|
|
777
|
-
list: "
|
|
793
|
+
list: fieldId("effort-list"),
|
|
778
794
|
value: draft.reasoningEffort,
|
|
779
795
|
spellCheck: false,
|
|
780
796
|
placeholder: "e.g. medium",
|
|
@@ -782,15 +798,15 @@ window.__ModuleLoader__.load({
|
|
|
782
798
|
}),
|
|
783
799
|
h(
|
|
784
800
|
"datalist",
|
|
785
|
-
{ id: "
|
|
801
|
+
{ id: fieldId("effort-list") },
|
|
786
802
|
REASONING_EFFORTS.map((effort) => h("option", { key: effort, value: effort })),
|
|
787
803
|
),
|
|
788
804
|
),
|
|
789
805
|
h(
|
|
790
806
|
Field,
|
|
791
|
-
{ label: "Agent preset", htmlFor: "
|
|
807
|
+
{ label: "Agent preset", htmlFor: fieldId("preset"), hint: "Uses the current Harness default when not explicitly selected." },
|
|
792
808
|
h(AgentPresetPicker, {
|
|
793
|
-
id: "
|
|
809
|
+
id: fieldId("preset"),
|
|
794
810
|
value: draft.agentPreset,
|
|
795
811
|
presets: agentPresets,
|
|
796
812
|
onChange: (value) => onChange("agentPreset", value),
|
|
@@ -800,12 +816,12 @@ window.__ModuleLoader__.load({
|
|
|
800
816
|
Field,
|
|
801
817
|
{
|
|
802
818
|
label: "Permission preset",
|
|
803
|
-
htmlFor: "
|
|
819
|
+
htmlFor: fieldId("permission"),
|
|
804
820
|
required: true,
|
|
805
821
|
hint: permissionPresetPresentation(draft.permissionPreset).detail,
|
|
806
822
|
},
|
|
807
823
|
h(PermissionPresetPicker, {
|
|
808
|
-
id: "
|
|
824
|
+
id: fieldId("permission"),
|
|
809
825
|
value: draft.permissionPreset,
|
|
810
826
|
presets: permissionPresets,
|
|
811
827
|
onChange: (value) => onChange("permissionPreset", value),
|
|
@@ -813,11 +829,11 @@ window.__ModuleLoader__.load({
|
|
|
813
829
|
),
|
|
814
830
|
h(
|
|
815
831
|
Field,
|
|
816
|
-
{ label: "Overlap policy", htmlFor: "
|
|
832
|
+
{ label: "Overlap policy", htmlFor: fieldId("overlap"), full: true, hint: "What happens when a scheduled run fires while another run for the same job is still active." },
|
|
817
833
|
h(
|
|
818
834
|
"select",
|
|
819
835
|
{
|
|
820
|
-
id: "
|
|
836
|
+
id: fieldId("overlap"),
|
|
821
837
|
className: "dsh-auto-select",
|
|
822
838
|
value: draft.overlap,
|
|
823
839
|
onChange: (event) => onChange("overlap", event.target.value),
|
|
@@ -827,11 +843,11 @@ window.__ModuleLoader__.load({
|
|
|
827
843
|
),
|
|
828
844
|
h(
|
|
829
845
|
Field,
|
|
830
|
-
{ label: "Misfire policy", htmlFor: "
|
|
846
|
+
{ label: "Misfire policy", htmlFor: fieldId("misfire"), hint: "How a missed occurrence is handled after the scheduler is back." },
|
|
831
847
|
h(
|
|
832
848
|
"select",
|
|
833
849
|
{
|
|
834
|
-
id: "
|
|
850
|
+
id: fieldId("misfire"),
|
|
835
851
|
className: "dsh-auto-select",
|
|
836
852
|
value: draft.misfire,
|
|
837
853
|
onChange: (event) => onChange("misfire", event.target.value),
|
|
@@ -841,9 +857,9 @@ window.__ModuleLoader__.load({
|
|
|
841
857
|
),
|
|
842
858
|
h(
|
|
843
859
|
Field,
|
|
844
|
-
{ label: "Working directory", htmlFor: "
|
|
860
|
+
{ label: "Working directory", htmlFor: fieldId("cwd"), required: true, full: true, hint: "Absolute project directory the agent runs in." },
|
|
845
861
|
h("input", {
|
|
846
|
-
id: "
|
|
862
|
+
id: fieldId("cwd"),
|
|
847
863
|
className: "dsh-auto-input",
|
|
848
864
|
type: "text",
|
|
849
865
|
value: draft.cwd,
|
|
@@ -854,9 +870,9 @@ window.__ModuleLoader__.load({
|
|
|
854
870
|
),
|
|
855
871
|
h(
|
|
856
872
|
Field,
|
|
857
|
-
{ label: "Prompt", htmlFor: "
|
|
873
|
+
{ label: "Prompt", htmlFor: fieldId("prompt"), required: true, full: true, hint: "Instructions for the agent run. Prompts are never shown in run history." },
|
|
858
874
|
h("textarea", {
|
|
859
|
-
id: "
|
|
875
|
+
id: fieldId("prompt"),
|
|
860
876
|
className: "dsh-auto-textarea",
|
|
861
877
|
value: draft.prompt,
|
|
862
878
|
placeholder: "Summarize yesterday's progress and list today's priorities\u2026",
|
|
@@ -1141,7 +1157,7 @@ window.__ModuleLoader__.load({
|
|
|
1141
1157
|
);
|
|
1142
1158
|
}
|
|
1143
1159
|
|
|
1144
|
-
function AutomationsSection() {
|
|
1160
|
+
function AutomationsSection({ centerMode = false } = {}) {
|
|
1145
1161
|
const [meta, setMeta] = useState(null);
|
|
1146
1162
|
const [snapshot, setSnapshot] = useState(null);
|
|
1147
1163
|
const [loading, setLoading] = useState(true);
|
|
@@ -1418,14 +1434,17 @@ window.__ModuleLoader__.load({
|
|
|
1418
1434
|
|
|
1419
1435
|
return h(
|
|
1420
1436
|
"section",
|
|
1421
|
-
{
|
|
1437
|
+
{
|
|
1438
|
+
className: "dsh-auto-root" + (centerMode ? " dsh-auto-root-workspace" : ""),
|
|
1439
|
+
"aria-busy": loading ? "true" : null,
|
|
1440
|
+
},
|
|
1422
1441
|
h(
|
|
1423
1442
|
"div",
|
|
1424
1443
|
{ className: "dsh-auto-head" },
|
|
1425
1444
|
h(
|
|
1426
1445
|
"div",
|
|
1427
1446
|
null,
|
|
1428
|
-
h("h2",
|
|
1447
|
+
h("h2", { className: centerMode ? "dsh-auto-sr-only" : undefined }, "Automations"),
|
|
1429
1448
|
h(
|
|
1430
1449
|
"p",
|
|
1431
1450
|
{ className: "dsh-auto-sub" },
|
|
@@ -1547,7 +1566,7 @@ window.__ModuleLoader__.load({
|
|
|
1547
1566
|
};
|
|
1548
1567
|
}
|
|
1549
1568
|
|
|
1550
|
-
const
|
|
1569
|
+
const FOCUSABLE_SELECTOR = [
|
|
1551
1570
|
"a[href]",
|
|
1552
1571
|
"button:not([disabled])",
|
|
1553
1572
|
"input:not([disabled])",
|
|
@@ -1557,45 +1576,15 @@ window.__ModuleLoader__.load({
|
|
|
1557
1576
|
"[tabindex]:not([tabindex=\"-1\"])",
|
|
1558
1577
|
].join(",");
|
|
1559
1578
|
|
|
1560
|
-
function
|
|
1579
|
+
function visibleFocusables(panel) {
|
|
1561
1580
|
if (!panel) return [];
|
|
1562
|
-
return Array.from(panel.querySelectorAll(
|
|
1581
|
+
return Array.from(panel.querySelectorAll(FOCUSABLE_SELECTOR)).filter((element) =>
|
|
1563
1582
|
!element.hasAttribute("hidden") &&
|
|
1564
1583
|
element.getAttribute("aria-hidden") !== "true" &&
|
|
1565
1584
|
element.getClientRects().length > 0,
|
|
1566
1585
|
);
|
|
1567
1586
|
}
|
|
1568
1587
|
|
|
1569
|
-
function trapModalTab(event, panel) {
|
|
1570
|
-
if (
|
|
1571
|
-
event.key !== "Tab" ||
|
|
1572
|
-
event.defaultPrevented ||
|
|
1573
|
-
event.altKey ||
|
|
1574
|
-
event.ctrlKey ||
|
|
1575
|
-
event.metaKey
|
|
1576
|
-
) return;
|
|
1577
|
-
const focusables = modalFocusables(panel);
|
|
1578
|
-
if (focusables.length === 0) {
|
|
1579
|
-
event.preventDefault();
|
|
1580
|
-
panel?.focus();
|
|
1581
|
-
return;
|
|
1582
|
-
}
|
|
1583
|
-
const first = focusables[0];
|
|
1584
|
-
const last = focusables[focusables.length - 1];
|
|
1585
|
-
const active = panel.ownerDocument.activeElement;
|
|
1586
|
-
if (event.shiftKey) {
|
|
1587
|
-
if (active === first || !panel.contains(active)) {
|
|
1588
|
-
event.preventDefault();
|
|
1589
|
-
last.focus();
|
|
1590
|
-
}
|
|
1591
|
-
return;
|
|
1592
|
-
}
|
|
1593
|
-
if (active === last || !panel.contains(active)) {
|
|
1594
|
-
event.preventDefault();
|
|
1595
|
-
first.focus();
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
1588
|
function AutomationGlyph({ size = 18 }) {
|
|
1600
1589
|
return h(
|
|
1601
1590
|
"svg",
|
|
@@ -1644,10 +1633,9 @@ window.__ModuleLoader__.load({
|
|
|
1644
1633
|
ref: triggerRef,
|
|
1645
1634
|
type: "button",
|
|
1646
1635
|
className: "dsh-auto-sidebar-trigger",
|
|
1647
|
-
title: wide ? undefined : "Automations",
|
|
1648
|
-
"aria-label": "Automations",
|
|
1649
|
-
"aria-
|
|
1650
|
-
"aria-expanded": open,
|
|
1636
|
+
title: wide ? undefined : open ? "Exit Automations" : "Automations",
|
|
1637
|
+
"aria-label": open ? "Exit Automations" : "Open Automations",
|
|
1638
|
+
"aria-pressed": open,
|
|
1651
1639
|
"data-active": open ? "true" : undefined,
|
|
1652
1640
|
"data-dsh-automations-trigger": "true",
|
|
1653
1641
|
onClick: disclosure.toggle,
|
|
@@ -1658,67 +1646,55 @@ window.__ModuleLoader__.load({
|
|
|
1658
1646
|
);
|
|
1659
1647
|
}
|
|
1660
1648
|
|
|
1661
|
-
function
|
|
1662
|
-
const
|
|
1663
|
-
disclosure.subscribe,
|
|
1664
|
-
disclosure.getSnapshot,
|
|
1665
|
-
disclosure.getSnapshot,
|
|
1666
|
-
);
|
|
1667
|
-
const closeRef = useRef(null);
|
|
1668
|
-
const panelRef = useRef(null);
|
|
1649
|
+
function AutomationsWorkspace({ disclosure }) {
|
|
1650
|
+
const workspaceRef = useRef(null);
|
|
1669
1651
|
const titleId = useId();
|
|
1670
1652
|
|
|
1671
1653
|
useEffect(() => {
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1654
|
+
const frame = window.requestAnimationFrame(() =>
|
|
1655
|
+
workspaceRef.current?.querySelector('[data-dsh-automations-exit="true"]')?.focus(),
|
|
1656
|
+
);
|
|
1657
|
+
const onKeyDown = (event) => {
|
|
1658
|
+
if (event.key !== "Escape" || event.defaultPrevented || event.__dshAutomationsNested) return;
|
|
1659
|
+
if (event.target?.closest?.('[role="dialog"],[role="menu"]')) return;
|
|
1660
|
+
if (document.querySelector('.dsh-auto-picker-trigger[aria-expanded="true"]')) return;
|
|
1661
|
+
event.preventDefault();
|
|
1662
|
+
disclosure.close();
|
|
1663
|
+
};
|
|
1664
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1665
|
+
return () => {
|
|
1666
|
+
window.cancelAnimationFrame(frame);
|
|
1667
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
1668
|
+
};
|
|
1669
|
+
}, [disclosure]);
|
|
1676
1670
|
|
|
1677
|
-
if (!open) return null;
|
|
1678
1671
|
return h(
|
|
1679
|
-
"
|
|
1680
|
-
{
|
|
1681
|
-
|
|
1672
|
+
"section",
|
|
1673
|
+
{
|
|
1674
|
+
ref: workspaceRef,
|
|
1675
|
+
className: "dsh-auto-workspace",
|
|
1676
|
+
"data-dsh-automations-workspace": "true",
|
|
1677
|
+
"aria-labelledby": titleId,
|
|
1678
|
+
},
|
|
1682
1679
|
h(
|
|
1683
|
-
"
|
|
1684
|
-
{
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
role: "dialog",
|
|
1688
|
-
tabIndex: -1,
|
|
1689
|
-
"aria-modal": "true",
|
|
1690
|
-
"aria-labelledby": titleId,
|
|
1691
|
-
onKeyDownCapture: (event) => {
|
|
1692
|
-
const panel = panelRef.current;
|
|
1693
|
-
if (panel && event.target && !panel.contains(event.target)) return;
|
|
1694
|
-
if (event.key === "Escape") {
|
|
1695
|
-
if (panelRef.current?.querySelector('.dsh-auto-picker-trigger[aria-expanded="true"]')) return;
|
|
1696
|
-
event.preventDefault();
|
|
1697
|
-
disclosure.close();
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1700
|
-
trapModalTab(event, panelRef.current);
|
|
1701
|
-
},
|
|
1702
|
-
},
|
|
1680
|
+
"header",
|
|
1681
|
+
{ className: "dsh-auto-workspace-toolbar" },
|
|
1682
|
+
h("span", { className: "dsh-auto-workspace-icon", "aria-hidden": "true" }, h(AutomationGlyph, { size: 16 })),
|
|
1683
|
+
h("strong", { id: titleId, className: "dsh-auto-workspace-title" }, "Automations"),
|
|
1703
1684
|
h(
|
|
1704
|
-
|
|
1705
|
-
{
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
"
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
title: "Close",
|
|
1715
|
-
onClick: disclosure.close,
|
|
1716
|
-
},
|
|
1717
|
-
h(IconCloseOutline16),
|
|
1718
|
-
),
|
|
1685
|
+
Button,
|
|
1686
|
+
{
|
|
1687
|
+
type: "button",
|
|
1688
|
+
variant: "toolbar",
|
|
1689
|
+
size: "sm",
|
|
1690
|
+
icon: h(IconChevronLeftOutline14),
|
|
1691
|
+
onClick: disclosure.close,
|
|
1692
|
+
"data-dsh-automations-exit": "true",
|
|
1693
|
+
},
|
|
1694
|
+
"Exit Automations",
|
|
1719
1695
|
),
|
|
1720
|
-
h("div", { className: "dsh-auto-overlay-body" }, h(AutomationsSection)),
|
|
1721
1696
|
),
|
|
1697
|
+
h("div", { className: "dsh-auto-workspace-scroll" }, h(AutomationsSection, { centerMode: true })),
|
|
1722
1698
|
);
|
|
1723
1699
|
}
|
|
1724
1700
|
|
|
@@ -1731,17 +1707,15 @@ window.__ModuleLoader__.load({
|
|
|
1731
1707
|
".dsh-auto-sidebar-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
1732
1708
|
".dsh-auto-sidebar-action-rail{width:36px;height:36px;margin:0;}",
|
|
1733
1709
|
".dsh-auto-sidebar-action-rail .dsh-auto-sidebar-trigger{width:36px;height:36px;margin:0;padding:0;justify-content:center;gap:0;border-radius:50%;}",
|
|
1734
|
-
".dsh-auto-
|
|
1735
|
-
".dsh-auto-
|
|
1736
|
-
".dsh-auto-
|
|
1737
|
-
".dsh-auto-
|
|
1738
|
-
".dsh-auto-
|
|
1739
|
-
".dsh-auto-
|
|
1740
|
-
".dsh-auto-overlay-close:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4176e6);outline-offset:1px;}",
|
|
1741
|
-
".dsh-auto-overlay-body{box-sizing:border-box;min-height:0;flex:1;padding:0 28px 28px;overflow-y:auto;overscroll-behavior:contain;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);}",
|
|
1742
|
-
".dsh-auto-overlay-body>.dsh-auto-root{width:100%;margin:0 auto;padding-top:0;}",
|
|
1710
|
+
".dsh-auto-workspace{box-sizing:border-box;width:100%;height:100%;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;color:var(--dsw-alias-label-primary,#0f1115);background:var(--dsw-alias-bg-base,#fff);font-family:inherit;}",
|
|
1711
|
+
".dsh-auto-workspace-toolbar{box-sizing:border-box;width:100%;height:44px;flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px 6px 12px;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(15,17,21,.14));background:var(--dsw-alias-bg-base,#fff);}",
|
|
1712
|
+
".dsh-auto-workspace-icon{width:28px;height:28px;flex:none;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-state-business-primary,#4176e6);background:color-mix(in srgb,var(--dsw-alias-state-business-primary,#4176e6) 10%,transparent);}",
|
|
1713
|
+
".dsh-auto-workspace-title{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;}",
|
|
1714
|
+
".dsh-auto-workspace-scroll{container:dsh-auto-workspace / inline-size;box-sizing:border-box;min-height:0;flex:1;padding:24px clamp(20px,4vw,48px) 40px;overflow-y:auto;overscroll-behavior:contain;--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);}",
|
|
1715
|
+
".dsh-auto-workspace-scroll>.dsh-auto-root{width:100%;margin:0 auto;padding-top:0;}",
|
|
1743
1716
|
".dsh-auto-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important;}",
|
|
1744
1717
|
".dsh-auto-root{--dsh-auto-border:var(--dsw-alias-border-l2,rgba(15,17,21,.14));--dsh-auto-surface:var(--dsw-alias-bg-layer-3,#fff);--dsh-auto-surface-active:var(--dsw-alias-bg-layer-2,#fff);--dsh-auto-input-bg:var(--dsw-specific-input-major,var(--dsw-alias-bg-layer-1,#fff));--dsh-auto-text:var(--dsw-alias-label-primary,#0f1115);--dsh-auto-text-secondary:var(--dsw-alias-label-secondary,#4f5661);--dsh-auto-muted:var(--dsw-alias-label-tertiary,#81858c);--dsh-auto-caption:var(--dsw-alias-label-caption,#adb2b8);--dsh-auto-accent:var(--dsw-alias-state-business-primary,#4176e6);--dsh-auto-danger:var(--dsw-alias-state-error-primary,#ec1313);--dsh-auto-success:var(--dsw-alias-state-success-primary,#22c55e);--dsh-auto-warning:var(--dsw-alias-state-warn-primary,#f59e0b);box-sizing:border-box;max-width:820px;padding-top:12px;display:flex;flex-direction:column;gap:16px;font-family:inherit;color:var(--dsh-auto-text);}",
|
|
1718
|
+
".dsh-auto-root-workspace{max-width:960px;}",
|
|
1745
1719
|
"body:not([data-ds-dark-theme]) .dsh-auto-root{color-scheme:light;}",
|
|
1746
1720
|
"body[data-ds-dark-theme] .dsh-auto-root{color-scheme:dark;}",
|
|
1747
1721
|
".dsh-auto-root *,.dsh-auto-root *::before,.dsh-auto-root *::after{box-sizing:border-box;}",
|
|
@@ -1837,13 +1811,34 @@ window.__ModuleLoader__.load({
|
|
|
1837
1811
|
"@keyframes dsh-auto-pulse{0%,100%{opacity:1}50%{opacity:.35}}",
|
|
1838
1812
|
".dsh-auto-empty,.dsh-auto-loading,.dsh-auto-error{padding:22px 16px;text-align:center;border:1px dashed var(--dsh-auto-border);border-radius:12px;font-size:13px;color:var(--dsh-auto-text-secondary);}",
|
|
1839
1813
|
".dsh-auto-error{color:var(--dsh-auto-danger);display:flex;flex-direction:column;gap:10px;align-items:center;}",
|
|
1840
|
-
"@
|
|
1814
|
+
"@container dsh-auto-workspace (max-width:680px){.dsh-auto-formgrid{grid-template-columns:1fr;}.dsh-auto-card-head{flex-direction:column;align-items:flex-start;}.dsh-auto-run-name{max-width:150px;}}",
|
|
1815
|
+
"@media (max-width:640px){.dsh-auto-workspace-toolbar{padding-inline:8px;}.dsh-auto-workspace-scroll{padding:16px 14px 28px;}.dsh-auto-formgrid{grid-template-columns:1fr;}.dsh-auto-card-head{flex-direction:column;align-items:flex-start;}.dsh-auto-run-name{max-width:150px;}}",
|
|
1841
1816
|
].join("\n");
|
|
1842
1817
|
|
|
1843
1818
|
function apply(ctx) {
|
|
1844
1819
|
const disclosure = createDisclosureStore();
|
|
1845
|
-
|
|
1846
|
-
|
|
1820
|
+
let centerDeclared = false;
|
|
1821
|
+
let disposeCenter = null;
|
|
1822
|
+
const unmountCenter = () => {
|
|
1823
|
+
if (!disposeCenter) return;
|
|
1824
|
+
const dispose = disposeCenter;
|
|
1825
|
+
disposeCenter = null;
|
|
1826
|
+
dispose();
|
|
1827
|
+
};
|
|
1828
|
+
const mountCenter = () => {
|
|
1829
|
+
if (!centerDeclared || !disclosure.getSnapshot() || disposeCenter) return;
|
|
1830
|
+
try {
|
|
1831
|
+
disposeCenter = ctx.slots.register({
|
|
1832
|
+
name: "conversation",
|
|
1833
|
+
priority: -200,
|
|
1834
|
+
inject: () => ({ disclosure }),
|
|
1835
|
+
}, AutomationsWorkspace);
|
|
1836
|
+
} catch (error) {
|
|
1837
|
+
console.error("dsh automations: could not mount center workspace", error);
|
|
1838
|
+
disclosure.close();
|
|
1839
|
+
}
|
|
1840
|
+
};
|
|
1841
|
+
|
|
1847
1842
|
ctx.effect(() => {
|
|
1848
1843
|
const tag = document.createElement("style");
|
|
1849
1844
|
tag.setAttribute("data-plugin", "@syncended/dsh-automations");
|
|
@@ -1853,7 +1848,28 @@ window.__ModuleLoader__.load({
|
|
|
1853
1848
|
tag.remove();
|
|
1854
1849
|
};
|
|
1855
1850
|
}, "@syncended/dsh-automations: client styles");
|
|
1856
|
-
ctx.effect(
|
|
1851
|
+
ctx.effect(
|
|
1852
|
+
() => ctx.slots.inject("conversation", () => {
|
|
1853
|
+
centerDeclared = true;
|
|
1854
|
+
mountCenter();
|
|
1855
|
+
return () => {
|
|
1856
|
+
centerDeclared = false;
|
|
1857
|
+
unmountCenter();
|
|
1858
|
+
};
|
|
1859
|
+
}),
|
|
1860
|
+
"@syncended/dsh-automations: center workspace",
|
|
1861
|
+
);
|
|
1862
|
+
ctx.effect(() => {
|
|
1863
|
+
const unsubscribe = disclosure.subscribe(() => {
|
|
1864
|
+
if (disclosure.getSnapshot()) mountCenter();
|
|
1865
|
+
else unmountCenter();
|
|
1866
|
+
});
|
|
1867
|
+
return () => {
|
|
1868
|
+
unsubscribe();
|
|
1869
|
+
unmountCenter();
|
|
1870
|
+
disclosure.dispose();
|
|
1871
|
+
};
|
|
1872
|
+
}, "@syncended/dsh-automations: workspace state");
|
|
1857
1873
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
1858
1874
|
name: "settings.section",
|
|
1859
1875
|
id: "automations",
|
|
@@ -1867,18 +1883,12 @@ window.__ModuleLoader__.load({
|
|
|
1867
1883
|
label: "Automations",
|
|
1868
1884
|
inject: () => ({ disclosure }),
|
|
1869
1885
|
}, AutomationsSidebarAction));
|
|
1870
|
-
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
1871
|
-
name: "shell.overlay",
|
|
1872
|
-
id: "automations",
|
|
1873
|
-
order: 50,
|
|
1874
|
-
label: "Automations",
|
|
1875
|
-
inject: () => ({ disclosure }),
|
|
1876
|
-
}, AutomationsOverlay));
|
|
1877
1886
|
}
|
|
1878
1887
|
|
|
1879
1888
|
exports.agentPresetDisplayLabel = agentPresetDisplayLabel;
|
|
1880
1889
|
exports.permissionPresetPresentation = permissionPresetPresentation;
|
|
1881
1890
|
exports.PermissionPresetPicker = PermissionPresetPicker;
|
|
1891
|
+
exports.__testing = Object.freeze({ nextFormInstancePrefix });
|
|
1882
1892
|
exports.inject = inject;
|
|
1883
1893
|
exports.apply = apply;
|
|
1884
1894
|
return module.exports;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncended/dsh-automations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Durable cron automations for DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"inject": [
|
|
31
31
|
"@deepseek-ai/dsh-client-runtime",
|
|
32
32
|
"@deepseek-ai/dsh-client-ui-layout",
|
|
33
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
33
34
|
"@deepseek-ai/dsh-client-ui-sidebar",
|
|
34
35
|
"@deepseek-ai/dsh-client-ui-settings"
|
|
35
36
|
],
|
|
@@ -82,6 +83,7 @@
|
|
|
82
83
|
"@deepseek-ai/dsh-agent-default-model": "^0.1.1-rc.2",
|
|
83
84
|
"@deepseek-ai/dsh-agent-presets": "^0.1.1-rc.2",
|
|
84
85
|
"@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.2",
|
|
85
87
|
"@deepseek-ai/dsh-client-ui-layout": "^0.1.1-rc.2",
|
|
86
88
|
"@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.2",
|
|
87
89
|
"@deepseek-ai/dsh-client-ui-sidebar": "^0.1.1-rc.2",
|
|
@@ -97,6 +99,7 @@
|
|
|
97
99
|
"@deepseek-ai/dsh-agent-default-model": "0.1.1-rc.2",
|
|
98
100
|
"@deepseek-ai/dsh-agent-presets": "0.1.1-rc.2",
|
|
99
101
|
"@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
|
|
102
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.1-rc.2",
|
|
100
103
|
"@deepseek-ai/dsh-client-ui-layout": "0.1.1-rc.2",
|
|
101
104
|
"@deepseek-ai/dsh-client-ui-primitives": "0.1.1-rc.2",
|
|
102
105
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
|