dsh-ptc-plus 0.4.8 → 0.5.0
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 +61 -123
- package/README.md +61 -123
- package/assets/dsh-ptc-plus-banner-en.webp +0 -0
- package/assets/dsh-ptc-plus-banner-zh.webp +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.cjs +42336 -0
- package/cordis.patch.yml +13 -2
- package/docs/README.md +7 -2
- package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +31 -179
- package/docs/adr/0008-define-agent-operating-contract.md +5 -1
- package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -2
- package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
- package/docs/adr/0017-track-the-latest-dsh-public-surface.md +2 -2
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +14 -3
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0022-stage-npm-releases-with-oidc.md +4 -2
- package/docs/adr/0023-global-user-bindings.md +3 -1
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +2 -0
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +101 -35
- package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +3 -3
- package/docs/adr/0031-close-semantic-obligations-by-owner.md +1 -1
- package/docs/adr/0032-own-session-log-facts-in-a-host-only-projection.md +27 -0
- package/docs/adr/0033-gate-client-visual-usability-in-a-browser.md +23 -0
- package/docs/adr/0034-keep-program-values-separate-from-output-projections.md +29 -0
- package/docs/adr/0035-run-coverage-only-before-a-new-release.md +27 -0
- package/docs/adr/0036-separate-focused-development-from-delivery-verification.md +29 -0
- package/docs/adr/0037-keep-tool-hover-previews-passive.md +52 -0
- package/docs/adr/0038-freeze-session-capability-plans.md +71 -0
- package/docs/adr/0039-verify-documentation-without-runtime-suites.md +29 -0
- package/docs/adr/0040-separate-capability-configurations-from-session-observations.md +39 -0
- package/docs/adr/0041-record-cell-execution-directories.md +65 -0
- package/docs/adr/0042-persist-provider-availability-and-handback.md +41 -0
- package/docs/adr/0043-compose-capability-and-context-policies.md +37 -0
- package/docs/adr/README.md +6 -0
- package/docs/architecture.md +25 -27
- package/docs/binding-review-placement-design.md +29 -21
- package/docs/capability-planning-components.md +93 -0
- package/docs/capability-projection.md +7 -0
- package/docs/client-ui.md +88 -29
- package/docs/client-visual-contract.md +65 -0
- package/docs/context-management.md +22 -0
- package/docs/context-optimization-plan.md +353 -0
- package/docs/context-public-interface-coverage.md +25 -0
- package/docs/durability-design.md +31 -14
- package/docs/evaluation.md +41 -6
- package/docs/evaluations/command-goat-deepseek-v4.1-flash-20261006.md +126 -0
- package/docs/evaluations/command-goat-deepseek-v4.1-flash.md +281 -0
- package/docs/installation.md +50 -8
- package/docs/program-data-plane.md +5 -3
- package/docs/publishing.md +5 -5
- package/docs/release-coverage.md +73 -0
- package/docs/release-notes.md +1 -1
- package/docs/review-procedure.md +56 -0
- package/docs/runtime-reference.md +48 -16
- package/docs/semantic-validation.md +14 -2
- package/docs/stateful-binding-updates-proposal.md +2 -2
- package/docs/user-bindings.en.md +2 -2
- package/docs/user-bindings.md +3 -3
- package/docs/value-wire.md +11 -1
- package/docs/verification-optimization-work.md +52 -15
- package/docs/verification.md +30 -86
- package/index.js +147 -23
- package/internal/binding-toggle-receipt.js +24 -0
- package/internal/capability-command-receipt.js +29 -0
- package/internal/capability-environment.js +1247 -0
- package/internal/capability-plan.js +285 -0
- package/internal/capability-policy.js +96 -0
- package/internal/capability-statistics-store.js +180 -0
- package/internal/capability-statistics.js +210 -0
- package/internal/compiler-platform.js +5 -3
- package/internal/compiler-service.js +2 -9
- package/internal/config-spec.js +79 -9
- package/internal/cordis-tools-owner.js +22 -19
- package/internal/direct-surface-owner.js +29 -29
- package/internal/dynamic-environment-runtime.js +9 -9
- package/internal/edit-transport-owner.js +183 -139
- package/internal/execution-provider-owner.js +160 -0
- package/internal/execution-seam-compat.js +76 -120
- package/internal/isolated-worker.js +12 -8
- package/internal/kernel-worker.js +104 -32
- package/internal/native-root-dynamic.js +12 -13
- package/internal/program-bindings.js +190 -0
- package/internal/recovery-tips.js +53 -23
- package/internal/rejected-cell-editor.js +8 -8
- package/internal/repl-observation-interest.js +11 -3
- package/internal/rpc-contract.js +1 -0
- package/internal/runtime-bridge-owner.js +351 -82
- package/internal/runtime-config.js +58 -0
- package/internal/runtime-contexts.js +85 -16
- package/internal/runtime-intrinsics.js +1 -0
- package/internal/runtime-messages.js +41 -0
- package/internal/sdk-projection.js +10 -82
- package/internal/session-cell-executor.js +42 -19
- package/internal/session-events.js +74 -4
- package/internal/session-journal-recovery.js +904 -184
- package/internal/session-journal-schema.js +6 -3
- package/internal/session-journal.js +31 -2
- package/internal/session-log-view.js +189 -43
- package/internal/session-runtime.js +175 -23
- package/internal/settings-compat.js +23 -6
- package/internal/stateful-module-compiler.js +3 -2
- package/internal/stateful-module-runtime.js +7 -3
- package/internal/stateful-root-runtime.js +9 -4
- package/internal/user-binding-authoring.js +2 -7
- package/internal/user-bindings-owner.js +47 -7
- package/internal/validated-parse-repair.js +1 -1
- package/internal/value-wire.js +68 -21
- package/internal/worker-cwd-virtualization.js +20 -18
- package/internal/worker-realm-surfaces.js +3 -3
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +55 -38
- package/src/client-authoring-view.js +286 -168
- package/src/client-binding-review.js +4 -1
- package/src/client-binding-toggle.js +18 -0
- package/src/client-capabilities-view.js +1341 -0
- package/src/client-capability-sort.js +29 -0
- package/src/client-code-editor.js +6 -0
- package/src/client-copy.js +881 -8
- package/src/client-feature-gates.js +15 -5
- package/src/client-host-compat.js +23 -2
- package/src/client-indicator-view.js +4 -6
- package/src/client-primitives.js +280 -0
- package/src/client-repl-view.js +23 -16
- package/src/client-settings-view.js +412 -69
- package/src/client-styles.js +193 -41
- package/src/client-tool-hover.js +185 -0
- package/src/client-tool-view.js +45 -11
- package/src/client-transport.js +44 -9
- package/src/client-workbench.js +9 -10
- package/src/client.js +148 -68
- 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/client.js +0 -31857
package/src/client.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { createClientRpc } from './client-rpc.js'
|
|
2
2
|
import { RPC_CONTRACTS } from '../internal/rpc-contract.js'
|
|
3
|
-
import { SETTINGS_NAMESPACE } from '../internal/config-spec.js'
|
|
3
|
+
import { CONFIG_DEFAULTS, SETTINGS_NAMESPACE } from '../internal/config-spec.js'
|
|
4
4
|
import { createPtcToolView } from './client-tool-view.js'
|
|
5
5
|
import { createPtcSettingsView } from './client-settings-view.js'
|
|
6
|
+
import { createCapabilityCommandCard, createCapabilityRefreshView, createSessionCapabilityControlsView } from './client-capabilities-view.js'
|
|
7
|
+
import { capabilityProfileConfiguration } from '../internal/runtime-config.js'
|
|
6
8
|
import { createReplView } from './client-repl-view.js'
|
|
7
9
|
import { createAuthoringView } from './client-authoring-view.js'
|
|
10
|
+
import { bindingToggleConversationDefinition } from './client-binding-toggle.js'
|
|
8
11
|
import { createIndicatorView } from './client-indicator-view.js'
|
|
9
12
|
import { createTypeScriptEditor } from './client-code-editor.js'
|
|
10
13
|
import { createBindingConsole } from './client-console.js'
|
|
11
14
|
import {
|
|
12
15
|
createMenuChildrenEvidence,
|
|
13
16
|
hostIconComponents,
|
|
17
|
+
isHostComponent,
|
|
14
18
|
isHostIconComponent,
|
|
15
19
|
isIdleSessionComposer,
|
|
16
20
|
publishSettingsCard,
|
|
@@ -28,23 +32,84 @@ import { installStyles } from './client-styles.js'
|
|
|
28
32
|
import { featureEnabled, registerGated } from './client-feature-gates.js'
|
|
29
33
|
import { createCatalogOwner } from './client-catalog.js'
|
|
30
34
|
import { createUserBindingsWorkbench } from './client-workbench.js'
|
|
31
|
-
import { createBindingCommandAvailability, createReplObserver } from './client-transport.js'
|
|
35
|
+
import { createBindingCommandAvailability, createCommandAccess, createReplObserver } from './client-transport.js'
|
|
36
|
+
import { createActionButton, resolvePrimitives } from './client-primitives.js'
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
/** Settings snapshot used until the installed generation serves a transport. */
|
|
39
|
+
const UNAVAILABLE_PREFERENCE = Object.freeze({
|
|
40
|
+
status: 'unavailable',
|
|
41
|
+
writable: false,
|
|
42
|
+
value: CONFIG_DEFAULTS,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the settings preference scope of the running generation without
|
|
47
|
+
* depending on that generation publishing a particular transport name: the
|
|
48
|
+
* current one serves `configForms` and the preceding one served
|
|
49
|
+
* `settingsScope`. The plugin exposes the shipped Config defaults until a
|
|
50
|
+
* transport appears, prefers the current one, and retains live alternatives.
|
|
51
|
+
* A renamed or omitted transport degrades the settings surface instead of
|
|
52
|
+
* suspending apply() before any contribution is registered.
|
|
53
|
+
*/
|
|
54
|
+
function createPreferenceScope(ctx) {
|
|
55
|
+
const listeners = new Set()
|
|
56
|
+
const registrations = new Map()
|
|
57
|
+
let bound
|
|
58
|
+
const notify = () => { for (const listener of [...listeners]) listener() }
|
|
59
|
+
const sync = () => {
|
|
60
|
+
const next = registrations.get('configForms') ?? registrations.get('settingsScope')
|
|
61
|
+
if (bound === next) return
|
|
62
|
+
bound = next
|
|
63
|
+
notify()
|
|
64
|
+
}
|
|
65
|
+
const adopt = (name, scope) => {
|
|
66
|
+
if (scope === undefined || scope === null) return undefined
|
|
67
|
+
const registration = { scope }
|
|
68
|
+
const unsubscribe = typeof scope.subscribe === 'function' ? scope.subscribe(() => {
|
|
69
|
+
if (bound === registration) notify()
|
|
70
|
+
}) : undefined
|
|
71
|
+
registrations.set(name, registration)
|
|
72
|
+
sync()
|
|
73
|
+
return () => {
|
|
74
|
+
unsubscribe?.()
|
|
75
|
+
if (registrations.get(name) !== registration) return
|
|
76
|
+
registrations.delete(name)
|
|
77
|
+
sync()
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
ctx.inject(['configForms'], scope => adopt('configForms', scope.configForms.get(SETTINGS_NAMESPACE)))
|
|
81
|
+
ctx.inject(['settingsScope'], scope => adopt('settingsScope', scope.settingsScope.bind({ namespace: SETTINGS_NAMESPACE })))
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
getSnapshot: () => bound?.scope.getSnapshot() ?? UNAVAILABLE_PREFERENCE,
|
|
84
|
+
subscribe(listener) {
|
|
85
|
+
listeners.add(listener)
|
|
86
|
+
return () => listeners.delete(listener)
|
|
87
|
+
},
|
|
88
|
+
set: (key, value) => bound?.scope.set(key, value),
|
|
89
|
+
mutate: patch => bound?.scope.mutate(patch),
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function createClientPlugin(require) {
|
|
37
94
|
const React = require('react')
|
|
38
|
-
const
|
|
95
|
+
const { createPortal } = require('react-dom')
|
|
96
|
+
let primitives
|
|
97
|
+
try {
|
|
98
|
+
primitives = require('@deepseek-ai/dsh-client-ui-primitives') ?? {}
|
|
99
|
+
} catch {
|
|
100
|
+
primitives = {}
|
|
101
|
+
}
|
|
39
102
|
const {
|
|
40
103
|
Button,
|
|
41
104
|
CodeBlock,
|
|
42
105
|
DisclosureRow,
|
|
43
106
|
Menu,
|
|
107
|
+
MenuFallback,
|
|
44
108
|
Modal,
|
|
109
|
+
Select,
|
|
45
110
|
Toast,
|
|
46
111
|
Tooltip,
|
|
47
|
-
} = primitives
|
|
112
|
+
} = resolvePrimitives(primitives, React, createPortal)
|
|
48
113
|
const {
|
|
49
114
|
check: IconCheckOutline14,
|
|
50
115
|
chevron: IconChevronDownOutline14,
|
|
@@ -59,66 +124,27 @@ window.__ModuleLoader__.load({
|
|
|
59
124
|
play: IconPlayOutline16,
|
|
60
125
|
stop: IconStopFill16,
|
|
61
126
|
} = hostIconComponents(primitives)
|
|
62
|
-
const module = { exports: {} }
|
|
63
127
|
const h = React.createElement
|
|
64
128
|
const TypeScriptEditor = createTypeScriptEditor(React)
|
|
65
129
|
|
|
66
130
|
function IconButton({ icon: Icon, label, ...props }) {
|
|
67
131
|
const button = h('button', { ...props, type: 'button', className: 'ptcPlusIconButton',
|
|
68
132
|
'aria-label': label, title: label }, isHostIconComponent(Icon) ? h(Icon, { size: 16 }) : label)
|
|
69
|
-
return
|
|
133
|
+
return isHostComponent(Tooltip) ? h(Tooltip, { label, delayMs: 400 }, button) : button
|
|
70
134
|
}
|
|
71
135
|
|
|
72
|
-
|
|
73
|
-
return typeof Button === 'function'
|
|
74
|
-
? h(Button, {
|
|
75
|
-
...props, size: 'sm', variant: kind === 'primary' ? 'primary' : kind === 'ghost' ? 'ghost' : 'outline',
|
|
76
|
-
className: className.split(' ').filter(name => name !== 'ptcPlusButton').join(' '),
|
|
77
|
-
})
|
|
78
|
-
: h('button', { ...props, className, 'data-kind': kind })
|
|
79
|
-
}
|
|
136
|
+
const ActionButton = createActionButton(React, Button)
|
|
80
137
|
|
|
81
138
|
const BindingConsole = createBindingConsole(React, { TypeScriptEditor, IconButton, ActionButton,
|
|
82
139
|
icons: { play: IconPlayOutline16, stop: IconStopFill16, reset: IconRefreshOutline16, clear: IconTrashOutline16 } })
|
|
83
140
|
const { PTCPlusToolRow } = createPtcToolView(React, {
|
|
84
|
-
CodeBlock, DisclosureRow,
|
|
141
|
+
CodeBlock, DisclosureRow, createPortal,
|
|
85
142
|
icons: { chevron: IconChevronDownOutline14, check: IconCheckOutline14, inspect: IconInspectOutline12 },
|
|
86
143
|
})
|
|
87
144
|
|
|
88
|
-
/**
|
|
89
|
-
* Resolve the settings transport of the running generation. The current
|
|
90
|
-
* release publishes `configForms`; the preceding one published
|
|
91
|
-
* `settingsScope`. Both are optional child injections so the client entry
|
|
92
|
-
* does not stay pending on the name the installed generation does not use.
|
|
93
|
-
*/
|
|
94
|
-
function settingsPreferenceScope(ctx) {
|
|
95
|
-
return new Promise((resolve, reject) => {
|
|
96
|
-
let settled = false
|
|
97
|
-
let configFormsWatcher
|
|
98
|
-
let settingsScopeWatcher
|
|
99
|
-
const take = (name, scope) => {
|
|
100
|
-
if (settled) return
|
|
101
|
-
settled = true
|
|
102
|
-
if (name !== 'configForms' && typeof configFormsWatcher === 'function') configFormsWatcher()
|
|
103
|
-
if (name !== 'settingsScope' && typeof settingsScopeWatcher === 'function') settingsScopeWatcher()
|
|
104
|
-
resolve(name === 'configForms'
|
|
105
|
-
? scope.configForms.get(SETTINGS_NAMESPACE)
|
|
106
|
-
: scope.settingsScope.bind({ namespace: SETTINGS_NAMESPACE }))
|
|
107
|
-
}
|
|
108
|
-
try {
|
|
109
|
-
configFormsWatcher = ctx.inject(['configForms'], scope => take('configForms', scope))
|
|
110
|
-
if (!settled) {
|
|
111
|
-
settingsScopeWatcher = ctx.inject(['settingsScope'], scope => take('settingsScope', scope))
|
|
112
|
-
}
|
|
113
|
-
} catch (error) {
|
|
114
|
-
reject(error)
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
|
|
119
145
|
async function apply(ctx) {
|
|
120
146
|
const rpc = await createClientRpc(ctx)
|
|
121
|
-
const preferenceScope =
|
|
147
|
+
const preferenceScope = createPreferenceScope(ctx)
|
|
122
148
|
ctx.effect(() => ctx.locale.register(LOCALE_NS, SETTINGS_COPY), 'ptc-plus: settings dictionaries')
|
|
123
149
|
ctx.effect(installStyles, 'ptc-plus: client styles')
|
|
124
150
|
|
|
@@ -141,7 +167,7 @@ window.__ModuleLoader__.load({
|
|
|
141
167
|
const catalogOwner = createCatalogOwner({ callUserBindings })
|
|
142
168
|
ctx.effect(() => () => catalogOwner.dispose(), 'ptc-plus: binding catalog sources')
|
|
143
169
|
const { useWorkbenchController, UserBindingsWorkbench, BindingsDialog } = createUserBindingsWorkbench(React, {
|
|
144
|
-
TypeScriptEditor, BindingConsole, IconButton, ActionButton, CodeBlock, Modal,
|
|
170
|
+
TypeScriptEditor, BindingConsole, IconButton, ActionButton, CodeBlock, Modal, Select,
|
|
145
171
|
catalogOwner,
|
|
146
172
|
icons: {
|
|
147
173
|
refresh: IconRefreshOutline16, plus: IconPlusOutline16, check: IconCheckOutline14,
|
|
@@ -150,12 +176,43 @@ window.__ModuleLoader__.load({
|
|
|
150
176
|
},
|
|
151
177
|
})
|
|
152
178
|
const { observeRepl } = createReplObserver({ rpc, ctx })
|
|
179
|
+
const capabilityCommands = createCommandAccess(ctx, 'capabilities')
|
|
180
|
+
const CapabilityCommandCard = createCapabilityCommandCard(React)
|
|
181
|
+
const CapabilityRefreshButton = createCapabilityRefreshView(React, capabilityCommands)
|
|
182
|
+
const SessionCapabilityControls = createSessionCapabilityControlsView(React, {
|
|
183
|
+
commands: capabilityCommands, Modal, Select,
|
|
184
|
+
async inspectSessionCatalog(sessionId, signal) {
|
|
185
|
+
const result = await rpc.call(RPC_CONTRACTS.capabilities, 'session-catalog', { sessionId }, signal)
|
|
186
|
+
if (result?.ok !== true) throw new Error(result?.error?.message ?? 'Session capability catalog unavailable')
|
|
187
|
+
return result.value
|
|
188
|
+
},
|
|
189
|
+
})
|
|
153
190
|
const { PTCPlusSettingsCard, PTCPlusSettingsDialog } = createPtcSettingsView(React, {
|
|
154
|
-
ActionButton, BindingsDialog, Modal, useWorkbenchController,
|
|
155
|
-
|
|
191
|
+
ActionButton, BindingsDialog, Modal, Select, useWorkbenchController, CapabilityRefreshButton,
|
|
192
|
+
async inspectCapabilityTargets(signal) {
|
|
193
|
+
const result = await rpc.call(RPC_CONTRACTS.capabilities, 'targets', {}, signal)
|
|
194
|
+
if (result?.ok !== true) throw new Error(result?.error?.message ?? 'Capability refresh targets unavailable')
|
|
195
|
+
return result.value
|
|
196
|
+
},
|
|
197
|
+
async inspectCapabilityPlans(signal) {
|
|
198
|
+
const result = await rpc.call(RPC_CONTRACTS.capabilities, 'inspect', {}, signal)
|
|
199
|
+
if (result?.ok !== true) throw new Error(result?.error?.message ?? 'Capability plans unavailable')
|
|
200
|
+
return result.value
|
|
201
|
+
},
|
|
202
|
+
async inspectCapabilityCatalog(signal) {
|
|
203
|
+
const result = await rpc.call(RPC_CONTRACTS.capabilities, 'catalog', {}, signal)
|
|
204
|
+
if (result?.ok !== true) throw new Error(result?.error?.message ?? 'Capability catalog unavailable')
|
|
205
|
+
return result.value
|
|
206
|
+
},
|
|
207
|
+
async inspectCapabilityAllocation(payload, signal) {
|
|
208
|
+
const result = await rpc.call(RPC_CONTRACTS.capabilities, 'allocation', payload, signal)
|
|
209
|
+
if (result?.ok !== true) throw new Error(result?.error?.message ?? 'Capability allocation unavailable')
|
|
210
|
+
return result.value
|
|
211
|
+
},
|
|
212
|
+
icons: { search: IconSearchOutline16, chevron: IconChevronDownOutline14 },
|
|
156
213
|
})
|
|
157
|
-
const { ReplComposer, ReplConsole, ReplMemoryCard, replPopoverIsOpen, placeReplPopover } = createReplView(React, {
|
|
158
|
-
CodeBlock, featureEnabled, normalizeReplMemorySnapshot, unavailableReplMemorySnapshot,
|
|
214
|
+
const { ReplComposer, ReplConsole, ReplMemoryCard, replPopoverIsOpen, placeReplPopover, useObservedReplMemory } = createReplView(React, {
|
|
215
|
+
CodeBlock, Select, featureEnabled, normalizeReplMemorySnapshot, unavailableReplMemorySnapshot,
|
|
159
216
|
useSessionPreset, sessionUsesPtcPreset, useWorkbenchController, UserBindingsWorkbench,
|
|
160
217
|
icons: { search: IconSearchOutline16, chevron: IconChevronDownOutline14 },
|
|
161
218
|
})
|
|
@@ -178,6 +235,15 @@ window.__ModuleLoader__.load({
|
|
|
178
235
|
&& (key !== 'bindingUpdates' || after.value.legacyBindingSettings !== true)
|
|
179
236
|
? 'status.applied' : 'status.conflict'
|
|
180
237
|
}
|
|
238
|
+
const updateCapabilityConfiguration = async configuration => {
|
|
239
|
+
const before = preferenceScope.getSnapshot()
|
|
240
|
+
if (before.status !== 'ready' || before.writable !== true || !featureEnabled(before, 'plugin')) throw new Error('Capability settings are not writable')
|
|
241
|
+
const validated = capabilityProfileConfiguration(configuration)
|
|
242
|
+
await preferenceScope.mutate(Object.entries(validated).map(([key, value]) => ({ op: 'set', path: [key], value })))
|
|
243
|
+
const after = preferenceScope.getSnapshot()
|
|
244
|
+
if (after.status !== 'ready' || Object.entries(validated).some(([key, value]) => after.value?.[key] !== value)) throw new Error('Capability configuration was not applied')
|
|
245
|
+
return 'status.applied'
|
|
246
|
+
}
|
|
181
247
|
// One gated-registration shape for every settings-driven contribution.
|
|
182
248
|
const settingsGate = (feature, register) => ({
|
|
183
249
|
subscribe: listener => preferenceScope.subscribe(listener),
|
|
@@ -191,20 +257,25 @@ window.__ModuleLoader__.load({
|
|
|
191
257
|
const settingsCard = publishSettingsCard(ctx, {
|
|
192
258
|
bundleName: __PTC_PLUS_CLIENT_MODULE_ID__,
|
|
193
259
|
locale: LOCALE_NS,
|
|
194
|
-
injectProps: () => ({ ...settingsProps(), updateSetting }),
|
|
260
|
+
injectProps: () => ({ ...settingsProps(), updateSetting, updateCapabilityConfiguration }),
|
|
195
261
|
component: PTCPlusSettingsCard,
|
|
196
262
|
})
|
|
197
263
|
|
|
264
|
+
function ConfiguredToolRow(props) {
|
|
265
|
+
const snapshot = React.useSyncExternalStore(preferenceScope.subscribe, preferenceScope.getSnapshot)
|
|
266
|
+
return h(PTCPlusToolRow, { ...props, hoverEnabled: featureEnabled(snapshot, 'toolHover') })
|
|
267
|
+
}
|
|
268
|
+
|
|
198
269
|
ctx.slots.inject('tool.call.toolview', () => registerGated(ctx, settingsGate('toolView', () => {
|
|
199
270
|
// Two rows share one eligibility decision; roll both back if either fails.
|
|
200
271
|
const disposers = []
|
|
201
272
|
try {
|
|
202
273
|
disposers.push(ctx.slots.register({
|
|
203
274
|
name: 'tool.call.toolview', key: 'run_code', locale: LOCALE_NS,
|
|
204
|
-
},
|
|
275
|
+
}, ConfiguredToolRow))
|
|
205
276
|
disposers.push(ctx.slots.register({
|
|
206
277
|
name: 'tool.call.toolview', key: 'edit_run_code', locale: LOCALE_NS,
|
|
207
|
-
},
|
|
278
|
+
}, ConfiguredToolRow))
|
|
208
279
|
} catch (error) {
|
|
209
280
|
disposers.reverse().forEach(dispose => dispose())
|
|
210
281
|
throw error
|
|
@@ -255,9 +326,9 @@ window.__ModuleLoader__.load({
|
|
|
255
326
|
// One probe answer serves every session's composer entry for this Client.
|
|
256
327
|
const menuChildren = createMenuChildrenEvidence()
|
|
257
328
|
const { BindingAuthorButton, BindingReviewDock, BindingCommandCard } = createAuthoringView(React, {
|
|
258
|
-
ActionButton, IconButton, Menu, Toast, Tooltip, CodeBlock, BindingsDialog, PTCPlusSettingsDialog,
|
|
329
|
+
ActionButton, IconButton, Menu, MenuFallback, Toast, Tooltip, CodeBlock, Modal, createPortal, BindingsDialog, PTCPlusSettingsDialog,
|
|
259
330
|
useWorkbenchController, useBindingReview, catalogOwner, callUserBindings, subscribeReset,
|
|
260
|
-
settingsCardSeat: settingsCard.seat, updateSetting, menuChildren,
|
|
331
|
+
settingsCardSeat: settingsCard.seat, updateSetting, updateCapabilityConfiguration, menuChildren, SessionCapabilityControls,
|
|
261
332
|
icons: {
|
|
262
333
|
sparkle: IconSparkle16, chevron: IconChevronDownOutline14,
|
|
263
334
|
close: IconCloseOutline16, check: IconCheckOutline14,
|
|
@@ -268,6 +339,7 @@ window.__ModuleLoader__.load({
|
|
|
268
339
|
normalizeReplMemorySnapshot, unavailableReplMemorySnapshot,
|
|
269
340
|
ReplMemoryCard, replPopoverIsOpen, placeReplPopover,
|
|
270
341
|
catalogOwner, subscribeReset,
|
|
342
|
+
useObservedReplMemory, observeRepl,
|
|
271
343
|
})
|
|
272
344
|
|
|
273
345
|
ctx.slots.inject('conversation.session.header.actions', () => registerGated(ctx, settingsGate('plugin', () => ctx.slots.register({
|
|
@@ -278,9 +350,18 @@ window.__ModuleLoader__.load({
|
|
|
278
350
|
name: 'conversation.chat.commandview', key: 'binding', locale: LOCALE_NS,
|
|
279
351
|
inject: settingsProps,
|
|
280
352
|
}, props => h(BindingCommandCard, { ...props, key: props.node.commandId })))))
|
|
353
|
+
ctx.slots.inject('conversation.chat.commandview', () => registerGated(ctx, settingsGate('plugin', () => ctx.slots.register({
|
|
354
|
+
name: 'conversation.chat.commandview', key: 'capabilities', locale: LOCALE_NS,
|
|
355
|
+
}, props => h(CapabilityCommandCard, props)))))
|
|
356
|
+
ctx.inject(['uiConversation'], scope => scope.effect(() => scope.uiConversation.events.register(bindingToggleConversationDefinition),
|
|
357
|
+
'ptc-plus binding configuration receipts'))
|
|
358
|
+
ctx.slots.inject('conversation.chat.node', () => ctx.effect(() => ctx.slots.register({
|
|
359
|
+
name: 'conversation.chat.node', key: 'ptc-plus-binding-toggle', locale: LOCALE_NS,
|
|
360
|
+
}, ({ node, t }) => h('p', { className: 'ptcPlusCapabilityReceipt', role: 'status' },
|
|
361
|
+
t(node.data.enabled ? 'bindings.toggleEnabled' : 'bindings.toggleDisabled', { name: node.data.name }))), 'ptc-plus binding configuration receipt renderer'))
|
|
281
362
|
ctx.slots.inject('conversation.input.dock', () => ctx.slots.inject('conversation.input.left', () =>
|
|
282
363
|
registerGated(ctx, settingsGate('bindings', () => ctx.slots.register({
|
|
283
|
-
name: 'conversation.input.dock', id: 'ptc-plus-binding-review', order: 30, locale: LOCALE_NS,
|
|
364
|
+
name: 'conversation.input.dock', id: 'ptc-plus-binding-review', order: -30, locale: LOCALE_NS,
|
|
284
365
|
}, props => typeof props.useProjection === 'function' && props.sessionId !== undefined
|
|
285
366
|
? h(BindingReviewDock, { ...props, key: props.sessionId }) : null)))))
|
|
286
367
|
const availability = createBindingCommandAvailability(ctx)
|
|
@@ -300,21 +381,20 @@ window.__ModuleLoader__.load({
|
|
|
300
381
|
return () => { unsubscribePreset(); unsubscribeSettings() }
|
|
301
382
|
},
|
|
302
383
|
isEnabled: () => sessionUsesPtcPreset(preset)
|
|
303
|
-
&& featureEnabled(preferenceScope.getSnapshot(), '
|
|
384
|
+
&& featureEnabled(preferenceScope.getSnapshot(), 'plugin'),
|
|
304
385
|
register: () => ctx.slots.register({
|
|
305
386
|
name: 'conversation.input.left', id: 'ptc-plus-binding-author', order: 20, locale: LOCALE_NS,
|
|
306
387
|
inject: sessionId => ({
|
|
307
|
-
hooks: { ptcSettings: preferenceScope, bindingCommand: availability.source(sessionId)
|
|
388
|
+
hooks: { ptcSettings: preferenceScope, bindingCommand: availability.source(sessionId),
|
|
389
|
+
capabilityCommand: capabilityCommands.source(sessionId) },
|
|
308
390
|
}),
|
|
309
391
|
}, props => props.sessionId === undefined ? null : h(BindingAuthorButton, { ...props, key: props.sessionId })),
|
|
310
392
|
}))
|
|
311
393
|
})
|
|
312
394
|
}
|
|
313
395
|
|
|
314
|
-
|
|
396
|
+
return {
|
|
315
397
|
apply,
|
|
316
398
|
inject: ['slots', 'locale', 'connection', 'remote'],
|
|
317
399
|
}
|
|
318
|
-
|
|
319
|
-
},
|
|
320
|
-
})
|
|
400
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|