dsh-ptc-plus 0.3.2 → 0.4.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.en.md +65 -78
- package/README.md +65 -78
- package/assets/ptc-plus-bindings-en.png +0 -0
- package/assets/ptc-plus-bindings-zh.png +0 -0
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-repair-zh.png +0 -0
- package/assets/ptc-plus-repl-workspace-en.png +0 -0
- package/assets/ptc-plus-repl-workspace-zh.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.js +30596 -742
- package/compiler-amaro.cjs +5 -0
- package/compiler-amaro.cjs.map +6 -0
- package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
- package/compiler-assets.json +3 -0
- package/compiler-core.cjs +554 -0
- package/compiler-core.cjs.map +6 -0
- package/compiler-platform.cjs +2 -0
- package/compiler-platform.cjs.map +6 -0
- package/compiler-typescript.cjs +388 -0
- package/compiler-typescript.cjs.map +6 -0
- package/docs/README.md +6 -0
- package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
- package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
- package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
- package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
- package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
- package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
- package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
- package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
- package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
- package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
- package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
- package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
- package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
- package/docs/adr/0023-global-user-bindings.md +104 -0
- package/docs/adr/0024-repl-console-observation.md +33 -0
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
- package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
- package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
- package/docs/architecture.md +73 -21
- package/docs/binding-review-placement-design.md +200 -0
- package/docs/capability-projection.md +1 -1
- package/docs/client-ui.md +95 -19
- package/docs/durability-design.md +25 -10
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +72 -25
- package/docs/semantic-validation.md +29 -0
- package/docs/stateful-binding-updates-proposal.md +755 -0
- package/docs/user-bindings.en.md +64 -0
- package/docs/user-bindings.md +64 -0
- package/docs/value-wire.md +3 -3
- package/docs/verification.md +57 -0
- package/index.js +369 -92
- package/internal/ast-traversal.js +5 -2
- package/internal/binding-descriptors.js +1 -0
- package/internal/binding-pattern-traversal.js +25 -0
- package/internal/binding-pattern.js +26 -29
- package/internal/binding-source-analysis.js +391 -0
- package/internal/binding-update-policy.js +66 -0
- package/internal/bounded-worker-round.js +56 -0
- package/internal/callable-definition-environment.js +42 -0
- package/internal/callable-source-catalog.js +129 -0
- package/internal/callable-source-encoding.js +47 -0
- package/internal/callable-source-facts.js +459 -0
- package/internal/callable-source-format.js +2 -0
- package/internal/callable-source-lowering.js +123 -0
- package/internal/cell-analysis-contract.js +25 -0
- package/internal/cell-analysis.js +240 -290
- package/internal/cell-completion.js +15 -0
- package/internal/cell-error.js +7 -0
- package/internal/cell-parser.js +66 -0
- package/internal/cell-rewriter.js +3 -677
- package/internal/commonjs-export-evidence.js +63 -0
- package/internal/commonjs-source-evidence.js +72 -0
- package/internal/compiler-amaro.cjs +2 -0
- package/internal/compiler-compression.js +12 -0
- package/internal/compiler-data.js +58 -0
- package/internal/compiler-descriptors.js +54 -0
- package/internal/compiler-dynamic-cache.js +48 -0
- package/internal/compiler-entry.js +35 -0
- package/internal/compiler-generated-names.js +17 -0
- package/internal/compiler-intrinsics.js +84 -0
- package/internal/compiler-module-links.js +34 -0
- package/internal/compiler-operations.js +61 -0
- package/internal/compiler-platform-factory.js +84 -0
- package/internal/compiler-platform.js +136 -0
- package/internal/compiler-record-roles.js +53 -0
- package/internal/compiler-region-output.js +259 -0
- package/internal/compiler-resource-lowering.js +103 -0
- package/internal/compiler-scope-facts.js +115 -0
- package/internal/compiler-service.js +109 -0
- package/internal/compiler-source-cache.js +32 -0
- package/internal/compiler-source-pieces.js +93 -0
- package/internal/compiler-source-regions.js +132 -0
- package/internal/compiler-storage-source.js +54 -0
- package/internal/compiler-text.js +15 -0
- package/internal/compiler-typescript.cjs +2 -0
- package/internal/config-spec.js +83 -27
- package/internal/cordis-tools-owner.js +130 -21
- package/internal/diagnostic.js +27 -1
- package/internal/direct-surface-owner.js +76 -23
- package/internal/dynamic-binding-evidence.js +16 -0
- package/internal/dynamic-environment-compiler.js +779 -0
- package/internal/dynamic-environment-integration.js +87 -0
- package/internal/dynamic-environment-runtime.js +362 -0
- package/internal/dynamic-native-calls.js +150 -0
- package/internal/dynamic-native-runtime.js +248 -0
- package/internal/dynamic-scope-analysis.js +90 -0
- package/internal/edit-transport-owner.js +27 -2
- package/internal/execution-seam-compat.js +193 -0
- package/internal/failure-reporting.js +118 -18
- package/internal/host-rpc.js +66 -0
- package/internal/isolated-worker.js +548 -0
- package/internal/kernel-child.js +139 -0
- package/internal/kernel-worker.js +904 -120
- package/internal/language-semantics.js +14 -0
- package/internal/legacy-binding-catalog.js +48 -0
- package/internal/legacy-cell-analysis.js +600 -0
- package/internal/legacy-cell-parser.js +50 -0
- package/internal/legacy-cell-rewriter.js +631 -0
- package/internal/legacy-repl-convenience.js +291 -0
- package/internal/managed-module-operations.js +170 -0
- package/internal/module-compilation.js +321 -0
- package/internal/module-runtime-platform.js +19 -0
- package/internal/module-transform-contract.js +12 -0
- package/internal/native-await-declarations.js +68 -0
- package/internal/native-root-compilation.js +54 -0
- package/internal/native-root-dynamic.js +67 -0
- package/internal/recovery-tips.js +27 -15
- package/internal/rejected-cell-editor.js +13 -8
- package/internal/repl-convenience.js +2 -289
- package/internal/repl-memory-projection.js +81 -12
- package/internal/repl-observation-interest.js +70 -0
- package/internal/repl-rewrite-contract.js +6 -0
- package/internal/repl-scope-normalizer.js +2091 -0
- package/internal/repl-value-observer.js +114 -0
- package/internal/rpc-contract.js +52 -0
- package/internal/runtime-bridge-owner.js +172 -28
- package/internal/runtime-config.js +48 -52
- package/internal/runtime-contexts.js +82 -10
- package/internal/runtime-messages.js +111 -0
- package/internal/session-cell-executor.js +401 -87
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +106 -0
- package/internal/session-journal.js +184 -654
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +256 -95
- package/internal/session-state.js +247 -71
- package/internal/source-position-map.js +211 -71
- package/internal/stateful-module-compiler.js +154 -0
- package/internal/stateful-module-runtime.js +303 -0
- package/internal/stateful-root-compiler.js +598 -0
- package/internal/stateful-root-runtime.js +340 -0
- package/internal/typert-codec-compat.js +28 -0
- package/internal/typescript-transform.js +29 -0
- package/internal/user-binding-authoring.js +70 -0
- package/internal/user-binding-console-worker.js +184 -0
- package/internal/user-binding-console.js +148 -0
- package/internal/user-binding-draft-projection.js +335 -0
- package/internal/user-binding-model-context.js +31 -0
- package/internal/user-binding-runner.js +56 -0
- package/internal/user-bindings-owner.js +1065 -0
- package/internal/user-bindings-store.js +293 -0
- package/internal/user-bindings.js +353 -0
- package/internal/value-wire-schema.js +28 -0
- package/internal/value-wire.js +29 -20
- package/internal/worker-client.js +57 -67
- package/internal/worker-environment.js +45 -0
- package/internal/worker-output-relay.js +29 -0
- package/internal/worker-shutdown.js +14 -0
- package/package.json +75 -7
- package/src/client-activity.js +88 -53
- package/src/client-authoring-view.js +580 -0
- package/src/client-binding-review.js +230 -0
- package/src/client-bindings-data.js +29 -0
- package/src/client-catalog.js +127 -0
- package/src/client-code-editor.js +84 -0
- package/src/client-console.js +112 -0
- package/src/client-copy.js +370 -0
- package/src/client-feature-gates.js +62 -0
- package/src/client-host-compat.js +150 -0
- package/src/client-indicator-view.js +267 -0
- package/src/client-repl-view.js +292 -0
- package/src/client-rpc.js +20 -0
- package/src/client-settings-view.js +221 -0
- package/src/client-styles.js +106 -0
- package/src/client-tool-view.js +108 -0
- package/src/client-transport.js +159 -0
- package/src/client-workbench.js +521 -0
- package/src/client.js +233 -615
package/src/client.js
CHANGED
|
@@ -1,149 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createClientRpc } from './client-rpc.js'
|
|
2
|
+
import { RPC_CONTRACTS } from '../internal/rpc-contract.js'
|
|
3
|
+
import { SETTINGS_NAMESPACE } from '../internal/config-spec.js'
|
|
4
|
+
import { createPtcToolView } from './client-tool-view.js'
|
|
5
|
+
import { createPtcSettingsView } from './client-settings-view.js'
|
|
6
|
+
import { createReplView } from './client-repl-view.js'
|
|
7
|
+
import { createAuthoringView } from './client-authoring-view.js'
|
|
8
|
+
import { createIndicatorView } from './client-indicator-view.js'
|
|
9
|
+
import { createTypeScriptEditor } from './client-code-editor.js'
|
|
10
|
+
import { createBindingConsole } from './client-console.js'
|
|
11
|
+
import {
|
|
12
|
+
isIdleSessionComposer,
|
|
13
|
+
publishSettingsCard,
|
|
14
|
+
sessionUsesPtcPreset,
|
|
15
|
+
useSessionPreset,
|
|
16
|
+
watchCurrentSessionPreset,
|
|
17
|
+
} from './client-host-compat.js'
|
|
3
18
|
import {
|
|
4
19
|
normalizeReplMemorySnapshot,
|
|
5
20
|
unavailableReplMemorySnapshot,
|
|
6
21
|
} from '../internal/repl-memory-projection.js'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.ptcPlusChevron{display:flex;color:var(--dsw-alias-label-tertiary,#74777d);transition:transform .18s ease}.ptcPlusChevron[data-open=true]{transform:rotate(180deg)}.ptcPlusBody{display:grid;grid-template-rows:0fr;transition:grid-template-rows .2s ease}.ptcPlusBody[data-open=true]{grid-template-rows:1fr}.ptcPlusBodyInner{min-height:0;overflow:hidden}.ptcPlusFields{margin:0 16px;padding:8px 0 12px;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}
|
|
15
|
-
.ptcPlusGroup+.ptcPlusGroup{margin-top:14px}.ptcPlusGroupTitle{margin:0;padding:8px 0 5px;color:var(--dsw-alias-label-secondary,#52565d);font-size:11px;font-weight:600;letter-spacing:0;line-height:16px}.ptcPlusRow{display:flex;align-items:center;gap:12px;min-height:48px;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}.ptcPlusRow:first-child{border-top:0}.ptcPlusMain{flex:1;min-width:0}.ptcPlusLabel{font-size:14px;font-weight:500;line-height:20px}.ptcPlusDetail,.ptcPlusMessage{color:var(--dsw-alias-label-tertiary,#74777d);font-size:12px;line-height:18px;overflow-wrap:anywhere}.ptcPlusInput{box-sizing:border-box;min-width:72px;width:140px;padding:5px 8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:6px;background:var(--dsw-alias-bg-layer-1,#fff);color:inherit;font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace}.ptcPlusCheck{width:18px;height:18px;accent-color:var(--dsw-alias-interactive-primary,#4d6bfe)}
|
|
16
|
-
.ptcPlusFooter{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:8px}.ptcPlusButton{min-height:32px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:6px;background:transparent;color:inherit;cursor:pointer;font:500 13px/20px inherit;transition:background-color .16s ease,border-color .16s ease}.ptcPlusButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusButton:disabled,.ptcPlusInput:disabled,.ptcPlusCheck:disabled{cursor:not-allowed;opacity:.55}
|
|
17
|
-
.ptcPlusActiveShell{display:inline-flex;align-items:center}.ptcPlusActive{appearance:none;display:inline-flex;height:24px;align-items:center;gap:5px;padding:0 8px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 32%,transparent);border-radius:6px;background:var(--dsw-alias-state-success-tertiary,#e7f7ef);color:var(--dsw-alias-state-success-primary,#16794f);cursor:help;font:600 12px/18px inherit;white-space:nowrap;transition:background-color .14s ease,border-color .14s ease}.ptcPlusActive:hover,.ptcPlusActive[aria-expanded=true]{border-color:color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 48%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 16%,var(--dsw-alias-bg-layer-3,#fff))}.ptcPlusActive:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary,#16794f);outline-offset:2px}.ptcPlusReplPopover{position:fixed;z-index:2147483000;inset:auto;display:none;box-sizing:border-box;margin:0;padding:0;border:0;overflow:visible;background:transparent;color:var(--dsw-alias-label-primary,#18191c)}.ptcPlusReplPopover:popover-open,.ptcPlusReplPopover[data-open=true]{display:block}.ptcPlusReplPopover::backdrop{background:transparent}.ptcPlusReplCard{display:flex;max-height:inherit;overflow:hidden;flex-direction:column;border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 22%,var(--dsw-alias-border-l2,rgba(0,0,0,.1)));border-top:3px solid var(--dsw-alias-state-success-primary,#16794f);border-radius:8px;background:var(--dsw-alias-bg-layer-3,#fff);box-shadow:0 14px 36px rgba(16,24,40,.2),0 3px 10px rgba(16,24,40,.1);color:var(--dsw-alias-label-primary,#18191c);white-space:normal}.ptcPlusReplHead{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;column-gap:8px;padding:11px 13px 10px;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));background:color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 7%,var(--dsw-alias-bg-layer-3,#fff))}.ptcPlusReplStatusDot{grid-row:1/3;width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary,#16794f);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-state-success-primary,#16794f) 14%,transparent)}.ptcPlusReplTitle,.ptcPlusReplSummary{display:block;min-width:0}.ptcPlusReplTitle{font-size:13px;font-weight:600;line-height:19px}.ptcPlusReplSummary{color:var(--dsw-alias-label-tertiary,#74777d);font-size:11px;line-height:16px}.ptcPlusReplList{min-height:0;margin:0;padding:5px 0;overflow:auto;overscroll-behavior:contain;list-style:none;scrollbar-gutter:stable}.ptcPlusReplBinding{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:4px 10px;padding:7px 12px}.ptcPlusReplBinding:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusReplIdentity{display:flex;min-width:0;align-items:center;gap:7px}.ptcPlusReplName{min-width:0;overflow:hidden;font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.ptcPlusReplKind{flex:none;padding:1px 6px;border:1px solid color-mix(in srgb,currentColor 22%,transparent);border-radius:999px;background:color-mix(in srgb,currentColor 10%,transparent);font-size:10px;font-weight:600;line-height:15px}.ptcPlusReplKind[data-kind=variable]{color:var(--dsw-alias-interactive-primary,#315fbd)}.ptcPlusReplKind[data-kind=function]{color:#7651b5}.ptcPlusReplKind[data-kind=class]{color:var(--dsw-alias-state-warning-primary,#946200)}.ptcPlusReplKind[data-kind=import]{color:#14766f}.ptcPlusReplPreview{grid-column:1;min-width:0;overflow:hidden;color:var(--dsw-alias-label-tertiary,#74777d);font:11px/16px ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.ptcPlusReplInspect{grid-column:2;grid-row:1/3;display:inline-flex;align-items:center;gap:4px;padding:3px 5px;border:0;border-radius:4px;background:transparent;color:var(--dsw-alias-label-secondary,#52565d);cursor:pointer;font:500 11px/17px inherit;white-space:nowrap}.ptcPlusReplInspect:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06));color:var(--dsw-alias-interactive-primary,#4d6bfe)}.ptcPlusReplInspect:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:1px}.ptcPlusReplDefinition{grid-column:1/-1;min-width:0;margin-top:4px;padding:8px;border-left:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.03))}.ptcPlusReplLocation{display:block;margin-bottom:5px;color:var(--dsw-alias-label-tertiary,#74777d);font-size:10px;line-height:15px}.ptcPlusReplCode{max-height:180px;margin:0;overflow:auto;color:inherit;font:11px/16px ui-monospace,SFMono-Regular,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.ptcPlusReplEmpty,.ptcPlusReplMore{display:block;color:var(--dsw-alias-label-tertiary,#74777d)}.ptcPlusReplEmpty{padding:18px 13px;font-size:12px;line-height:18px}.ptcPlusReplMore{padding:8px 13px;border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.03));font-size:11px;line-height:17px}
|
|
18
|
-
.ptcPlusReplList{max-height:min(52vh,480px)}.ptcPlusReplBinding{grid-template-columns:minmax(0,1fr) 24px;gap:3px 8px;min-height:36px;padding:5px 12px;content-visibility:auto;contain-intrinsic-size:36px;cursor:pointer;transition:background-color .16s ease}.ptcPlusReplBinding:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:-2px}.ptcPlusReplBinding[data-expanded=true]{background:color-mix(in srgb,var(--dsw-alias-interactive-primary,#4d6bfe) 5%,transparent)}.ptcPlusReplName{grid-column:1}.ptcPlusReplName[data-kind=variable]{color:var(--dsw-alias-interactive-primary,#315fbd)}.ptcPlusReplName[data-kind=function]{color:#7651b5}.ptcPlusReplName[data-kind=class]{color:var(--dsw-alias-state-warning-primary,#946200)}.ptcPlusReplName[data-kind=import]{color:#14766f}.ptcPlusReplPreview{grid-column:1}.ptcPlusReplChevron{grid-column:2;grid-row:1/3;display:flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary,#74777d);transition:transform .2s ease}.ptcPlusReplChevron[data-open=true]{transform:rotate(180deg)}.ptcPlusReplDefinitionWrap{grid-column:1/-1;display:grid;grid-template-rows:0fr;min-width:0;transition:grid-template-rows .24s cubic-bezier(.2,.7,.2,1)}.ptcPlusReplDefinitionWrap[data-open=true]{grid-template-rows:1fr}.ptcPlusReplDefinitionInner{min-height:0;overflow:hidden}
|
|
19
|
-
.ptcPlusTool{display:flex;min-width:0;flex-direction:column}.ptcPlusToolPreview{display:flex;min-width:0;flex:1 1 auto;flex-direction:row;align-items:center;overflow:hidden;margin-left:7px}.ptcPlusToolPreview .ptcPlusFeatures{flex:0 1 auto;flex-wrap:nowrap;overflow:hidden;margin:0 0 0 7px}.ptcPlusToolSummaryLine{box-sizing:border-box;display:flex;min-width:0;min-height:20px;flex:1 1 auto;align-items:center;gap:7px;padding:0;color:inherit;line-height:20px}.ptcPlusToolSummary{box-sizing:border-box;display:flex;min-width:0;min-height:32px;align-items:center;gap:7px;padding:0;color:inherit;line-height:20px}.ptcPlusToolSummary[data-expandable=true]{cursor:pointer}.ptcPlusToolSummary[data-expandable=true]:hover .ptcPlusToolTitle{color:var(--dsw-alias-interactive-primary,#4d6bfe)}.ptcPlusToolSummary:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:2px}.ptcPlusToolLeading{display:flex;width:16px;height:20px;flex:none;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary,#74777d)}.ptcPlusToolChevron{transition:transform .16s ease}.ptcPlusToolChevron[data-open=true]{transform:rotate(180deg)}.ptcPlusToolTitle{display:flex;height:20px;flex:none;align-items:center;font-size:13px;font-weight:500;line-height:20px}.ptcPlusToolState{display:flex;height:20px;flex:none;align-items:center;color:var(--dsw-alias-label-tertiary,#74777d);font-size:11px;line-height:20px}.ptcPlusToolSummaryLine[data-state=running] .ptcPlusToolState,.ptcPlusToolSummary[data-state=running] .ptcPlusToolState{color:var(--dsw-alias-interactive-primary,#4d6bfe)}.ptcPlusToolSummaryLine[data-state=error] .ptcPlusToolState,.ptcPlusToolSummary[data-state=error] .ptcPlusToolState{color:var(--dsw-alias-state-danger-primary,#c43d3d)}.ptcPlusToolSummaryLine[data-state=stopped] .ptcPlusToolState,.ptcPlusToolSummary[data-state=stopped] .ptcPlusToolState{color:var(--dsw-alias-state-warning-primary,#a15c00)}.ptcPlusToolSep{width:3px;height:3px;flex:none;border-radius:50%;background:var(--dsw-alias-label-tertiary,#74777d)}.ptcPlusToolDescription{display:flex;min-width:0;min-height:20px;flex:1 1 auto;align-items:center;overflow:hidden;color:var(--dsw-alias-label-secondary,#52565d);font-size:13px;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.ptcPlusToolPreview .ptcPlusFeature{flex:none;max-width:180px;white-space:nowrap}.ptcPlusToolPreview .ptcPlusFeatureDetail{max-width:120px}.ptcPlusToolSummaryLine[data-state=error] .ptcPlusToolDescription,.ptcPlusToolSummary[data-state=error] .ptcPlusToolDescription{color:var(--dsw-alias-state-danger-primary,#c43d3d)}.ptcPlusToolSummaryLine[data-state=stopped] .ptcPlusToolDescription,.ptcPlusToolSummary[data-state=stopped] .ptcPlusToolDescription{color:var(--dsw-alias-state-warning-primary,#a15c00)}
|
|
20
|
-
.ptcPlusFeatures{display:flex;min-width:0;flex-wrap:wrap;gap:3px 14px;margin:0 0 5px 23px}.ptcPlusFeature{display:inline-flex;min-width:0;align-items:center;gap:5px;color:var(--dsw-alias-label-secondary,#52565d);font-size:11px;line-height:17px}.ptcPlusFeature::before{width:4px;height:4px;flex:none;border-radius:50%;background:var(--dsw-alias-interactive-primary,#4d6bfe);content:''}.ptcPlusFeatureName{font-weight:500}.ptcPlusFeatureDetail{min-width:0;overflow:hidden;color:var(--dsw-alias-label-tertiary,#74777d);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}
|
|
21
|
-
.ptcPlusToolBody{margin:4px 0 8px 23px;border-left:2px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.03))}.ptcPlusToolSection{display:flex;min-width:0;flex-direction:column;gap:4px;padding:9px 11px}.ptcPlusToolSection+.ptcPlusToolSection{border-top:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1))}.ptcPlusToolSectionLabel{color:var(--dsw-alias-label-tertiary,#74777d);font-size:10px;font-weight:600;line-height:16px;text-transform:uppercase}.ptcPlusToolCode{max-height:320px;margin:0;overflow:auto;color:inherit;font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.ptcPlusIoCard{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.1));border-radius:12px;background:var(--dsw-alias-markdown-code-block,rgba(38,49,72,.06));overflow:hidden}.ptcPlusIoText{max-height:320px;margin:0;padding:12px 16px;overflow:auto;color:var(--dsw-alias-label-secondary,#52565d);font:12px/18px ui-monospace,SFMono-Regular,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.ptcPlusIoText[data-error]{color:var(--dsw-alias-state-error-primary,#c43d3d)}.ptcPlusInspect{display:inline-flex;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.1));border-radius:999px;background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-label-secondary,#52565d);cursor:pointer;opacity:0;font-size:11px;line-height:16px;transition:opacity .1s ease;display:inline-flex}.ptcPlusTool:hover .ptcPlusInspect,.ptcPlusInspect:focus-visible{opacity:1}.ptcPlusInspect:hover{background:var(--dsw-alias-interactive-bg-hover-solid,rgba(38,49,72,.06));color:var(--dsw-alias-label-primary,#18191c)}
|
|
22
|
-
@media(max-width:560px){.ptcPlusHeader{padding:12px}.ptcPlusFields{margin:0 12px}.ptcPlusRow{align-items:flex-start;flex-direction:column;gap:6px;padding:10px 0}.ptcPlusInput{width:100%}.ptcPlusFooter{align-items:stretch;flex-direction:column}.ptcPlusButton{width:100%}.ptcPlusFeatures,.ptcPlusToolBody{margin-left:0}.ptcPlusToolSummary .ptcPlusToolDescription{white-space:normal;overflow-wrap:anywhere}}
|
|
23
|
-
@media(prefers-reduced-motion:reduce){.ptcPlusHeader,.ptcPlusChevron,.ptcPlusBody,.ptcPlusButton,.ptcPlusActive,.ptcPlusToolChevron,.ptcPlusReplChevron,.ptcPlusReplDefinitionWrap,.ptcPlusInspect{transition:none}}
|
|
24
|
-
/* The summary button owns disclosure; definition content is a separate grid item. */
|
|
25
|
-
.ptcPlusReplBinding{padding:0;cursor:default}.ptcPlusReplBindingTrigger{appearance:none;display:grid;width:100%;grid-column:1/-1;grid-template-columns:minmax(0,1fr) 24px;gap:3px 8px;min-height:36px;padding:5px 12px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer;font:inherit;transition:background-color .16s ease}.ptcPlusReplBindingTrigger:hover,.ptcPlusReplBindingTrigger[aria-expanded=true]{background:color-mix(in srgb,var(--dsw-alias-interactive-primary,#4d6bfe) 5%,transparent)}.ptcPlusReplBindingTrigger:focus-visible{outline:2px solid var(--dsw-alias-interactive-primary,#4d6bfe);outline-offset:-2px}
|
|
26
|
-
/* High-contrast TypeScript-like token colors adapt to the active text theme. */
|
|
27
|
-
.ptcPlusReplCard .ptcPlusReplName[data-kind=variable]{color:color-mix(in srgb,#005cc5 78%,var(--dsw-alias-label-primary,#18191c))}
|
|
28
|
-
.ptcPlusReplCard .ptcPlusReplName[data-kind=function]{color:color-mix(in srgb,#795e26 78%,var(--dsw-alias-label-primary,#18191c))}
|
|
29
|
-
.ptcPlusReplCard .ptcPlusReplName[data-kind=class]{color:color-mix(in srgb,#267f99 78%,var(--dsw-alias-label-primary,#18191c))}
|
|
30
|
-
.ptcPlusReplCard .ptcPlusReplName[data-kind=import]{color:color-mix(in srgb,#af00db 78%,var(--dsw-alias-label-primary,#18191c))}
|
|
31
|
-
/* Keep the session-header action on the same compact 32px rhythm as DSH chrome. */
|
|
32
|
-
.ptcPlusActiveShell{display:inline-flex;height:28px;align-items:center;justify-content:center;line-height:0;vertical-align:middle}.ptcPlusActive{box-sizing:border-box;height:28px;justify-content:center;gap:6px;padding:0 6px;border:0;background:transparent;font-family:inherit;font-size:13px;font-weight:500;line-height:18px}.ptcPlusActive::before{width:6px;height:6px;flex:none;border-radius:50%;background:currentColor;box-shadow:0 0 0 2px color-mix(in srgb,currentColor 18%,transparent);content:''}.ptcPlusActive:hover,.ptcPlusActive[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover,rgba(38,49,72,.06))}.ptcPlusActiveLabel{display:inline-flex;height:18px;align-items:center;line-height:18px}
|
|
33
|
-
`
|
|
34
|
-
|
|
35
|
-
/** Locale namespace owning every settings-card string (field copy plus chrome). */
|
|
36
|
-
const LOCALE_NS = 'settings.ptcPlus'
|
|
37
|
-
|
|
38
|
-
/** Card chrome copy; field labels and hints ride the shared config spec. */
|
|
39
|
-
const CHROME_COPY = Object.freeze({
|
|
40
|
-
zh: Object.freeze({
|
|
41
|
-
'card.description': 'PTC 模式的会话级 TypeScript REPL。',
|
|
42
|
-
'status.enabled': '已启用',
|
|
43
|
-
'status.disabled': '已停用',
|
|
44
|
-
'action.expand': '展开 PTC Plus 设置',
|
|
45
|
-
'action.collapse': '收起 PTC Plus 设置',
|
|
46
|
-
'state.syncing': '正在同步设置...',
|
|
47
|
-
'state.unavailable': '当前 DSH 实例未提供设置服务',
|
|
48
|
-
'footer.live': '设置会在修改后立即生效',
|
|
49
|
-
'footer.readOnly': '当前设置为只读',
|
|
50
|
-
'status.applied': '设置已立即生效',
|
|
51
|
-
'status.conflict': '设置未生效,请检查设置冲突',
|
|
52
|
-
'status.failed': '设置失败:{error}',
|
|
53
|
-
'indicator.title': 'PTC Plus 已启用;查看当前可复用的 REPL 绑定',
|
|
54
|
-
'memory.title': 'REPL 可复用绑定',
|
|
55
|
-
'memory.count': '{count} 个可复用绑定',
|
|
56
|
-
'memory.empty': '当前没有可复用绑定',
|
|
57
|
-
'memory.unavailable': '当前绑定状态尚不可确认',
|
|
58
|
-
'memory.more': '另有 {count} 个绑定未显示',
|
|
59
|
-
'memory.kind.variable': '变量',
|
|
60
|
-
'memory.kind.function': '函数',
|
|
61
|
-
'memory.kind.class': '类',
|
|
62
|
-
'memory.kind.import': '导入',
|
|
63
|
-
'memory.location': '第 {line} 行,第 {column} 列',
|
|
64
|
-
'tool.code': '执行',
|
|
65
|
-
'tool.codeEdit': '修正执行',
|
|
66
|
-
'tool.running': '正在运行',
|
|
67
|
-
'tool.completed': '执行完成',
|
|
68
|
-
'tool.failed': '执行失败',
|
|
69
|
-
'tool.stopped': '执行已中断',
|
|
70
|
-
'tool.source': '源码',
|
|
71
|
-
'tool.result': '结果',
|
|
72
|
-
'tool.copy': '复制代码',
|
|
73
|
-
'tool.copied': '已复制',
|
|
74
|
-
'tool.inspect': '检查调用',
|
|
75
|
-
'feature.safeEdit': '安全编辑执行',
|
|
76
|
-
'feature.codeRun': '隔离执行 code.run',
|
|
77
|
-
'feature.stateSaved': '保存 REPL 状态',
|
|
78
|
-
'feature.stateRestored': '恢复 REPL 状态',
|
|
79
|
-
'feature.stateDeleted': '删除 REPL 状态',
|
|
80
|
-
}),
|
|
81
|
-
en: Object.freeze({
|
|
82
|
-
'card.description': 'The session-bound TypeScript REPL for PTC mode.',
|
|
83
|
-
'status.enabled': 'Enabled',
|
|
84
|
-
'status.disabled': 'Disabled',
|
|
85
|
-
'action.expand': 'Expand PTC Plus settings',
|
|
86
|
-
'action.collapse': 'Collapse PTC Plus settings',
|
|
87
|
-
'state.syncing': 'Syncing settings...',
|
|
88
|
-
'state.unavailable': 'This DSH instance does not provide a settings service',
|
|
89
|
-
'footer.live': 'Changes take effect immediately.',
|
|
90
|
-
'footer.readOnly': 'These settings are read-only.',
|
|
91
|
-
'status.applied': 'Setting applied immediately.',
|
|
92
|
-
'status.conflict': 'The setting did not take effect; check for conflicting settings.',
|
|
93
|
-
'status.failed': 'Could not save: {error}',
|
|
94
|
-
'indicator.title': 'PTC Plus is active; view reusable REPL bindings',
|
|
95
|
-
'memory.title': 'Reusable REPL bindings',
|
|
96
|
-
'memory.count': '{count} reusable bindings',
|
|
97
|
-
'memory.empty': 'No reusable bindings',
|
|
98
|
-
'memory.unavailable': 'Current binding state cannot be confirmed',
|
|
99
|
-
'memory.more': '{count} more bindings not shown',
|
|
100
|
-
'memory.kind.variable': 'Variable',
|
|
101
|
-
'memory.kind.function': 'Function',
|
|
102
|
-
'memory.kind.class': 'Class',
|
|
103
|
-
'memory.kind.import': 'Import',
|
|
104
|
-
'memory.location': 'Line {line}, column {column}',
|
|
105
|
-
'tool.code': 'Code',
|
|
106
|
-
'tool.codeEdit': 'Code edit',
|
|
107
|
-
'tool.running': 'Running',
|
|
108
|
-
'tool.completed': 'Completed',
|
|
109
|
-
'tool.failed': 'Failed',
|
|
110
|
-
'tool.stopped': 'Stopped',
|
|
111
|
-
'tool.source': 'Source',
|
|
112
|
-
'tool.result': 'Result',
|
|
113
|
-
'tool.inspect': 'Inspect call',
|
|
114
|
-
'feature.safeEdit': 'Safe edit execution',
|
|
115
|
-
'feature.codeRun': 'Isolated code.run execution',
|
|
116
|
-
'feature.stateSaved': 'Saved REPL state',
|
|
117
|
-
'feature.stateRestored': 'Restored REPL state',
|
|
118
|
-
'feature.stateDeleted': 'Deleted REPL state',
|
|
119
|
-
'tool.copy': 'Copy code',
|
|
120
|
-
'tool.copied': 'Copied',
|
|
121
|
-
}),
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
/** Project one field's copy into locale dictionary keys; an empty hint has no key. */
|
|
125
|
-
function fieldCopy(field, locale) {
|
|
126
|
-
const copy = { [`${field.key}.label`]: locale === 'en' ? field.labelEn : field.label }
|
|
127
|
-
const description = locale === 'en' ? field.descriptionEn : field.description
|
|
128
|
-
if (description !== '') copy[`${field.key}.description`] = description
|
|
129
|
-
return copy
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/** Complete dictionaries for both shipped locales, derived once from the spec. */
|
|
133
|
-
const SETTINGS_COPY = Object.freeze(Object.fromEntries(
|
|
134
|
-
['zh', 'en'].map(locale => [locale, Object.freeze({
|
|
135
|
-
...CHROME_COPY[locale],
|
|
136
|
-
...Object.assign({}, ...CONFIG_GROUPS.map(group => ({
|
|
137
|
-
[`group.${group.key}`]: locale === 'en' ? group.labelEn : group.label,
|
|
138
|
-
}))),
|
|
139
|
-
...Object.assign({}, ...CONFIG_FIELDS.map(field => fieldCopy(field, locale))),
|
|
140
|
-
})]),
|
|
141
|
-
))
|
|
142
|
-
|
|
143
|
-
function sessionUsesPtcPreset(session) {
|
|
144
|
-
const preset = session?.projectionValues?.agentPreset ?? session?.agentPreset
|
|
145
|
-
return preset === 'ptc' || preset === 'code'
|
|
146
|
-
}
|
|
22
|
+
import { createBindingReviews } from './client-binding-review.js'
|
|
23
|
+
import { LOCALE_NS, SETTINGS_COPY } from './client-copy.js'
|
|
24
|
+
import { installStyles } from './client-styles.js'
|
|
25
|
+
import { featureEnabled, registerGated } from './client-feature-gates.js'
|
|
26
|
+
import { createCatalogOwner } from './client-catalog.js'
|
|
27
|
+
import { createUserBindingsWorkbench } from './client-workbench.js'
|
|
28
|
+
import { createBindingCommandAvailability, createReplObserver } from './client-transport.js'
|
|
147
29
|
|
|
148
30
|
window.__ModuleLoader__.load({
|
|
149
31
|
// Replaced by the bundle entry with the package name from package.json.
|
|
@@ -151,513 +33,249 @@ window.__ModuleLoader__.load({
|
|
|
151
33
|
factory: (require) => {
|
|
152
34
|
const React = require('react')
|
|
153
35
|
const {
|
|
36
|
+
Button,
|
|
154
37
|
CodeBlock,
|
|
155
38
|
DisclosureRow,
|
|
156
39
|
IconCheckOutline14,
|
|
157
40
|
IconChevronDownOutline14,
|
|
158
41
|
IconInspectOutline12,
|
|
42
|
+
IconSparkle16,
|
|
43
|
+
IconCloseOutline16,
|
|
44
|
+
IconSearchOutline16,
|
|
45
|
+
IconPlusOutline16,
|
|
46
|
+
IconRefreshOutline16,
|
|
47
|
+
IconTrashOutline16,
|
|
48
|
+
IconEditOutline16,
|
|
49
|
+
IconPlayOutline16,
|
|
50
|
+
IconStopFill16,
|
|
51
|
+
Menu,
|
|
52
|
+
Modal,
|
|
53
|
+
Toast,
|
|
54
|
+
Tooltip,
|
|
159
55
|
} = require('@deepseek-ai/dsh-client-ui-primitives')
|
|
160
56
|
const module = { exports: {} }
|
|
161
57
|
const h = React.createElement
|
|
58
|
+
const TypeScriptEditor = createTypeScriptEditor(React)
|
|
162
59
|
|
|
163
|
-
function
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
style.textContent = CLIENT_CSS
|
|
168
|
-
document.head.append(style)
|
|
169
|
-
return () => style.remove()
|
|
60
|
+
function IconButton({ icon: Icon, label, ...props }) {
|
|
61
|
+
const button = h('button', { ...props, type: 'button', className: 'ptcPlusIconButton',
|
|
62
|
+
'aria-label': label, title: label }, typeof Icon === 'function' ? h(Icon, { size: 16 }) : label)
|
|
63
|
+
return typeof Tooltip === 'function' ? h(Tooltip, { label, delayMs: 400 }, button) : button
|
|
170
64
|
}
|
|
171
65
|
|
|
172
|
-
function
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
onChange: event => onChange(field, event.target.checked),
|
|
66
|
+
function ActionButton({ className = '', 'data-kind': kind, ...props }) {
|
|
67
|
+
return typeof Button === 'function'
|
|
68
|
+
? h(Button, {
|
|
69
|
+
...props, size: 'sm', variant: kind === 'primary' ? 'primary' : kind === 'ghost' ? 'ghost' : 'outline',
|
|
70
|
+
className: className.split(' ').filter(name => name !== 'ptcPlusButton').join(' '),
|
|
178
71
|
})
|
|
179
|
-
|
|
180
|
-
return h('input', {
|
|
181
|
-
type: 'number', className: 'ptcPlusInput',
|
|
182
|
-
value: Number.isSafeInteger(value) ? String(value) : '',
|
|
183
|
-
min: field.min, max: field.max, step: 1, disabled, 'aria-label': label,
|
|
184
|
-
onChange: event => {
|
|
185
|
-
const input = event.target.value
|
|
186
|
-
const parsed = input === '' ? '' : Number(input)
|
|
187
|
-
onChange(field, Number.isSafeInteger(parsed) ? parsed : input)
|
|
188
|
-
},
|
|
189
|
-
})
|
|
72
|
+
: h('button', { ...props, className, 'data-kind': kind })
|
|
190
73
|
}
|
|
191
74
|
|
|
192
|
-
|
|
75
|
+
const BindingConsole = createBindingConsole(React, { TypeScriptEditor, IconButton, ActionButton,
|
|
76
|
+
icons: { play: IconPlayOutline16, stop: IconStopFill16, reset: IconRefreshOutline16, clear: IconTrashOutline16 } })
|
|
77
|
+
const { PTCPlusToolRow } = createPtcToolView(React, {
|
|
78
|
+
CodeBlock, DisclosureRow,
|
|
79
|
+
icons: { chevron: IconChevronDownOutline14, check: IconCheckOutline14, inspect: IconInspectOutline12 },
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
async function apply(ctx) {
|
|
83
|
+
const rpc = await createClientRpc(ctx)
|
|
193
84
|
const preferenceScope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE })
|
|
194
85
|
ctx.effect(() => ctx.locale.register(LOCALE_NS, SETTINGS_COPY), 'ptc-plus: settings dictionaries')
|
|
195
86
|
ctx.effect(installStyles, 'ptc-plus: client styles')
|
|
196
87
|
|
|
197
|
-
function
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const [pending, setPending] = React.useState(() => new Set())
|
|
201
|
-
const writeTail = React.useRef(Promise.resolve())
|
|
202
|
-
const subscribe = React.useCallback(listener => preferenceScope.subscribe(listener), [])
|
|
203
|
-
const getSnapshot = React.useCallback(() => preferenceScope.getSnapshot(), [])
|
|
204
|
-
const snapshot = React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot)
|
|
205
|
-
const value = snapshot.status === 'ready' ? (snapshot.value ?? {}) : {}
|
|
206
|
-
const enabled = value.enabled === true
|
|
207
|
-
const unavailable = snapshot.status !== 'ready' || snapshot.writable !== true
|
|
208
|
-
const persist = (field, nextValue) => {
|
|
209
|
-
if (unavailable || pending.has(field.key)) return
|
|
210
|
-
const operation = writeTail.current.then(async () => {
|
|
211
|
-
const before = preferenceScope.getSnapshot()
|
|
212
|
-
if (before.status !== 'ready' || before.writable !== true) return
|
|
213
|
-
if (field.key !== 'enabled' && before.value?.enabled !== true) return
|
|
214
|
-
if (before.value?.[field.key] === nextValue) return
|
|
215
|
-
setPending(current => new Set(current).add(field.key))
|
|
216
|
-
setStatus(null)
|
|
217
|
-
try {
|
|
218
|
-
await preferenceScope.set(field.key, nextValue)
|
|
219
|
-
const after = preferenceScope.getSnapshot()
|
|
220
|
-
if (after.status !== 'ready' || after.value?.[field.key] !== nextValue) {
|
|
221
|
-
setStatus({ key: 'status.conflict' })
|
|
222
|
-
} else {
|
|
223
|
-
setStatus({ key: 'status.applied' })
|
|
224
|
-
}
|
|
225
|
-
} catch (error) {
|
|
226
|
-
setStatus({
|
|
227
|
-
key: 'status.failed',
|
|
228
|
-
params: { error: error instanceof Error ? error.message : String(error) },
|
|
229
|
-
})
|
|
230
|
-
} finally {
|
|
231
|
-
setPending(current => {
|
|
232
|
-
const next = new Set(current)
|
|
233
|
-
next.delete(field.key)
|
|
234
|
-
return next
|
|
235
|
-
})
|
|
236
|
-
}
|
|
237
|
-
})
|
|
238
|
-
writeTail.current = operation.catch(() => {})
|
|
88
|
+
async function callUserBindings(endpoint, payload = {}, signal = undefined) {
|
|
89
|
+
if (!featureEnabled(preferenceScope.getSnapshot(), 'bindings')) {
|
|
90
|
+
throw new Error('Global User Bindings are disabled')
|
|
239
91
|
}
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
className: 'ptcPlusGroup',
|
|
246
|
-
'aria-labelledby': `ptc-plus-settings-group-${group.key}`,
|
|
247
|
-
},
|
|
248
|
-
h('h3', {
|
|
249
|
-
id: `ptc-plus-settings-group-${group.key}`,
|
|
250
|
-
className: 'ptcPlusGroupTitle',
|
|
251
|
-
}, t(`group.${group.key}`)),
|
|
252
|
-
...group.fields.map(key => {
|
|
253
|
-
const field = CONFIG_FIELDS.find(candidate => candidate.key === key)
|
|
254
|
-
if (field === undefined) return null
|
|
255
|
-
return h('div', { key: field.key, className: 'ptcPlusRow' },
|
|
256
|
-
h('div', { className: 'ptcPlusMain' },
|
|
257
|
-
h('div', { className: 'ptcPlusLabel' }, t(`${field.key}.label`)),
|
|
258
|
-
field.description === '' ? null : h('div', { className: 'ptcPlusDetail' }, t(`${field.key}.description`))),
|
|
259
|
-
fieldInput(field, value[field.key], fieldDisabled(field), persist, t(`${field.key}.label`)))
|
|
260
|
-
})))
|
|
261
|
-
return h('li', { className: 'ptcPlusCard' },
|
|
262
|
-
h('button', {
|
|
263
|
-
type: 'button', className: 'ptcPlusHeader', 'aria-expanded': open,
|
|
264
|
-
'aria-label': t(open ? 'action.collapse' : 'action.expand'),
|
|
265
|
-
'aria-controls': 'ptc-plus-settings-body', onClick: () => setOpen(current => !current),
|
|
266
|
-
},
|
|
267
|
-
h('span', { className: 'ptcPlusHeadText' },
|
|
268
|
-
h('span', { className: 'ptcPlusName' }, 'PTC Plus'),
|
|
269
|
-
h('span', { className: 'ptcPlusDescription' }, t('card.description'))),
|
|
270
|
-
h('span', { className: 'ptcPlusStatus', 'data-enabled': enabled }, t(enabled ? 'status.enabled' : 'status.disabled')),
|
|
271
|
-
h('span', { className: 'ptcPlusChevron', 'data-open': open, 'aria-hidden': true }, h(IconChevronDownOutline14, { size: 14 }))),
|
|
272
|
-
h('div', { id: 'ptc-plus-settings-body', className: 'ptcPlusBody', 'data-open': open, 'aria-hidden': !open },
|
|
273
|
-
h('div', { className: 'ptcPlusBodyInner' }, h('div', { className: 'ptcPlusFields' },
|
|
274
|
-
snapshot.status === 'loading'
|
|
275
|
-
? h('p', { className: 'ptcPlusMessage' }, t('state.syncing'))
|
|
276
|
-
: snapshot.status === 'unavailable'
|
|
277
|
-
? h('p', { className: 'ptcPlusMessage' }, t('state.unavailable'))
|
|
278
|
-
: [
|
|
279
|
-
...settingGroups,
|
|
280
|
-
h('div', { key: 'footer', className: 'ptcPlusFooter' },
|
|
281
|
-
h('span', { className: 'ptcPlusMessage', role: 'status' }, status === null
|
|
282
|
-
? t(snapshot.writable ? 'footer.live' : 'footer.readOnly')
|
|
283
|
-
: t(status.key, status.params))),
|
|
284
|
-
]))),
|
|
92
|
+
const result = await rpc.call(
|
|
93
|
+
RPC_CONTRACTS.bindings,
|
|
94
|
+
endpoint,
|
|
95
|
+
payload,
|
|
96
|
+
signal,
|
|
285
97
|
)
|
|
98
|
+
if (result?.ok === true) return result.value
|
|
99
|
+
const error = new Error(result?.error?.message ?? 'Global User Binding request failed')
|
|
100
|
+
if (typeof result?.error?.code === 'string') error.code = result.error.code
|
|
101
|
+
throw error
|
|
286
102
|
}
|
|
287
103
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
},
|
|
104
|
+
const catalogOwner = createCatalogOwner({ callUserBindings })
|
|
105
|
+
ctx.effect(() => () => catalogOwner.dispose(), 'ptc-plus: binding catalog sources')
|
|
106
|
+
const { useWorkbenchController, UserBindingsWorkbench, BindingsDialog } = createUserBindingsWorkbench(React, {
|
|
107
|
+
TypeScriptEditor, BindingConsole, IconButton, ActionButton, CodeBlock, Modal,
|
|
108
|
+
catalogOwner,
|
|
109
|
+
icons: {
|
|
110
|
+
refresh: IconRefreshOutline16, plus: IconPlusOutline16, check: IconCheckOutline14,
|
|
111
|
+
trash: IconTrashOutline16, edit: IconEditOutline16, search: IconSearchOutline16,
|
|
112
|
+
chevron: IconChevronDownOutline14, close: IconCloseOutline16,
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
const { observeRepl } = createReplObserver({ rpc, ctx })
|
|
116
|
+
const { PTCPlusSettingsCard, PTCPlusSettingsDialog } = createPtcSettingsView(React, {
|
|
117
|
+
ActionButton, BindingsDialog, Modal, useWorkbenchController,
|
|
118
|
+
icons: { chevron: IconChevronDownOutline14 },
|
|
119
|
+
})
|
|
120
|
+
const { ReplComposer, ReplConsole, ReplMemoryCard, replPopoverIsOpen, placeReplPopover } = createReplView(React, {
|
|
121
|
+
CodeBlock, featureEnabled, normalizeReplMemorySnapshot, unavailableReplMemorySnapshot,
|
|
122
|
+
useSessionPreset, sessionUsesPtcPreset, useWorkbenchController, UserBindingsWorkbench,
|
|
123
|
+
icons: { search: IconSearchOutline16, chevron: IconChevronDownOutline14 },
|
|
124
|
+
})
|
|
291
125
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
const summaryText = summary === '' ? null : summary
|
|
311
|
-
const summaryLine = stateText === null && summaryText === null ? null
|
|
312
|
-
: h('div', { className: 'ptcPlusToolSummaryLine', 'data-state': view.state, role: 'status' },
|
|
313
|
-
stateText === null ? null : h('span', { className: 'ptcPlusToolState' }, stateText),
|
|
314
|
-
summaryText === null ? null : h('span', { className: 'ptcPlusToolSep', 'aria-hidden': true }),
|
|
315
|
-
summaryText === null ? null : h('span', { className: 'ptcPlusToolDescription' }, summaryText))
|
|
316
|
-
const body = !open ? null : h('div', { className: 'ptcPlusToolBody' },
|
|
317
|
-
view.code === '' ? null : h('div', { className: 'ptcPlusToolSection' },
|
|
318
|
-
h('span', { className: 'ptcPlusToolSectionLabel' }, t('tool.source')),
|
|
319
|
-
typeof CodeBlock === 'function'
|
|
320
|
-
? h(CodeBlock, {
|
|
321
|
-
code: view.code, lang: 'typescript', className: 'ptcPlusToolCode',
|
|
322
|
-
copyLabel: t('tool.copy'), copiedLabel: t('tool.copied'),
|
|
323
|
-
})
|
|
324
|
-
: h('pre', { className: 'ptcPlusToolCode' }, view.code)),
|
|
325
|
-
view.output === '' ? null : h('div', { className: 'ptcPlusToolSection' },
|
|
326
|
-
h('span', { className: 'ptcPlusToolSectionLabel' }, t('tool.result')),
|
|
327
|
-
h('div', { className: 'ptcPlusIoCard' },
|
|
328
|
-
h('pre', {
|
|
329
|
-
className: 'ptcPlusIoText',
|
|
330
|
-
'data-error': view.state === 'error' || undefined,
|
|
331
|
-
}, view.output))),
|
|
332
|
-
typeof inspect !== 'function' ? null : h('button', {
|
|
333
|
-
type: 'button', className: 'ptcPlusInspect', onClick: inspect,
|
|
334
|
-
}, h(IconInspectOutline12, { 'aria-hidden': true }), t('tool.inspect')))
|
|
335
|
-
const features = view.features.length === 0 ? null : h('div', { className: 'ptcPlusFeatures' },
|
|
336
|
-
view.features.map(feature => h('span', {
|
|
337
|
-
key: `${feature.key}:${feature.detail}`, className: 'ptcPlusFeature',
|
|
338
|
-
},
|
|
339
|
-
h('span', { className: 'ptcPlusFeatureName' }, t(feature.key)),
|
|
340
|
-
feature.detail === '' ? null
|
|
341
|
-
: h('span', { className: 'ptcPlusFeatureDetail', title: feature.detail }, feature.detail))))
|
|
342
|
-
const collapsedContent = h('div', { className: 'ptcPlusToolPreview' }, summaryLine, features)
|
|
343
|
-
if (typeof DisclosureRow === 'function') {
|
|
344
|
-
return h('div', { className: 'ptcPlusTool' },
|
|
345
|
-
h(DisclosureRow, {
|
|
346
|
-
icon: expandable
|
|
347
|
-
? h(IconChevronDownOutline14, { size: 14 })
|
|
348
|
-
: h(IconCheckOutline14, { size: 14 }),
|
|
349
|
-
title: t(toolName === 'edit_run_code' ? 'tool.codeEdit' : 'tool.code'),
|
|
350
|
-
open,
|
|
351
|
-
expandable,
|
|
352
|
-
onToggle: toggle,
|
|
353
|
-
expandOnRowClick: true,
|
|
354
|
-
previewChevron: false,
|
|
355
|
-
keepContentWhenOpen: true,
|
|
356
|
-
collapsedContent,
|
|
357
|
-
children: body,
|
|
358
|
-
}))
|
|
359
|
-
}
|
|
360
|
-
return h('div', { className: 'ptcPlusTool' },
|
|
361
|
-
h('div', {
|
|
362
|
-
className: 'ptcPlusToolSummary', 'data-state': view.state,
|
|
363
|
-
'data-expandable': expandable || undefined,
|
|
364
|
-
role: expandable ? 'button' : undefined,
|
|
365
|
-
tabIndex: expandable ? 0 : undefined,
|
|
366
|
-
'aria-expanded': expandable ? open : undefined,
|
|
367
|
-
onClick: expandable ? toggle : undefined,
|
|
368
|
-
onKeyDown: expandable ? (event) => {
|
|
369
|
-
if (event.key !== 'Enter' && event.key !== ' ') return
|
|
370
|
-
event.preventDefault()
|
|
371
|
-
toggle()
|
|
372
|
-
} : undefined,
|
|
373
|
-
},
|
|
374
|
-
h('span', { className: 'ptcPlusToolLeading', 'aria-hidden': true }, expandable
|
|
375
|
-
? h(IconChevronDownOutline14, { size: 14, className: 'ptcPlusToolChevron', 'data-open': open })
|
|
376
|
-
: h(IconCheckOutline14, { size: 14 })),
|
|
377
|
-
h('span', { className: 'ptcPlusToolTitle' }, t(
|
|
378
|
-
toolName === 'edit_run_code' ? 'tool.codeEdit' : 'tool.code')),
|
|
379
|
-
view.state === 'ok' ? null
|
|
380
|
-
: h('span', { className: 'ptcPlusToolState', role: 'status' }, t(stateKey)),
|
|
381
|
-
h('span', { className: 'ptcPlusToolSep', 'aria-hidden': true }),
|
|
382
|
-
h('span', { className: 'ptcPlusToolDescription' }, summary)),
|
|
383
|
-
features,
|
|
384
|
-
body)
|
|
126
|
+
const settingsProps = () => ({ hooks: { ptcSettings: preferenceScope }, callUserBindings })
|
|
127
|
+
const updateSetting = async (key, value) => {
|
|
128
|
+
const before = preferenceScope.getSnapshot()
|
|
129
|
+
if (before.status !== 'ready' || before.writable !== true
|
|
130
|
+
|| (key !== 'enabled' && !featureEnabled(before, 'plugin'))
|
|
131
|
+
|| (before.value?.[key] === value
|
|
132
|
+
&& !(key === 'bindingUpdates' && before.value.legacyBindingSettings === true))) return null
|
|
133
|
+
if (key === 'bindingUpdates') {
|
|
134
|
+
await preferenceScope.mutate([
|
|
135
|
+
{ op: 'set', path: ['bindingUpdates'], value },
|
|
136
|
+
{ op: 'set', path: ['legacyBindingSettings'], value: false },
|
|
137
|
+
])
|
|
138
|
+
} else await preferenceScope.set(key, value)
|
|
139
|
+
const after = preferenceScope.getSnapshot()
|
|
140
|
+
return after.status === 'ready' && after.value?.[key] === value
|
|
141
|
+
&& (key !== 'bindingUpdates' || after.value.legacyBindingSettings !== true)
|
|
142
|
+
? 'status.applied' : 'status.conflict'
|
|
385
143
|
}
|
|
144
|
+
// One gated-registration shape for every settings-driven contribution.
|
|
145
|
+
const settingsGate = (feature, register) => ({
|
|
146
|
+
subscribe: listener => preferenceScope.subscribe(listener),
|
|
147
|
+
isEnabled: () => featureEnabled(preferenceScope.getSnapshot(), feature),
|
|
148
|
+
register,
|
|
149
|
+
})
|
|
386
150
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const enabled = snapshot.status === 'ready'
|
|
396
|
-
&& snapshot.value?.enabled === true
|
|
397
|
-
&& snapshot.value?.enhancedToolView !== false
|
|
398
|
-
if (enabled === (releaseRows !== undefined)) return
|
|
399
|
-
release()
|
|
400
|
-
if (!enabled) return
|
|
401
|
-
const disposers = []
|
|
402
|
-
try {
|
|
403
|
-
disposers.push(ctx.slots.register({
|
|
404
|
-
name: 'tool.call.toolview', key: 'run_code', locale: LOCALE_NS,
|
|
405
|
-
}, PTCPlusToolRow))
|
|
406
|
-
disposers.push(ctx.slots.register({
|
|
407
|
-
name: 'tool.call.toolview', key: 'edit_run_code', locale: LOCALE_NS,
|
|
408
|
-
}, PTCPlusToolRow))
|
|
409
|
-
} catch (error) {
|
|
410
|
-
disposers.reverse().forEach(dispose => dispose())
|
|
411
|
-
throw error
|
|
412
|
-
}
|
|
413
|
-
releaseRows = () => disposers.reverse().forEach(dispose => dispose())
|
|
414
|
-
}
|
|
415
|
-
sync()
|
|
416
|
-
const unsubscribe = preferenceScope.subscribe(sync)
|
|
417
|
-
return () => {
|
|
418
|
-
unsubscribe()
|
|
419
|
-
release()
|
|
420
|
-
}
|
|
151
|
+
// The settings card's seat differs by DSH generation; the compat module
|
|
152
|
+
// owns both contracts and why one publication serves them. The composer
|
|
153
|
+
// entry points at whichever seat the installed generation declared.
|
|
154
|
+
const settingsCard = publishSettingsCard(ctx, {
|
|
155
|
+
bundleName: __PTC_PLUS_CLIENT_MODULE_ID__,
|
|
156
|
+
locale: LOCALE_NS,
|
|
157
|
+
injectProps: () => ({ ...settingsProps(), updateSetting }),
|
|
158
|
+
component: PTCPlusSettingsCard,
|
|
421
159
|
})
|
|
422
160
|
|
|
423
|
-
ctx.inject(
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
161
|
+
ctx.slots.inject('tool.call.toolview', () => registerGated(ctx, settingsGate('toolView', () => {
|
|
162
|
+
// Two rows share one eligibility decision; roll both back if either fails.
|
|
163
|
+
const disposers = []
|
|
164
|
+
try {
|
|
165
|
+
disposers.push(ctx.slots.register({
|
|
166
|
+
name: 'tool.call.toolview', key: 'run_code', locale: LOCALE_NS,
|
|
167
|
+
}, PTCPlusToolRow))
|
|
168
|
+
disposers.push(ctx.slots.register({
|
|
169
|
+
name: 'tool.call.toolview', key: 'edit_run_code', locale: LOCALE_NS,
|
|
170
|
+
}, PTCPlusToolRow))
|
|
171
|
+
} catch (error) {
|
|
172
|
+
disposers.reverse().forEach(dispose => dispose())
|
|
173
|
+
throw error
|
|
431
174
|
}
|
|
175
|
+
return () => disposers.reverse().forEach(dispose => dispose())
|
|
176
|
+
})))
|
|
432
177
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
:
|
|
455
|
-
|
|
178
|
+
ctx.inject(['sessions'], (viewScope) => {
|
|
179
|
+
const hideComposer = sessionId => viewScope.effect(() => viewScope.slots.inject(
|
|
180
|
+
'conversation.composer', () => viewScope.slots.register({
|
|
181
|
+
name: 'conversation.composer', priority: 100,
|
|
182
|
+
select: owner => isIdleSessionComposer(owner, sessionId) ? true : null,
|
|
183
|
+
}, ReplComposer),
|
|
184
|
+
))
|
|
185
|
+
viewScope.slots.inject('conversation.view', () => {
|
|
186
|
+
// The REPL tab needs both the settings gate and the session preset.
|
|
187
|
+
let preset
|
|
188
|
+
return registerGated(viewScope, {
|
|
189
|
+
subscribe: listener => {
|
|
190
|
+
const unsubscribePreset = watchCurrentSessionPreset(viewScope.sessions, value => {
|
|
191
|
+
preset = value
|
|
192
|
+
listener()
|
|
193
|
+
})
|
|
194
|
+
const unsubscribeSettings = preferenceScope.subscribe(listener)
|
|
195
|
+
return () => { unsubscribePreset(); unsubscribeSettings() }
|
|
196
|
+
},
|
|
197
|
+
isEnabled: () => featureEnabled(preferenceScope.getSnapshot(), 'replView')
|
|
198
|
+
&& sessionUsesPtcPreset(preset),
|
|
199
|
+
register: () => viewScope.slots.register({
|
|
200
|
+
name: 'conversation.view', id: 'ptc-plus-repl', label: 'REPL', order: 20,
|
|
201
|
+
locale: LOCALE_NS, inject: () => ({ ...settingsProps(), hideComposer, observeRepl }),
|
|
202
|
+
}, props => typeof props.useProjection === 'function' ? h(ReplConsole, props) : null),
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
})
|
|
456
206
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
className: 'ptcPlusReplPopover', id, ref: popoverRef, popover: 'auto',
|
|
461
|
-
role: 'dialog', 'aria-labelledby': titleId,
|
|
462
|
-
onPointerEnter: onEnter, onPointerLeave: onLeave,
|
|
463
|
-
},
|
|
464
|
-
h('div', { className: 'ptcPlusReplCard' },
|
|
465
|
-
h('div', { className: 'ptcPlusReplHead' },
|
|
466
|
-
h('span', { className: 'ptcPlusReplStatusDot', 'aria-hidden': true }),
|
|
467
|
-
h('span', { className: 'ptcPlusReplTitle', id: titleId }, t('memory.title')),
|
|
468
|
-
memory.available
|
|
469
|
-
? h('span', { className: 'ptcPlusReplSummary' }, t('memory.count', { count: memory.total }))
|
|
470
|
-
: null),
|
|
471
|
-
!memory.available
|
|
472
|
-
? h('span', { className: 'ptcPlusReplEmpty' }, t('memory.unavailable'))
|
|
473
|
-
: memory.entries.length === 0
|
|
474
|
-
? h('span', { className: 'ptcPlusReplEmpty' }, t('memory.empty'))
|
|
475
|
-
: h('ul', { className: 'ptcPlusReplList' }, memory.entries.map((binding, index) => {
|
|
476
|
-
const expanded = expandedBinding === binding.name
|
|
477
|
-
const preview = binding.definition.source.replace(/\s+/g, ' ').trim()
|
|
478
|
-
const definitionId = `${id}-binding-${index}`
|
|
479
|
-
const toggle = () => setExpandedBinding(current => (
|
|
480
|
-
current === binding.name ? null : binding.name
|
|
481
|
-
))
|
|
482
|
-
return h('li', {
|
|
483
|
-
className: 'ptcPlusReplBinding', key: binding.name,
|
|
484
|
-
'data-expanded': expanded,
|
|
485
|
-
},
|
|
486
|
-
h('button', {
|
|
487
|
-
className: 'ptcPlusReplBindingTrigger', type: 'button',
|
|
488
|
-
'aria-expanded': expanded,
|
|
489
|
-
'aria-controls': expanded ? definitionId : undefined,
|
|
490
|
-
onClick: toggle,
|
|
491
|
-
},
|
|
492
|
-
h('span', {
|
|
493
|
-
className: 'ptcPlusReplName', 'data-kind': binding.kind,
|
|
494
|
-
title: `${binding.name} - ${t(`memory.kind.${binding.kind}`)}`,
|
|
495
|
-
}, binding.name),
|
|
496
|
-
h('span', { className: 'ptcPlusReplPreview', title: preview }, preview),
|
|
497
|
-
h('span', {
|
|
498
|
-
className: 'ptcPlusReplChevron', 'data-open': expanded, 'aria-hidden': true,
|
|
499
|
-
}, h(IconChevronDownOutline14, { size: 14 }))),
|
|
500
|
-
expanded
|
|
501
|
-
? h('div', {
|
|
502
|
-
className: 'ptcPlusReplDefinitionWrap', 'data-open': true,
|
|
503
|
-
id: definitionId, role: 'region', 'aria-label': binding.name,
|
|
504
|
-
}, h('div', { className: 'ptcPlusReplDefinitionInner' },
|
|
505
|
-
h('div', { className: 'ptcPlusReplDefinition' },
|
|
506
|
-
h('span', { className: 'ptcPlusReplLocation' }, t('memory.location', {
|
|
507
|
-
line: binding.definition.line,
|
|
508
|
-
column: binding.definition.column,
|
|
509
|
-
})),
|
|
510
|
-
typeof CodeBlock === 'function'
|
|
511
|
-
? h(CodeBlock, {
|
|
512
|
-
code: binding.definition.source,
|
|
513
|
-
lang: 'typescript',
|
|
514
|
-
className: 'ptcPlusReplCode',
|
|
515
|
-
copyLabel: t('tool.copy'),
|
|
516
|
-
copiedLabel: t('tool.copied'),
|
|
517
|
-
})
|
|
518
|
-
: h('pre', { className: 'ptcPlusReplCode' }, binding.definition.source))))
|
|
519
|
-
: null)
|
|
520
|
-
})),
|
|
521
|
-
memory.omitted === 0 ? null
|
|
522
|
-
: h('span', { className: 'ptcPlusReplMore' }, t('memory.more', { count: memory.omitted }))))
|
|
523
|
-
}
|
|
207
|
+
const bindingReviews = createBindingReviews(callUserBindings)
|
|
208
|
+
ctx.effect(() => () => bindingReviews.dispose())
|
|
209
|
+
ctx.on('connection/reset', () => bindingReviews.reset())
|
|
524
210
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
)
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
popover.style.visibility = 'visible'
|
|
587
|
-
setExpanded(true)
|
|
588
|
-
}, [])
|
|
589
|
-
const hidePopover = React.useCallback(() => {
|
|
590
|
-
const popover = popoverRef.current
|
|
591
|
-
if (popover === null) return
|
|
592
|
-
if (popover.dataset.open === 'true') delete popover.dataset.open
|
|
593
|
-
if (typeof popover.hidePopover === 'function' && replPopoverIsOpen(popover)) {
|
|
594
|
-
try { popover.hidePopover() } catch {}
|
|
595
|
-
}
|
|
596
|
-
setExpanded(false)
|
|
597
|
-
}, [])
|
|
598
|
-
const scheduleHide = React.useCallback(() => {
|
|
599
|
-
if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)
|
|
600
|
-
closeTimer.current = setTimeout(() => {
|
|
601
|
-
closeTimer.current = undefined
|
|
602
|
-
if (document.activeElement === triggerRef.current
|
|
603
|
-
|| popoverRef.current?.contains(document.activeElement)) return
|
|
604
|
-
hidePopover()
|
|
605
|
-
}, 120)
|
|
606
|
-
}, [hidePopover])
|
|
607
|
-
React.useEffect(() => {
|
|
608
|
-
const syncPopoverState = (event) => {
|
|
609
|
-
if (event.target !== popoverRef.current) return
|
|
610
|
-
setExpanded(replPopoverIsOpen(popoverRef.current))
|
|
611
|
-
}
|
|
612
|
-
window.addEventListener('resize', positionPopover)
|
|
613
|
-
document.addEventListener('scroll', positionPopover, true)
|
|
614
|
-
document.addEventListener('toggle', syncPopoverState, true)
|
|
615
|
-
return () => {
|
|
616
|
-
if (closeTimer.current !== undefined) clearTimeout(closeTimer.current)
|
|
617
|
-
window.removeEventListener('resize', positionPopover)
|
|
618
|
-
document.removeEventListener('scroll', positionPopover, true)
|
|
619
|
-
document.removeEventListener('toggle', syncPopoverState, true)
|
|
620
|
-
const popover = popoverRef.current
|
|
621
|
-
if (popover?.dataset?.open === 'true') delete popover.dataset.open
|
|
622
|
-
if (typeof popover?.hidePopover === 'function' && replPopoverIsOpen(popover)) {
|
|
623
|
-
try { popover.hidePopover() } catch {}
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
}, [hidePopover, positionPopover])
|
|
627
|
-
const resolvedSessionId = sessionId ?? conversation?.sessionId
|
|
628
|
-
const session = sessions?.byId?.[resolvedSessionId] ?? conversation
|
|
629
|
-
if (!sessionUsesPtcPreset(session)
|
|
630
|
-
|| settings.status !== 'ready' || settings.value?.enabled !== true) return null
|
|
631
|
-
let memory
|
|
632
|
-
try {
|
|
633
|
-
memory = normalizeReplMemorySnapshot(projectionMemory
|
|
634
|
-
?? session?.projectionValues?.ptcPlusRepl)
|
|
635
|
-
} catch {
|
|
636
|
-
memory = unavailableReplMemorySnapshot()
|
|
637
|
-
}
|
|
638
|
-
const popoverId = `ptc-plus-repl-${String(resolvedSessionId).replace(/[^A-Za-z0-9_-]/g, '-')}`
|
|
639
|
-
const titleId = `${popoverId}-title`
|
|
640
|
-
return h('span', { className: 'ptcPlusActiveShell' },
|
|
641
|
-
h('button', {
|
|
642
|
-
type: 'button', className: 'ptcPlusActive', ref: triggerRef,
|
|
643
|
-
'aria-label': t('indicator.title'), 'aria-controls': popoverId,
|
|
644
|
-
'aria-expanded': expanded, 'aria-haspopup': 'dialog',
|
|
645
|
-
onPointerEnter: showPopover, onPointerLeave: scheduleHide,
|
|
646
|
-
onFocus: showPopover, onBlur: scheduleHide, onClick: showPopover,
|
|
647
|
-
onKeyDown: event => { if (event.key === 'Escape') hidePopover() },
|
|
648
|
-
}, h('span', { className: 'ptcPlusActiveLabel' }, 'PTC Plus')),
|
|
649
|
-
h(ReplMemoryCard, {
|
|
650
|
-
memory, t, id: popoverId, titleId, popoverRef,
|
|
651
|
-
onEnter: showPopover, onLeave: scheduleHide,
|
|
652
|
-
}))
|
|
653
|
-
}
|
|
654
|
-
scope.slots.inject('conversation.session.header.actions', () => scope.slots.register({
|
|
655
|
-
name: 'conversation.session.header.actions', id: 'ptc-plus-active', order: -9, locale: LOCALE_NS,
|
|
656
|
-
}, PTCPlusSessionIndicator))
|
|
211
|
+
function useBindingReview(sessionId) {
|
|
212
|
+
const review = bindingReviews.forSession(sessionId)
|
|
213
|
+
const view = React.useSyncExternalStore(review.subscribe, review.getSnapshot)
|
|
214
|
+
return [review, view]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const subscribeReset = listener => ctx.on('connection/reset', listener)
|
|
218
|
+
const { BindingAuthorButton, BindingReviewDock, BindingCommandCard } = createAuthoringView(React, {
|
|
219
|
+
ActionButton, IconButton, Menu, Toast, Tooltip, CodeBlock, BindingsDialog, PTCPlusSettingsDialog,
|
|
220
|
+
useWorkbenchController, useBindingReview, catalogOwner, callUserBindings, subscribeReset,
|
|
221
|
+
settingsCardSeat: settingsCard.seat, updateSetting,
|
|
222
|
+
icons: {
|
|
223
|
+
sparkle: IconSparkle16, chevron: IconChevronDownOutline14,
|
|
224
|
+
close: IconCloseOutline16, check: IconCheckOutline14,
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
const { PTCPlusSessionIndicator } = createIndicatorView(React, {
|
|
228
|
+
featureEnabled, useSessionPreset, sessionUsesPtcPreset,
|
|
229
|
+
normalizeReplMemorySnapshot, unavailableReplMemorySnapshot,
|
|
230
|
+
ReplMemoryCard, replPopoverIsOpen, placeReplPopover,
|
|
231
|
+
catalogOwner, subscribeReset,
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
ctx.slots.inject('conversation.session.header.actions', () => registerGated(ctx, settingsGate('plugin', () => ctx.slots.register({
|
|
235
|
+
name: 'conversation.session.header.actions', id: 'ptc-plus-active', order: -9, locale: LOCALE_NS,
|
|
236
|
+
inject: settingsProps,
|
|
237
|
+
}, props => typeof props.useProjection === 'function' ? h(PTCPlusSessionIndicator, props) : null))))
|
|
238
|
+
ctx.slots.inject('conversation.chat.commandview', () => registerGated(ctx, settingsGate('bindings', () => ctx.slots.register({
|
|
239
|
+
name: 'conversation.chat.commandview', key: 'binding', locale: LOCALE_NS,
|
|
240
|
+
inject: settingsProps,
|
|
241
|
+
}, props => h(BindingCommandCard, { ...props, key: props.node.commandId })))))
|
|
242
|
+
ctx.slots.inject('conversation.input.dock', () => ctx.slots.inject('conversation.input.left', () =>
|
|
243
|
+
registerGated(ctx, settingsGate('bindings', () => ctx.slots.register({
|
|
244
|
+
name: 'conversation.input.dock', id: 'ptc-plus-binding-review', order: 30, locale: LOCALE_NS,
|
|
245
|
+
}, props => typeof props.useProjection === 'function' && props.sessionId !== undefined
|
|
246
|
+
? h(BindingReviewDock, { ...props, key: props.sessionId }) : null)))))
|
|
247
|
+
const availability = createBindingCommandAvailability(ctx)
|
|
248
|
+
// The composer binding entry belongs to the PTC surface, exactly like the
|
|
249
|
+
// header indicator and the REPL tab. A non-PTC session keeps plugin
|
|
250
|
+
// settings and `/binding` command cards, but shows no binding shortcut and
|
|
251
|
+
// issues no command-directory read for it.
|
|
252
|
+
ctx.inject(['sessions'], (viewScope) => {
|
|
253
|
+
let preset
|
|
254
|
+
viewScope.slots.inject('conversation.input.left', () => registerGated(viewScope, {
|
|
255
|
+
subscribe: listener => {
|
|
256
|
+
const unsubscribePreset = watchCurrentSessionPreset(viewScope.sessions, value => {
|
|
257
|
+
preset = value
|
|
258
|
+
listener()
|
|
259
|
+
})
|
|
260
|
+
const unsubscribeSettings = preferenceScope.subscribe(listener)
|
|
261
|
+
return () => { unsubscribePreset(); unsubscribeSettings() }
|
|
262
|
+
},
|
|
263
|
+
isEnabled: () => sessionUsesPtcPreset(preset)
|
|
264
|
+
&& featureEnabled(preferenceScope.getSnapshot(), 'bindings'),
|
|
265
|
+
register: () => ctx.slots.register({
|
|
266
|
+
name: 'conversation.input.left', id: 'ptc-plus-binding-author', order: 20, locale: LOCALE_NS,
|
|
267
|
+
inject: sessionId => ({
|
|
268
|
+
hooks: { ptcSettings: preferenceScope, bindingCommand: availability.source(sessionId) },
|
|
269
|
+
}),
|
|
270
|
+
}, props => props.sessionId === undefined ? null : h(BindingAuthorButton, { ...props, key: props.sessionId })),
|
|
271
|
+
}))
|
|
657
272
|
})
|
|
658
273
|
}
|
|
659
274
|
|
|
660
|
-
module.exports = {
|
|
275
|
+
module.exports = {
|
|
276
|
+
apply,
|
|
277
|
+
inject: ['settingsScope', 'slots', 'locale', 'connection', 'remote'],
|
|
278
|
+
}
|
|
661
279
|
return module.exports
|
|
662
280
|
},
|
|
663
281
|
})
|