dsh-ptc-plus 0.4.10 → 0.5.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 -127
- package/README.md +65 -127
- 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 +42702 -0
- package/cordis.patch.yml +1 -0
- package/docs/README.md +6 -2
- package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +31 -198
- 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 +4 -4
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +1 -1
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +1 -1
- package/docs/adr/0022-stage-npm-releases-with-oidc.md +4 -2
- package/docs/adr/0023-global-user-bindings.md +2 -0
- 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 +25 -23
- package/docs/adr/0031-close-semantic-obligations-by-owner.md +1 -1
- 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/0044-coexist-with-the-official-persistent-repl.md +35 -0
- package/docs/adr/README.md +8 -0
- package/docs/architecture.md +23 -25
- package/docs/capability-planning-components.md +93 -0
- package/docs/capability-projection.md +7 -0
- package/docs/client-ui.md +70 -23
- package/docs/client-visual-contract.md +26 -9
- 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 +20 -15
- 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 +33 -10
- package/docs/program-data-plane.md +5 -3
- package/docs/publishing.md +7 -7
- 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 +53 -16
- package/docs/semantic-validation.md +14 -2
- package/docs/stateful-binding-updates-proposal.md +2 -2
- package/docs/user-bindings.md +1 -1
- package/docs/value-wire.md +11 -1
- package/docs/verification-optimization-work.md +26 -15
- package/docs/verification.md +30 -88
- package/index.js +146 -20
- package/internal/binding-toggle-receipt.js +24 -0
- package/internal/capability-command-receipt.js +31 -0
- package/internal/capability-environment.js +1253 -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 +214 -0
- package/internal/config-spec.js +89 -10
- package/internal/direct-surface-owner.js +27 -29
- package/internal/dynamic-environment-runtime.js +9 -9
- package/internal/edit-transport-owner.js +195 -140
- package/internal/execution-provider-owner.js +40 -12
- package/internal/execution-seam-compat.js +26 -8
- package/internal/kernel-worker.js +104 -32
- package/internal/native-root-dynamic.js +12 -13
- package/internal/official-repl-priority.js +51 -0
- package/internal/program-bindings.js +190 -0
- package/internal/recovery-tips.js +3 -2
- 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 +275 -34
- package/internal/runtime-config.js +58 -0
- package/internal/runtime-contexts.js +74 -5
- 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 +34 -0
- package/internal/session-journal-recovery.js +234 -11
- package/internal/session-journal-schema.js +6 -3
- package/internal/session-journal.js +31 -2
- package/internal/session-log-view.js +1 -1
- package/internal/session-runtime.js +119 -15
- package/internal/settings-compat.js +12 -5
- 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 +19 -2
- 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/package.json +49 -30
- package/src/client-activity.js +3 -2
- package/src/client-authoring-view.js +67 -30
- package/src/client-binding-review.js +2 -1
- package/src/client-binding-toggle.js +18 -0
- package/src/client-capabilities-view.js +1555 -0
- package/src/client-capability-sort.js +29 -0
- package/src/client-copy.js +923 -8
- package/src/client-feature-gates.js +3 -0
- package/src/client-indicator-view.js +4 -6
- package/src/client-primitives.js +33 -2
- package/src/client-repl-view.js +20 -13
- package/src/client-settings-view.js +411 -41
- package/src/client-styles.js +112 -15
- package/src/client-tool-hover.js +185 -0
- package/src/client-tool-view.js +45 -9
- package/src/client-transport.js +44 -9
- package/src/client-workbench.js +6 -7
- package/src/client.js +76 -22
- package/client.js +0 -32479
|
@@ -8,13 +8,13 @@ import { USER_BINDING_TRANSFORM, LEGACY_USER_BINDING_TRANSFORM } from './module-
|
|
|
8
8
|
import { isAbsolute, resolve } from 'node:path'
|
|
9
9
|
import repl from 'node:repl'
|
|
10
10
|
import { PassThrough, Writable } from 'node:stream'
|
|
11
|
-
import { pathToFileURL } from '
|
|
11
|
+
import { pathToFileURL } from './module-runtime-platform.js'
|
|
12
12
|
import { MessageChannel, parentPort, workerData } from 'node:worker_threads'
|
|
13
13
|
import { synchronizeBuiltinEsmExports } from './builtin-esm-sync.js'
|
|
14
14
|
import { createPrivateAsyncLocalStorage } from './async-local-storage-intrinsics.js'
|
|
15
15
|
import { createExceptionOriginScope, errorDetails, messageOf, programBindingError } from './failure-reporting.js'
|
|
16
16
|
import { DURABLE_IMPORTS, FORBIDDEN_IMPORTS } from './module-policy.js'
|
|
17
|
-
import { decodeValue, encodeValue } from './value-wire.js'
|
|
17
|
+
import { decodeValue, encodeValue, encodeValueAtBoundary, valueEncodingFailure } from './value-wire.js'
|
|
18
18
|
import { LEGACY_USER_BINDINGS_REUSE_POLICY, LIVE_USER_BINDINGS_SHADOW_POLICY, normalizeUserBindingNames } from './session-journal-schema.js'
|
|
19
19
|
import { installWorkerCwdVirtualization } from './worker-cwd-virtualization.js'
|
|
20
20
|
import {
|
|
@@ -114,6 +114,15 @@ const output = new PassThrough()
|
|
|
114
114
|
output.resume()
|
|
115
115
|
const evaluationScope = createPrivateAsyncLocalStorage()
|
|
116
116
|
const sessionCwd = typeof workerData?.cwd === 'string' ? workerData.cwd : undefined
|
|
117
|
+
// The module source base is fixed when a cell starts; the operation directory
|
|
118
|
+
// follows the Session's working directory while the cell runs, so a confirmed
|
|
119
|
+
// `tools.working_directory` change rebases the rest of the cell exactly as the
|
|
120
|
+
// Host tools, which resolve at call time, already do.
|
|
121
|
+
let executionCwd = sessionCwd
|
|
122
|
+
let cellOperationCwd = sessionCwd
|
|
123
|
+
const resolveModuleFilename = resolve
|
|
124
|
+
const isAbsoluteDirectory = isAbsolute
|
|
125
|
+
const nativeCreateRequire = createRequire
|
|
117
126
|
if (sessionCwd !== undefined && !isAbsolute(sessionCwd)) {
|
|
118
127
|
throw new Error(`ptc-plus session cwd must be absolute, got ${jsonStringify(sessionCwd)}`)
|
|
119
128
|
}
|
|
@@ -145,7 +154,7 @@ const completionObserver = createCellCompletionObserver(runInWorkerReplRealm('Fu
|
|
|
145
154
|
let replModuleRealm
|
|
146
155
|
const statefulRoots = createStatefulRootRuntime({
|
|
147
156
|
refresh: name => refreshLegacyPublication(name),
|
|
148
|
-
importModule: (
|
|
157
|
+
importModule: moduleImportFor(),
|
|
149
158
|
errors: runInWorkerReplRealm('({ ReferenceError, TypeError })'),
|
|
150
159
|
dynamicIntrinsics: runInWorkerReplRealm('({intrinsicEval:eval,realmFunction:Function,globalObject:globalThis,errors:{ReferenceError,TypeError,SyntaxError},reflect:Reflect,object:Object})'),
|
|
151
160
|
readAmbient: name => runInWorkerReplRealm(name),
|
|
@@ -169,7 +178,7 @@ const statefulRoots = createStatefulRootRuntime({
|
|
|
169
178
|
const nativeRootDynamic = createNativeRootDynamic({
|
|
170
179
|
logicalReference: (name, writable) => statefulRoots.legacyReference(name, writable),
|
|
171
180
|
intrinsics: runInWorkerReplRealm('({intrinsicEval:eval,realmFunction:Function,globalObject:globalThis,errors:{ReferenceError,TypeError,SyntaxError},reflect:Reflect,object:Object})'),
|
|
172
|
-
importModule: (
|
|
181
|
+
importModule: moduleImportFor(),
|
|
173
182
|
read: name => runInWorkerReplRealm(name),
|
|
174
183
|
typeOf: name => runInWorkerReplRealm(`typeof ${name}`),
|
|
175
184
|
write(name, value, strict) {
|
|
@@ -181,11 +190,11 @@ const nativeRootDynamic = createNativeRootDynamic({
|
|
|
181
190
|
let valueObserver
|
|
182
191
|
const REPL_IMPORT_CANARY = 'data:text/javascript,export default 1'
|
|
183
192
|
let replParent
|
|
184
|
-
const
|
|
185
|
-
const staticAdapterParents = new
|
|
193
|
+
const cellModuleParent = () => executionCwd === undefined ? replParent : pathToFileURL(resolveModuleFilename(executionCwd, 'repl')).href
|
|
194
|
+
const staticAdapterParents = new Map()
|
|
186
195
|
const userBindingModuleParents = new Map()
|
|
187
196
|
const userModuleCompilation = createUserModuleCompilationHooks({
|
|
188
|
-
transformForParent: parent => (parent === replParent || parent ===
|
|
197
|
+
transformForParent: parent => (parent === replParent || parent === cellModuleParent()) && activeExecution !== undefined
|
|
189
198
|
? activeExecution.moduleTransform : undefined,
|
|
190
199
|
})
|
|
191
200
|
registerHooks({
|
|
@@ -193,10 +202,11 @@ registerHooks({
|
|
|
193
202
|
if (specifier === REPL_IMPORT_CANARY && replParent === undefined) replParent = context.parentURL
|
|
194
203
|
return userModuleCompilation.resolve(specifier, context, (source, resolvedContext) => {
|
|
195
204
|
const userBindingParent = mapGet(userBindingModuleParents, resolvedContext.parentURL)
|
|
205
|
+
const adapterParent = mapGet(staticAdapterParents, resolvedContext.parentURL)
|
|
196
206
|
return nextResolve(source, userBindingParent !== undefined
|
|
197
207
|
? { ...resolvedContext, parentURL: userBindingParent }
|
|
198
|
-
:
|
|
199
|
-
? { ...resolvedContext, parentURL:
|
|
208
|
+
: adapterParent !== undefined
|
|
209
|
+
? { ...resolvedContext, parentURL: adapterParent }
|
|
200
210
|
: resolvedContext)
|
|
201
211
|
})
|
|
202
212
|
},
|
|
@@ -356,23 +366,53 @@ installWorkerCwdVirtualization(sessionCwd, originalRequire, reason => {
|
|
|
356
366
|
return
|
|
357
367
|
}
|
|
358
368
|
markVolatile(reason)
|
|
359
|
-
})
|
|
369
|
+
}, () => cellOperationCwd)
|
|
360
370
|
synchronizeBuiltinEsmExports()
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
return managedRequire(activeExecution?.languageSemantics === 'legacy-v1' ? replParent : sessionReplParent ?? replParent,
|
|
367
|
-
activeExecution?.languageSemantics === 'legacy-v1' ? originalRequire : providedRequire)
|
|
371
|
+
function recordCellModuleResolution(transform) {
|
|
372
|
+
// An escaped loader retains its source generation. Native resolution still
|
|
373
|
+
// selects the URL; the module compiler owns adaptation before its first load.
|
|
374
|
+
return (parent, source, attributes, resolution) => userModuleCompilation.recordResolution(
|
|
375
|
+
parent, source, attributes, resolution, transform)
|
|
368
376
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
377
|
+
|
|
378
|
+
function moduleImportFor(parent, recordResolution) {
|
|
379
|
+
return (source, options) => managedModuleImport(parent ?? replParent, source, options, replModuleRealm, recordResolution)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function cellImportModuleFor(parent, transform) {
|
|
383
|
+
return moduleImportFor(parent, recordCellModuleResolution(transform))
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function providedRequireFor(parent, legacy, transform, explicitCwd) {
|
|
387
|
+
const recordResolution = recordCellModuleResolution(transform)
|
|
388
|
+
const nativeRequire = legacy || !explicitCwd ? originalRequire : nativeCreateRequire(parent)
|
|
389
|
+
const select = args => {
|
|
390
|
+
const specifier = args[0]
|
|
391
|
+
if (setHas(FORBIDDEN_IMPORTS, specifier)) throw new Error(`module ${specifier} is forbidden because it exposes kernel control`)
|
|
392
|
+
if (!setHas(DURABLE_IMPORTS, specifier)) markVolatile(`require(${jsonStringify(specifier)})`)
|
|
393
|
+
return managedRequire(legacy ? replParent : parent ?? replParent, legacy ? originalRequire : nativeRequire, recordResolution)
|
|
394
|
+
}
|
|
395
|
+
return new Proxy(nativeRequire, {
|
|
396
|
+
apply: (_, receiver, args) => privateReflect.apply(select(args), receiver, args),
|
|
397
|
+
construct: (_, args, newTarget) => privateReflect.construct(select(args), args, newTarget),
|
|
398
|
+
})
|
|
399
|
+
}
|
|
400
|
+
let providedRequireParent = cellModuleParent()
|
|
401
|
+
let providedRequireLegacy = false
|
|
402
|
+
let providedRequireTransform
|
|
403
|
+
let providedRequireExplicitCwd
|
|
404
|
+
function installProvidedRequire(parent, legacy = false, transform, explicitCwd = executionCwd !== undefined) {
|
|
405
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.STABLE, 'cell module metadata', context, 'require', {
|
|
406
|
+
configurable: true,
|
|
407
|
+
value: providedRequireFor(parent, legacy, transform, explicitCwd),
|
|
408
|
+
})
|
|
409
|
+
providedRequireParent = parent
|
|
410
|
+
providedRequireLegacy = legacy
|
|
411
|
+
providedRequireTransform = transform
|
|
412
|
+
providedRequireExplicitCwd = explicitCwd
|
|
413
|
+
}
|
|
414
|
+
installProvidedRequire(providedRequireParent)
|
|
415
|
+
|
|
376
416
|
function evaluate(program, completionSignal, asyncCompletion = false) {
|
|
377
417
|
return new ControlPromise((resolve, reject) => {
|
|
378
418
|
let settled = false
|
|
@@ -483,14 +523,16 @@ function staticAdapterSource(load) {
|
|
|
483
523
|
}
|
|
484
524
|
|
|
485
525
|
async function loadStaticModule(load) {
|
|
526
|
+
const parent = cellModuleParent()
|
|
527
|
+
const importModule = cellImportModuleFor(parent, activeExecution?.moduleTransform)
|
|
486
528
|
if (load.operation === 'native-dynamic') return { namespace: nativeRootDynamic.environment(load.callableSources,
|
|
487
529
|
load.awaitRoot === true, filterArray(load.logicalRoots, name => statefulRoots.has(name)
|
|
488
|
-
&& rootBindingStorage(name, moduleRuntimeIntrinsics.includes(load.nativeLexicals, name)) !== 'lexical'), load.writableRoots) }
|
|
530
|
+
&& rootBindingStorage(name, moduleRuntimeIntrinsics.includes(load.nativeLexicals, name)) !== 'lexical'), load.writableRoots, importModule) }
|
|
489
531
|
if (load.operation === 'import') {
|
|
490
|
-
return { namespace:
|
|
532
|
+
return { namespace: importModule }
|
|
491
533
|
}
|
|
492
534
|
const adapter = `data:text/javascript,${encodeURIComponent(staticAdapterSource(load))}#${++nextStaticAdapterId}`
|
|
493
|
-
|
|
535
|
+
mapSet(staticAdapterParents, adapter, cellModuleParent())
|
|
494
536
|
userModuleCompilation.mark(adapter, { compiled: true,
|
|
495
537
|
transform: activeExecution?.moduleTransform })
|
|
496
538
|
try {
|
|
@@ -499,7 +541,7 @@ async function loadStaticModule(load) {
|
|
|
499
541
|
const namespace = readModuleImport(adapter, load.source, null, () => completion.value.namespace, load.options?.with)
|
|
500
542
|
return { namespace }
|
|
501
543
|
} finally {
|
|
502
|
-
|
|
544
|
+
mapDelete(staticAdapterParents, adapter)
|
|
503
545
|
}
|
|
504
546
|
}
|
|
505
547
|
|
|
@@ -510,6 +552,18 @@ function hasExecutionLease(runId) {
|
|
|
510
552
|
// BoundError is the error class installed by this cell's wrapper, not a name
|
|
511
553
|
// looked up later: the cell can replace or delete the context binding while a
|
|
512
554
|
// call is pending, and the call must keep its submitted error identity.
|
|
555
|
+
// A confirmed Session directory change rebases the rest of the cell: Host tools
|
|
556
|
+
// resolve against the session service at call time, and this worker's relative
|
|
557
|
+
// operations now resolve against the same directory. The cell's module source
|
|
558
|
+
// base (imports, import.meta, provided require) stays fixed at its start.
|
|
559
|
+
function adoptConfirmedCellDirectory(call, value) {
|
|
560
|
+
if (call.global !== 'tools' || call.member !== 'working_directory') return
|
|
561
|
+
if (activeRun !== call.runId) return
|
|
562
|
+
const cwd = value?.cwd
|
|
563
|
+
if (typeof cwd !== 'string' || cwd.length === 0 || !isAbsoluteDirectory(cwd)) return
|
|
564
|
+
cellOperationCwd = cwd
|
|
565
|
+
}
|
|
566
|
+
|
|
513
567
|
function callHost(runId, global, member, args, BoundError) {
|
|
514
568
|
if (!hasExecutionLease(runId)) {
|
|
515
569
|
return promiseReject(programBindingError('lease', 'PTC execution lease expired'))
|
|
@@ -528,11 +582,11 @@ function callHost(runId, global, member, args, BoundError) {
|
|
|
528
582
|
const settled = new ControlPromise(resolve => {
|
|
529
583
|
moduleRuntimeIntrinsics.Reflect.apply(moduleRuntimeIntrinsics.promiseThen, result, [resolve, resolve])
|
|
530
584
|
})
|
|
531
|
-
mapSet(pending, id, { ...settle, runId, valueLimits, settled, member, BoundError })
|
|
585
|
+
mapSet(pending, id, { ...settle, runId, valueLimits, settled, global, member, BoundError })
|
|
532
586
|
try {
|
|
533
587
|
channel.postMessage({
|
|
534
588
|
type: 'call', runId, id, global, member,
|
|
535
|
-
args:
|
|
589
|
+
args: encodeValueAtBoundary(args, valueLimits, 'parameter'),
|
|
536
590
|
})
|
|
537
591
|
} catch (error) {
|
|
538
592
|
mapDelete(pending, id)
|
|
@@ -1213,7 +1267,7 @@ async function closeExecution(execution) {
|
|
|
1213
1267
|
}
|
|
1214
1268
|
|
|
1215
1269
|
function failureOutcome(error, phase, program) {
|
|
1216
|
-
if (phase === 'encode') return { invalidOutput: messageOf(error) }
|
|
1270
|
+
if (phase === 'encode') return { invalidOutput: messageOf(error), valueFailure: valueEncodingFailure(error) }
|
|
1217
1271
|
const failure = error instanceof StaticImportFailure ? error.error : error
|
|
1218
1272
|
// The V8 frame is reported in the executed text; validate it there so an
|
|
1219
1273
|
// out-of-range frame is an explicit absence instead of a mapped position.
|
|
@@ -1225,6 +1279,7 @@ function failureOutcome(error, phase, program) {
|
|
|
1225
1279
|
return {
|
|
1226
1280
|
error: detail.message,
|
|
1227
1281
|
errorName: detail.name,
|
|
1282
|
+
valueFailure: valueEncodingFailure(failure),
|
|
1228
1283
|
...(detail.toolName === undefined ? {} : { toolName: detail.toolName }),
|
|
1229
1284
|
...(error instanceof StaticImportFailure ? { moduleLoadFailed: true } : {}),
|
|
1230
1285
|
...(position === undefined ? {} : { position }),
|
|
@@ -1306,6 +1361,18 @@ async function sendCompletion(message, execution, userBindings, committedRedecla
|
|
|
1306
1361
|
|
|
1307
1362
|
async function runCell(message) {
|
|
1308
1363
|
if (activeExecution !== undefined) throw new Error('kernel received overlapping cells')
|
|
1364
|
+
if (message.cwd !== undefined && (typeof message.cwd !== 'string' || !isAbsoluteDirectory(message.cwd))) {
|
|
1365
|
+
throw new Error('ptc-plus cell cwd must be absolute')
|
|
1366
|
+
}
|
|
1367
|
+
executionCwd = message.cwd ?? sessionCwd
|
|
1368
|
+
cellOperationCwd = executionCwd
|
|
1369
|
+
const parent = cellModuleParent()
|
|
1370
|
+
const legacyRequire = message.languageSemantics === 'legacy-v1'
|
|
1371
|
+
const explicitCwd = executionCwd !== undefined
|
|
1372
|
+
if (parent !== providedRequireParent || legacyRequire !== providedRequireLegacy || message.moduleTransform !== providedRequireTransform
|
|
1373
|
+
|| explicitCwd !== providedRequireExplicitCwd) {
|
|
1374
|
+
installProvidedRequire(parent, legacyRequire, message.moduleTransform, explicitCwd)
|
|
1375
|
+
}
|
|
1309
1376
|
await writeOutputFence(nativeStdoutWrite, outputFenceMarker(message.outputFence, 'stdout', 'start'))
|
|
1310
1377
|
await writeOutputFence(nativeStderrWrite, outputFenceMarker(message.outputFence, 'stderr', 'start'))
|
|
1311
1378
|
await new ControlPromise(resolve => {
|
|
@@ -1368,6 +1435,7 @@ async function runCell(message) {
|
|
|
1368
1435
|
context, message.rootRuntimeName, {
|
|
1369
1436
|
configurable: true,
|
|
1370
1437
|
value: statefulRoots.begin({ ...message.rootBindings,
|
|
1438
|
+
importModule: cellImportModuleFor(parent, message.moduleTransform),
|
|
1371
1439
|
legacyLexicals,
|
|
1372
1440
|
legacyWritable,
|
|
1373
1441
|
legacyObjects: filterArray(legacyWritable, name => mapGet(legacyStorage, name) !== 'lexical'),
|
|
@@ -1486,7 +1554,11 @@ channel.on('message', (message) => {
|
|
|
1486
1554
|
if (call === undefined || call.runId !== message.runId) return
|
|
1487
1555
|
mapDelete(pending, message.id)
|
|
1488
1556
|
try {
|
|
1489
|
-
if (message.ok)
|
|
1557
|
+
if (message.ok) {
|
|
1558
|
+
const value = decodeValue(message.value, call.valueLimits)
|
|
1559
|
+
adoptConfirmedCellDirectory(call, value)
|
|
1560
|
+
call.resolve(value)
|
|
1561
|
+
}
|
|
1490
1562
|
else if (call.BoundError === undefined) {
|
|
1491
1563
|
const error = new Error(message.error)
|
|
1492
1564
|
if (message.cause !== undefined) error.ptcCause = message.cause
|
|
@@ -6,26 +6,25 @@ const { Map, Set, mapGet, mapSet, mapHas, mapDelete, setHas, setAdd, appendArray
|
|
|
6
6
|
/** Native storage and catalog-proved logical roots share a captured legacy view. */
|
|
7
7
|
export function createNativeRootDynamic({ intrinsics, importModule, read, write, typeOf, remove, logicalReference }) {
|
|
8
8
|
const interfaceOwner = {}
|
|
9
|
-
const runtime = createDynamicEnvironmentRuntime({ ...intrinsics, importModule, interfaceOwner }).installIntrinsics()
|
|
10
9
|
const descriptor = name => ({ kind: 'var', get: () => read(name),
|
|
11
10
|
set: (value, strict) => write(name, value, strict), delete: () => remove(name), typeof: () => typeOf(name) })
|
|
12
|
-
const environment = runtime.environment({
|
|
13
|
-
ambient(name, strict) {
|
|
14
|
-
return runtime.reference(name, descriptor(name), undefined, strict)
|
|
15
|
-
},
|
|
16
|
-
declareVars: runtime.declareGlobals,
|
|
17
|
-
createVar: descriptor,
|
|
18
|
-
})
|
|
19
|
-
runtime.setRootEnvironment(() => environment)
|
|
20
11
|
return {
|
|
21
|
-
environment(callableSources, awaitRoot = false, logicalRoots = [], writableRoots = []) {
|
|
12
|
+
environment(callableSources, awaitRoot = false, logicalRoots = [], writableRoots = [], cellImportModule = importModule) {
|
|
22
13
|
if (logicalRoots.length === 0) {
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
const cellRuntime = createDynamicEnvironmentRuntime({ ...intrinsics,
|
|
15
|
+
importModule: cellImportModule, interfaceOwner }).installIntrinsics()
|
|
16
|
+
const captured = cellRuntime.environment({
|
|
17
|
+
ambient: (name, strict) => cellRuntime.reference(name, descriptor(name), undefined, strict),
|
|
18
|
+
declareVars: cellRuntime.declareGlobals,
|
|
19
|
+
createVar: descriptor,
|
|
20
|
+
})
|
|
21
|
+
cellRuntime.setRootEnvironment(() => captured)
|
|
22
|
+
cellRuntime.registerSources(callableSources)
|
|
23
|
+
return awaitRoot ? captured.awaitActivation() : captured
|
|
25
24
|
}
|
|
26
25
|
// Each captured legacy environment keeps its own root view. Installing a
|
|
27
26
|
// later bridge must not change escaped eval/Function calls from old cells.
|
|
28
|
-
const bridgedRuntime = createDynamicEnvironmentRuntime({ ...intrinsics, importModule, interfaceOwner }).installIntrinsics()
|
|
27
|
+
const bridgedRuntime = createDynamicEnvironmentRuntime({ ...intrinsics, importModule: cellImportModule, interfaceOwner }).installIntrinsics()
|
|
29
28
|
const writable = new Set()
|
|
30
29
|
for (let index = 0; index < writableRoots.length; index++) setAdd(writable, writableRoots[index])
|
|
31
30
|
const bindings = new Map(), varFrame = new Map(), roots = new Map()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official persistent-REPL priority.
|
|
3
|
+
*
|
|
4
|
+
* The official `persistent-in-memory` execution mode is a live provider
|
|
5
|
+
* capability, not a release fact: a provider reports `programFormat` `'repl'`
|
|
6
|
+
* exactly when it retains a REPL per state owner. While the user selects the
|
|
7
|
+
* official REPL priority and that provider is live, the plugin yields PTC
|
|
8
|
+
* session execution to the official implementation and installs no session
|
|
9
|
+
* runtime: `run_code`, its descriptors and its guidance stay official. The
|
|
10
|
+
* decision is re-evaluated on every configuration change and host source
|
|
11
|
+
* change, so either side can take over without restarting the host.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Decide whether this configuration yields PTC session execution to the
|
|
16
|
+
* official provider.
|
|
17
|
+
* @param {object} config - resolved plugin configuration.
|
|
18
|
+
* @param {object} provider - the live provider surface registered for the seam.
|
|
19
|
+
* @returns {boolean} true when the official persistent REPL owns execution.
|
|
20
|
+
*/
|
|
21
|
+
export function defersToOfficialRepl(config, provider) {
|
|
22
|
+
if (config?.officialReplPriority !== true) return false
|
|
23
|
+
try {
|
|
24
|
+
return provider?.programFormat === 'repl'
|
|
25
|
+
} catch {
|
|
26
|
+
// An unreadable capability descriptor cannot prove official ownership;
|
|
27
|
+
// the plugin keeps its execution responsibility instead of guessing.
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Runtime record for an attachment that yields execution to the official
|
|
34
|
+
* provider. It owns no execution resources: the official provider releases
|
|
35
|
+
* anything it retained through its own lifecycle, and the plugin's settings,
|
|
36
|
+
* storage and UI owners remain available so the user can switch back.
|
|
37
|
+
*/
|
|
38
|
+
export function createDeferredRuntime() {
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
cancelCordisActivation() {
|
|
41
|
+
// No Cordis companion is installed while execution is deferred.
|
|
42
|
+
},
|
|
43
|
+
contextsForRequest: () => [],
|
|
44
|
+
async reconfigure() {
|
|
45
|
+
// This attachment has no owners to reconfigure.
|
|
46
|
+
},
|
|
47
|
+
async dispose() {
|
|
48
|
+
// Nothing is owned here; disposal returns immediately.
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
}
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
/** Deterministic capability metadata derived from the current DSH tool view. */
|
|
2
2
|
import { record, text } from './record-utils.js'
|
|
3
|
+
import { createHash } from 'node:crypto'
|
|
4
|
+
import { snapshotJsonValue } from '@deepseek-ai/dsh-util-values'
|
|
5
|
+
|
|
6
|
+
/** Derive SDK contracts from the public, scope-qualified tool registry. */
|
|
7
|
+
export function toolSdkSchemas(tools, scope) {
|
|
8
|
+
return tools.schemas(scope).filter(schema => schema.name !== 'run_code').map(schema => {
|
|
9
|
+
const definition = tools.get(schema.name, scope)
|
|
10
|
+
const output = snapshotJsonValue(definition?.output?.schema)
|
|
11
|
+
if (output === undefined) {
|
|
12
|
+
throw new TypeError(`ptc-plus: tool "${schema.name}" output schema must be lossless JSON before SDK projection`)
|
|
13
|
+
}
|
|
14
|
+
return { ...schema, output }
|
|
15
|
+
})
|
|
16
|
+
}
|
|
3
17
|
|
|
4
18
|
const COMPLETENESS = new Set(['complete', 'bounded', 'incremental', 'open-world', 'unknown'])
|
|
5
19
|
const SOURCE_KINDS = new Set(['authored', 'runtime', 'tests', 'docs'])
|
|
@@ -185,3 +199,179 @@ export function capabilityInspect(metadata, symbols = undefined, budget = 50) {
|
|
|
185
199
|
budget,
|
|
186
200
|
}
|
|
187
201
|
}
|
|
202
|
+
|
|
203
|
+
const SEARCH_DEFAULT_BYTES = 16_384
|
|
204
|
+
const SEARCH_MIN_BYTES = 512
|
|
205
|
+
const SEARCH_STOP_WORDS = new Set('a an and are as at be by can could do for from how i in is it me of on or please that the this to use using with would you 我 帮 帮我 请 的 了 和 与 在 如何 怎么 可以'.split(' '))
|
|
206
|
+
const SEARCH_SEGMENTER = new Intl.Segmenter('zh', { granularity: 'word' })
|
|
207
|
+
|
|
208
|
+
function taskTerms(value) {
|
|
209
|
+
const separated = value.normalize('NFKC')
|
|
210
|
+
.replace(/(\p{Lu}+)(\p{Lu}\p{Ll})/gu, '$1 $2')
|
|
211
|
+
.replace(/([\p{Ll}\p{N}])(\p{Lu})/gu, '$1 $2')
|
|
212
|
+
.toLowerCase()
|
|
213
|
+
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
|
214
|
+
return [...new Set([...SEARCH_SEGMENTER.segment(separated)]
|
|
215
|
+
.filter(part => part.isWordLike && !SEARCH_STOP_WORDS.has(part.segment))
|
|
216
|
+
.map(part => part.segment))]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function searchKeywords(value) {
|
|
220
|
+
if (value === undefined) return ''
|
|
221
|
+
if (typeof value === 'string') return value
|
|
222
|
+
if (Array.isArray(value) && value.every(item => typeof item === 'string')) return value.join(' ')
|
|
223
|
+
throw new TypeError('ptc-plus: capability search keywords must be a string or string array')
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Search budgets measure JSON, so non-JSON metadata cannot be silently converted or dropped.
|
|
227
|
+
function searchJson(value) {
|
|
228
|
+
const ancestors = new Set()
|
|
229
|
+
const visit = (item) => {
|
|
230
|
+
if (item === null || typeof item === 'string' || typeof item === 'boolean') return
|
|
231
|
+
if (typeof item === 'number' && Number.isFinite(item)) return
|
|
232
|
+
if (typeof item !== 'object') throw new TypeError('ptc-plus: capability search metadata must be lossless JSON data')
|
|
233
|
+
if (ancestors.has(item)) throw new TypeError('ptc-plus: capability search metadata must be lossless JSON data')
|
|
234
|
+
const prototype = Object.getPrototypeOf(item)
|
|
235
|
+
if (prototype !== (Array.isArray(item) ? Array.prototype : Object.prototype) && prototype !== null) {
|
|
236
|
+
throw new TypeError('ptc-plus: capability search metadata must be lossless JSON data')
|
|
237
|
+
}
|
|
238
|
+
ancestors.add(item)
|
|
239
|
+
for (const key of Reflect.ownKeys(item)) {
|
|
240
|
+
if (Array.isArray(item) && key === 'length') continue
|
|
241
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key)
|
|
242
|
+
if (typeof key !== 'string' || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')) {
|
|
243
|
+
throw new TypeError('ptc-plus: capability search metadata must be lossless JSON data')
|
|
244
|
+
}
|
|
245
|
+
visit(descriptor.value)
|
|
246
|
+
}
|
|
247
|
+
if (Array.isArray(item) && (Object.keys(item).length !== item.length
|
|
248
|
+
|| Object.keys(item).some(key => !/^(0|[1-9][0-9]*)$/.test(key) || Number(key) >= item.length))) {
|
|
249
|
+
throw new TypeError('ptc-plus: capability search metadata must be lossless JSON data')
|
|
250
|
+
}
|
|
251
|
+
ancestors.delete(item)
|
|
252
|
+
}
|
|
253
|
+
visit(value)
|
|
254
|
+
return JSON.stringify(value, (_key, item) => item !== null && typeof item === 'object' && !Array.isArray(item)
|
|
255
|
+
? Object.fromEntries(Object.keys(item).sort().map(key => [key, item[key]])) : item)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function searchDigest(value) {
|
|
259
|
+
return createHash('sha256').update(value).digest('base64url')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function measuredSearchPage(value) {
|
|
263
|
+
value.usedBytes = 0
|
|
264
|
+
let bytes = Buffer.byteLength(JSON.stringify(value), 'utf8')
|
|
265
|
+
while (value.usedBytes !== bytes) {
|
|
266
|
+
value.usedBytes = bytes
|
|
267
|
+
bytes = Buffer.byteLength(JSON.stringify(value), 'utf8')
|
|
268
|
+
}
|
|
269
|
+
return value
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Derive one request-local lexical index from owner metadata; never owns invocation. */
|
|
273
|
+
export function createCapabilitySearcher(metadata) {
|
|
274
|
+
const seen = new Set()
|
|
275
|
+
const snapshot = JSON.parse(searchJson(metadata))
|
|
276
|
+
const catalog = metadataEntries(snapshot).flatMap((entry) => {
|
|
277
|
+
const { members, ...owner } = entry
|
|
278
|
+
return members.map((member) => {
|
|
279
|
+
const symbol = `${entry.namespace}.${member.name}`
|
|
280
|
+
if (seen.has(symbol)) throw new TypeError(`ptc-plus: capability search has ambiguous symbol ${symbol}`)
|
|
281
|
+
seen.add(symbol)
|
|
282
|
+
const value = metadataSnapshot(JSON.parse(searchJson({ symbol, owner, contract: member })), 'capability search metadata')
|
|
283
|
+
const names = new Set(taskTerms(symbol))
|
|
284
|
+
const terms = new Set(taskTerms([
|
|
285
|
+
symbol, member.description ?? '', owner.description ?? '',
|
|
286
|
+
searchKeywords(member.keywords), searchKeywords(owner.keywords),
|
|
287
|
+
].join(' ')))
|
|
288
|
+
return { value, names, terms }
|
|
289
|
+
})
|
|
290
|
+
}).sort((left, right) => left.value.symbol < right.value.symbol ? -1 : left.value.symbol > right.value.symbol ? 1 : 0)
|
|
291
|
+
const catalogId = searchDigest(JSON.stringify(catalog.map(item => item.value)))
|
|
292
|
+
|
|
293
|
+
return (args) => {
|
|
294
|
+
const params = record(args, 'capability search arguments')
|
|
295
|
+
const allowed = new Set(['query', 'budgetBytes', 'limit', 'cursor'])
|
|
296
|
+
if (Reflect.ownKeys(params).some(key => typeof key !== 'string' || !allowed.has(key)
|
|
297
|
+
|| !Object.prototype.propertyIsEnumerable.call(params, key))) {
|
|
298
|
+
throw new TypeError('ptc-plus: capability search has an unknown argument')
|
|
299
|
+
}
|
|
300
|
+
const query = text(params.query, 'capability search query').normalize('NFKC').trim().toLowerCase()
|
|
301
|
+
const queryTerms = taskTerms(params.query)
|
|
302
|
+
const budgetBytes = params.budgetBytes === undefined ? SEARCH_DEFAULT_BYTES : params.budgetBytes
|
|
303
|
+
const limit = params.limit === undefined ? 10 : params.limit
|
|
304
|
+
if (!Number.isSafeInteger(budgetBytes) || budgetBytes < SEARCH_MIN_BYTES) {
|
|
305
|
+
throw new TypeError(`ptc-plus: capability search budgetBytes must be an integer of at least ${SEARCH_MIN_BYTES}`)
|
|
306
|
+
}
|
|
307
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new TypeError('ptc-plus: capability search limit must be a positive integer')
|
|
308
|
+
const queryId = searchDigest(JSON.stringify({ query, terms: queryTerms }))
|
|
309
|
+
const ranked = catalog.flatMap((candidate) => {
|
|
310
|
+
const { symbol, owner, contract } = candidate.value
|
|
311
|
+
const coverage = queryTerms.filter(term => candidate.terms.has(term)).length
|
|
312
|
+
const nameCoverage = queryTerms.filter(term => candidate.names.has(term)).length
|
|
313
|
+
const rank = symbol.normalize('NFKC').toLowerCase() === query ? 0
|
|
314
|
+
: owner.namespace.normalize('NFKC').toLowerCase() === query ? 1
|
|
315
|
+
: contract.name.normalize('NFKC').toLowerCase() === query ? 2
|
|
316
|
+
: coverage === 0 ? undefined
|
|
317
|
+
: nameCoverage === queryTerms.length ? 3
|
|
318
|
+
: coverage === queryTerms.length ? 4 : 5
|
|
319
|
+
return rank === undefined ? [] : [{ ...candidate, rank, coverage, nameCoverage }]
|
|
320
|
+
}).sort((left, right) => left.rank - right.rank || right.coverage - left.coverage
|
|
321
|
+
|| right.nameCoverage - left.nameCoverage
|
|
322
|
+
|| (left.value.symbol < right.value.symbol ? -1 : left.value.symbol > right.value.symbol ? 1 : 0))
|
|
323
|
+
|
|
324
|
+
let offset = 0
|
|
325
|
+
if (params.cursor !== undefined) {
|
|
326
|
+
if (typeof params.cursor !== 'string' || !/^[A-Za-z0-9_-]+$/.test(params.cursor)) {
|
|
327
|
+
throw new TypeError('ptc-plus: capability search cursor is invalid')
|
|
328
|
+
}
|
|
329
|
+
let cursor
|
|
330
|
+
try { cursor = JSON.parse(Buffer.from(params.cursor, 'base64url').toString('utf8')) } catch {
|
|
331
|
+
throw new TypeError('ptc-plus: capability search cursor is invalid')
|
|
332
|
+
}
|
|
333
|
+
if (cursor?.version !== 1 || cursor.catalog !== catalogId || cursor.query !== queryId
|
|
334
|
+
|| !Number.isSafeInteger(cursor.offset) || cursor.offset < 0 || cursor.offset >= ranked.length
|
|
335
|
+
|| Buffer.from(JSON.stringify(cursor)).toString('base64url') !== params.cursor) {
|
|
336
|
+
throw new TypeError('ptc-plus: capability search cursor is invalid or catalog/query changed')
|
|
337
|
+
}
|
|
338
|
+
offset = cursor.offset
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const page = (matches, oversized, next) => measuredSearchPage({
|
|
342
|
+
matches, oversized, total: ranked.length, remaining: ranked.length - next,
|
|
343
|
+
cursor: next < ranked.length ? Buffer.from(JSON.stringify({
|
|
344
|
+
version: 1, catalog: catalogId, query: queryId, offset: next,
|
|
345
|
+
})).toString('base64url') : null,
|
|
346
|
+
budgetBytes, unit: 'utf8-json-bytes', usedBytes: 0,
|
|
347
|
+
})
|
|
348
|
+
let result = page([], [], offset)
|
|
349
|
+
for (let next = offset; next < ranked.length && next - offset < limit; next += 1) {
|
|
350
|
+
const candidate = ranked[next].value
|
|
351
|
+
const expanded = page([...result.matches, candidate], result.oversized, next + 1)
|
|
352
|
+
if (expanded.usedBytes <= budgetBytes) {
|
|
353
|
+
result = expanded
|
|
354
|
+
continue
|
|
355
|
+
}
|
|
356
|
+
const alone = page([candidate], [], next + 1)
|
|
357
|
+
if (alone.usedBytes <= budgetBytes) break
|
|
358
|
+
const omitted = {
|
|
359
|
+
symbol: candidate.symbol, requiredBytes: alone.usedBytes,
|
|
360
|
+
inspect: { symbols: [candidate.symbol], budget: 1 },
|
|
361
|
+
}
|
|
362
|
+
const bounded = page(result.matches, [...result.oversized, omitted], next + 1)
|
|
363
|
+
if (bounded.usedBytes > budgetBytes) {
|
|
364
|
+
if (next === offset) throw new RangeError(`ptc-plus: capability search needs at least ${bounded.usedBytes} budgetBytes for its continuation and inspect reference`)
|
|
365
|
+
break
|
|
366
|
+
}
|
|
367
|
+
result = bounded
|
|
368
|
+
}
|
|
369
|
+
if (result.usedBytes > budgetBytes) throw new RangeError(`ptc-plus: capability search needs at least ${result.usedBytes} budgetBytes for its continuation`)
|
|
370
|
+
return result
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** Return whole owner contracts within a UTF-8 JSON byte budget, including the envelope. */
|
|
375
|
+
export function capabilitySearch(metadata, args) {
|
|
376
|
+
return createCapabilitySearcher(metadata)(args)
|
|
377
|
+
}
|
|
@@ -2,6 +2,7 @@ import { PTC_STATE_NAMES, recoveryTipIdentity } from './runtime-messages.js'
|
|
|
2
2
|
|
|
3
3
|
const PLATFORM_CAUSE_CODES = new Set(['EACCES', 'EINVAL', 'ENOTDIR', 'ENOENT', 'UNKNOWN'])
|
|
4
4
|
const TIP_CONTEXT_PREFIX = 'tools:ptc-plus-tip/'
|
|
5
|
+
const PLATFORM_FACTS = '`return { platform: process.platform, arch: process.arch, node: process.version, cwd: process.cwd(), execPath: process.execPath }`'
|
|
5
6
|
const TIP_PREFIXES = Object.freeze({
|
|
6
7
|
'repeated-binding-failure': 'The same binding failure has recurred.',
|
|
7
8
|
'platform-command-failure': 'An executable, shell, or path failed in the current execution world.',
|
|
@@ -93,8 +94,8 @@ function tipCandidate(view) {
|
|
|
93
94
|
function renderTip(id, detailed, candidate = {}) {
|
|
94
95
|
if (id === 'platform-command-failure') {
|
|
95
96
|
return detailed
|
|
96
|
-
? `${TIP_PREFIXES[id]} Re-check the active execution world and the actual executable before retrying. Use direct argv for a normal executable; use a shell only when its syntax or resolution is required. Windows, WSL, POSIX, and package shims have different paths and launch rules.`
|
|
97
|
-
: `${TIP_PREFIXES[id]} Inspect the executable
|
|
97
|
+
? `${TIP_PREFIXES[id]} Re-check the active execution world and the actual executable before retrying. First inspect bounded runtime facts with ${PLATFORM_FACTS}; use the result to choose the executable and path. Use direct argv for a normal executable; use a shell only when its syntax or resolution is required. Windows, WSL, POSIX, and package shims have different paths and launch rules. Do not dump process.env.`
|
|
98
|
+
: `${TIP_PREFIXES[id]} Inspect bounded runtime facts with ${PLATFORM_FACTS}, then choose the executable and path in the current execution world. Use direct argv or a shell only when required; do not assume Windows, WSL, POSIX, or one shell. Do not dump process.env.`
|
|
98
99
|
}
|
|
99
100
|
if (!candidate.capability) {
|
|
100
101
|
return `${TIP_PREFIXES[id]} Inspect the visible cell source and results for the local name, scope, initialization, or declaration conflict. Correct that expression before continuing; capability discovery does not list session-local variables.${detailed ? ' Earlier statements may have run; use current expression evidence without assuming a failed declaration initialized its binding.' : ''}`
|
|
@@ -255,39 +255,39 @@ function assemble(source, replacements) {
|
|
|
255
255
|
export function editRunCodeSchema() {
|
|
256
256
|
return {
|
|
257
257
|
name: 'edit_run_code',
|
|
258
|
-
description: '
|
|
258
|
+
description: 'Call this from within a run_code cell. It accepts an edit of the most recent eligible cell captured at nested dispatch and returns { accepted, scheduled, target_call_seq } when scheduled. The corrected cell runs after the current run_code cell releases its worker; its result is reported with that cell, and a successful edit becomes the next target. This reruns the entire target cell, including prior effects; use it after pre-execution rejection or when repeating those effects is safe under the called API\'s retry rules. Otherwise continue in a new run_code cell using retained values. A diagnostic may supply a localized correction; use it when it matches your intent and preserve its expected_target_call_seq. Send exactly one edits or regex_edits array: edits replaces unique literal fragments; regex_edits replaces a counted set of pattern matches. All ranges must be non-overlapping in the original cell. Regex replacements use JavaScript $1/$<name> captures, not \\1.',
|
|
259
259
|
parameters: {
|
|
260
260
|
type: 'object',
|
|
261
261
|
additionalProperties: false,
|
|
262
262
|
properties: {
|
|
263
263
|
edits: {
|
|
264
|
-
type: 'array',
|
|
264
|
+
type: 'array',
|
|
265
265
|
description: 'Atomic exact replacements, all resolved against the original target cell.',
|
|
266
266
|
items: {
|
|
267
267
|
type: 'object', additionalProperties: false,
|
|
268
268
|
properties: {
|
|
269
|
-
old_string: { type: 'string',
|
|
269
|
+
old_string: { type: 'string', description: 'Nonempty exact text in the target cell. It must occur exactly once.' },
|
|
270
270
|
new_string: { type: 'string', description: 'Literal replacement text. Use an empty string to delete the match.' },
|
|
271
271
|
},
|
|
272
272
|
required: ['old_string', 'new_string'],
|
|
273
273
|
},
|
|
274
274
|
},
|
|
275
275
|
regex_edits: {
|
|
276
|
-
type: 'array',
|
|
276
|
+
type: 'array',
|
|
277
277
|
description: 'Atomic regular-expression replacements, all matched against the original target cell with JavaScript pattern and replacement semantics; each replacement is a JavaScript template (see replacement).',
|
|
278
278
|
items: {
|
|
279
279
|
type: 'object', additionalProperties: false,
|
|
280
280
|
properties: {
|
|
281
|
-
pattern: { type: 'string',
|
|
282
|
-
flags: { type: 'string',
|
|
281
|
+
pattern: { type: 'string', description: 'Nonempty JavaScript regular-expression source without delimiters or flags (for example \\d+px, not /\\d+px/). Zero-length matches are rejected.' },
|
|
282
|
+
flags: { type: 'string', description: 'Unique JavaScript g, i, m, s, or u flags. Global matching is always applied.' },
|
|
283
283
|
replacement: { type: 'string', description: 'JavaScript replacement template. Reference captures as $1, $2, ... or $<name> (for example "<$1>" inserts capture 1); backslash escapes such as \\1 are NOT capture references and stay literal text; write a literal dollar sign as $$.' },
|
|
284
|
-
expected_matches: { type: 'integer',
|
|
284
|
+
expected_matches: { type: 'integer', description: 'Positive exact match count required before any replacement is applied.' },
|
|
285
285
|
},
|
|
286
286
|
required: ['pattern', 'flags', 'replacement', 'expected_matches'],
|
|
287
287
|
},
|
|
288
288
|
},
|
|
289
289
|
[EXPECTED_TARGET_CALL_SEQ]: {
|
|
290
|
-
type: 'integer',
|
|
290
|
+
type: 'integer',
|
|
291
291
|
description: 'Optional target precondition copied from a validated diagnostic. The edit is rejected if the captured cell has another call sequence.',
|
|
292
292
|
},
|
|
293
293
|
},
|