dsh-ptc-plus 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +171 -0
- package/README.md +94 -67
- package/assets/dsh-ptc-plus-banner-en.webp +0 -0
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.js +1211 -128
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +20 -4
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0022-stage-npm-releases-with-oidc.md +31 -0
- package/docs/architecture.md +10 -9
- package/docs/client-ui.md +30 -12
- package/docs/installation.md +13 -5
- package/docs/publishing.md +25 -1
- package/docs/runtime-reference.md +18 -12
- package/docs/value-wire.md +1 -1
- package/index.js +43 -12
- package/internal/cell-analysis.js +20 -3
- package/internal/cell-rewriter.js +36 -2
- package/internal/config-spec.js +192 -82
- package/internal/direct-surface-owner.js +77 -23
- package/internal/edit-transport-owner.js +10 -1
- package/internal/failure-reporting.js +15 -0
- package/internal/rejected-cell-editor.js +21 -12
- package/internal/repl-memory-projection.js +277 -0
- package/internal/run-code-description.js +34 -0
- package/internal/runtime-bridge-owner.js +63 -15
- package/internal/runtime-config.js +2 -0
- package/internal/session-cell-executor.js +14 -4
- package/internal/session-events.js +7 -0
- package/internal/session-journal.js +3 -2
- package/internal/session-log-view.js +2 -1
- package/internal/session-runtime.js +19 -2
- package/internal/session-state.js +83 -4
- package/internal/settings-compat.js +31 -0
- package/package.json +20 -13
- package/src/client-activity.js +472 -0
- package/src/client.js +536 -38
- package/README.zh.md +0 -144
- package/assets/ptc-plus-settings.png +0 -0
- /package/assets/{dsh-ptc-plus-banner.webp → dsh-ptc-plus-banner-zh.webp} +0 -0
- /package/assets/{ptc-plus-repair.png → ptc-plus-repair-zh.png} +0 -0
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
toolCapabilityMetadata,
|
|
20
20
|
} from './program-bindings.js'
|
|
21
21
|
import { deepFreeze } from './record-utils.js'
|
|
22
|
+
import { withReplMemorySnapshot } from './repl-memory-projection.js'
|
|
23
|
+
import { generatedRunCodeDescriptionMeta } from './run-code-description.js'
|
|
22
24
|
|
|
23
25
|
export const RUN_CODE = 'run_code'
|
|
24
26
|
|
|
@@ -123,6 +125,7 @@ export function createRuntimeBridgeOwner({
|
|
|
123
125
|
ctx,
|
|
124
126
|
sessionConfig,
|
|
125
127
|
maxNestedRunCodeDepth,
|
|
128
|
+
presentationGeneration,
|
|
126
129
|
sessionId,
|
|
127
130
|
toolSchemasForAgent,
|
|
128
131
|
}) {
|
|
@@ -247,7 +250,7 @@ export function createRuntimeBridgeOwner({
|
|
|
247
250
|
return { request: { ...request, bindings: projected }, release }
|
|
248
251
|
}
|
|
249
252
|
|
|
250
|
-
const
|
|
253
|
+
const patchRunCodeDefinition = (agent) => {
|
|
251
254
|
const definition = ctx.tools.get(RUN_CODE, agent)
|
|
252
255
|
if (definition === undefined) {
|
|
253
256
|
throw new Error('ptc-plus: run_code definition is unavailable for the owning session')
|
|
@@ -257,28 +260,65 @@ export function createRuntimeBridgeOwner({
|
|
|
257
260
|
}
|
|
258
261
|
if (patchedDefinitions.has(definition)) return
|
|
259
262
|
const output = definition.output
|
|
260
|
-
const
|
|
261
|
-
const
|
|
262
|
-
if (!active)
|
|
263
|
-
|
|
263
|
+
const originalPresentationMeta = output.presentationMeta
|
|
264
|
+
const patchedPresentationMeta = (args, value) => {
|
|
265
|
+
if (!active) {
|
|
266
|
+
return originalPresentationMeta === undefined
|
|
267
|
+
? undefined
|
|
268
|
+
: originalPresentationMeta(args, value)
|
|
269
|
+
}
|
|
270
|
+
const base = originalPresentationMeta === undefined
|
|
271
|
+
? undefined
|
|
272
|
+
: originalPresentationMeta(args, value)
|
|
264
273
|
const current = scope.getStore()
|
|
265
274
|
const settlement = current?.settlement
|
|
266
|
-
if (settlement === undefined) return base
|
|
275
|
+
if (settlement === undefined) return generatedRunCodeDescriptionMeta(args, base)
|
|
267
276
|
let meta = withJournal(base, settlement.journal)
|
|
268
277
|
if (settlement.recoveryBoundaries !== undefined) {
|
|
269
278
|
meta = withRecoveryBoundaries(meta, settlement.recoveryBoundaries)
|
|
270
279
|
}
|
|
271
|
-
|
|
280
|
+
if (settlement.rewrites !== undefined) meta = withRewrites(meta, settlement.rewrites)
|
|
281
|
+
meta = generatedRunCodeDescriptionMeta(args, meta)
|
|
282
|
+
return withReplMemorySnapshot(meta, settlement.replMemory, presentationGeneration)
|
|
272
283
|
}
|
|
284
|
+
const ownExecute = Object.getOwnPropertyDescriptor(definition, 'execute')
|
|
285
|
+
const originalExecute = definition.execute
|
|
286
|
+
const patchedExecute = typeof originalExecute !== 'function'
|
|
287
|
+
? undefined
|
|
288
|
+
: function (args, exec) {
|
|
289
|
+
const executionArguments = scope.getStore()?.executionArguments ?? args
|
|
290
|
+
return originalExecute.call(this, executionArguments, exec)
|
|
291
|
+
}
|
|
292
|
+
let presentationPatched = false
|
|
273
293
|
try {
|
|
274
294
|
Object.defineProperty(output, 'presentationMeta', {
|
|
275
295
|
configurable: true,
|
|
276
296
|
enumerable: true,
|
|
277
297
|
writable: true,
|
|
278
|
-
value:
|
|
298
|
+
value: patchedPresentationMeta,
|
|
299
|
+
})
|
|
300
|
+
presentationPatched = true
|
|
301
|
+
if (patchedExecute !== undefined) {
|
|
302
|
+
Object.defineProperty(definition, 'execute', {
|
|
303
|
+
configurable: true,
|
|
304
|
+
enumerable: ownExecute?.enumerable ?? true,
|
|
305
|
+
writable: true,
|
|
306
|
+
value: patchedExecute,
|
|
307
|
+
})
|
|
308
|
+
}
|
|
309
|
+
patchedDefinitions.set(definition, {
|
|
310
|
+
definition,
|
|
311
|
+
output,
|
|
312
|
+
originalPresentationMeta,
|
|
313
|
+
patchedPresentationMeta,
|
|
314
|
+
ownExecute,
|
|
315
|
+
patchedExecute,
|
|
279
316
|
})
|
|
280
|
-
patchedDefinitions.set(definition, { output, original, patched })
|
|
281
317
|
} catch (error) {
|
|
318
|
+
if (presentationPatched && output.presentationMeta === patchedPresentationMeta) {
|
|
319
|
+
if (originalPresentationMeta === undefined) delete output.presentationMeta
|
|
320
|
+
else output.presentationMeta = originalPresentationMeta
|
|
321
|
+
}
|
|
282
322
|
throw new Error(`ptc-plus: cannot attach the session journal to run_code results: ${error.message}`)
|
|
283
323
|
}
|
|
284
324
|
}
|
|
@@ -333,11 +373,11 @@ export function createRuntimeBridgeOwner({
|
|
|
333
373
|
throw error
|
|
334
374
|
}
|
|
335
375
|
},
|
|
336
|
-
handleExecute(exec, next) {
|
|
376
|
+
handleExecute(exec, next, executionArguments = exec.arguments) {
|
|
337
377
|
if (exec.parent !== undefined) return scope.run(undefined, next)
|
|
338
378
|
const id = sessionId(exec.agent)
|
|
339
379
|
if (id === undefined) return next()
|
|
340
|
-
|
|
380
|
+
patchRunCodeDefinition(exec.agent)
|
|
341
381
|
const inherited = scope.getStore()
|
|
342
382
|
const persistedCallSeq = inherited?.persistedCallSeq
|
|
343
383
|
const current = {
|
|
@@ -349,6 +389,7 @@ export function createRuntimeBridgeOwner({
|
|
|
349
389
|
: { deferredSettlement: inherited.deferredSettlement }),
|
|
350
390
|
session: exec.agent?.session,
|
|
351
391
|
agent: exec.agent,
|
|
392
|
+
executionArguments,
|
|
352
393
|
}
|
|
353
394
|
if (current.deferredSettlement !== undefined) {
|
|
354
395
|
current.deferredSettlement.current = current
|
|
@@ -363,6 +404,7 @@ export function createRuntimeBridgeOwner({
|
|
|
363
404
|
meta = withRecoveryBoundaries(meta, settlement.recoveryBoundaries)
|
|
364
405
|
}
|
|
365
406
|
if (settlement.rewrites !== undefined) meta = withRewrites(meta, settlement.rewrites)
|
|
407
|
+
meta = withReplMemorySnapshot(meta, settlement.replMemory, presentationGeneration)
|
|
366
408
|
return { ...result, meta }
|
|
367
409
|
}
|
|
368
410
|
return result
|
|
@@ -405,10 +447,16 @@ export function createRuntimeBridgeOwner({
|
|
|
405
447
|
if (ownRun === undefined) delete runtime.run
|
|
406
448
|
else Object.defineProperty(runtime, 'run', ownRun)
|
|
407
449
|
}
|
|
408
|
-
for (const
|
|
409
|
-
if (output.presentationMeta
|
|
410
|
-
|
|
411
|
-
|
|
450
|
+
for (const patched of patchedDefinitions.values()) {
|
|
451
|
+
if (patched.output.presentationMeta === patched.patchedPresentationMeta) {
|
|
452
|
+
if (patched.originalPresentationMeta === undefined) delete patched.output.presentationMeta
|
|
453
|
+
else patched.output.presentationMeta = patched.originalPresentationMeta
|
|
454
|
+
}
|
|
455
|
+
if (patched.patchedExecute !== undefined
|
|
456
|
+
&& patched.definition.execute === patched.patchedExecute) {
|
|
457
|
+
if (patched.ownExecute === undefined) delete patched.definition.execute
|
|
458
|
+
else Object.defineProperty(patched.definition, 'execute', patched.ownExecute)
|
|
459
|
+
}
|
|
412
460
|
}
|
|
413
461
|
patchedDefinitions.clear()
|
|
414
462
|
await sessions.dispose()
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
LONG_CELL_CODE_UNITS,
|
|
13
13
|
markBindingFailure,
|
|
14
14
|
messageOf,
|
|
15
|
+
missingDescriptionPath,
|
|
15
16
|
oneLineMessage,
|
|
16
17
|
safeProperty,
|
|
17
18
|
} from './failure-reporting.js'
|
|
@@ -128,7 +129,11 @@ function exceptionDiagnostic({
|
|
|
128
129
|
declared,
|
|
129
130
|
longCellFailure = false,
|
|
130
131
|
}) {
|
|
131
|
-
const
|
|
132
|
+
const missingPath = error.name === 'ToolCallError' ? missingDescriptionPath(error) : undefined
|
|
133
|
+
const missingDescription = missingPath !== undefined
|
|
134
|
+
const message = missingDescription
|
|
135
|
+
? `nested native tool arguments are missing required \`description\` at JSON path $.${missingPath} (${error.toolName ?? 'unknown tool'}); this does not satisfy the outer run_code transport`
|
|
136
|
+
: firstLine(error.message, 'Unknown exception')
|
|
132
137
|
const rawName = typeof error.name === 'string' && error.name.length > 0
|
|
133
138
|
? error.name
|
|
134
139
|
/* c8 ignore next */
|
|
@@ -147,7 +152,9 @@ function exceptionDiagnostic({
|
|
|
147
152
|
...(cause === undefined ? {} : { cause }),
|
|
148
153
|
...(source === undefined ? {} : { source }),
|
|
149
154
|
help: [
|
|
150
|
-
|
|
155
|
+
...(missingDescription
|
|
156
|
+
? ['add a string `description` property to the nested native-tool argument object']
|
|
157
|
+
: ['inspect existing bindings and retry only the failing expression']),
|
|
151
158
|
...(error.name === 'ToolCallError'
|
|
152
159
|
&& typeof error.toolName === 'string'
|
|
153
160
|
&& error.toolName.startsWith('cordis_')
|
|
@@ -496,7 +503,7 @@ export class SessionCellExecutor {
|
|
|
496
503
|
})
|
|
497
504
|
active.appliedBindingCatalog = message.moduleLoadFailed === true
|
|
498
505
|
? active.priorBindingCatalog
|
|
499
|
-
: active.priorBindingCatalog.advance(active.prepared)
|
|
506
|
+
: active.priorBindingCatalog.advance(active.prepared, active.request.program)
|
|
500
507
|
const recordedFailure = active.replay?.diagnostics?.find(item => item.code === 'PTC-X001')
|
|
501
508
|
const failure = recordedFailure?.message === actualFailure.message ? recordedFailure : actualFailure
|
|
502
509
|
const error = {
|
|
@@ -525,7 +532,10 @@ export class SessionCellExecutor {
|
|
|
525
532
|
hasValue: message.hasValue,
|
|
526
533
|
...(message.hasValue ? { value } : {}),
|
|
527
534
|
}
|
|
528
|
-
active.appliedBindingCatalog = active.priorBindingCatalog.advance(
|
|
535
|
+
active.appliedBindingCatalog = active.priorBindingCatalog.advance(
|
|
536
|
+
active.prepared,
|
|
537
|
+
active.request.program,
|
|
538
|
+
)
|
|
529
539
|
if (active.replay?.completion?.kind === 'return'
|
|
530
540
|
&& (active.replay.completion.hasValue !== message.hasValue
|
|
531
541
|
|| (message.hasValue && !valueWiresEqual(active.replay.completion.value, value, active.valueLimits)))) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { decodeValue, encodeValue, normalizeValueWire } from './value-wire.js'
|
|
2
2
|
import { normalizeDiagnostic } from './diagnostic.js'
|
|
3
3
|
import { assertOwnFields, isRecord } from './record-utils.js'
|
|
4
|
+
import { sessionEvents } from './session-events.js'
|
|
4
5
|
|
|
5
6
|
export const JOURNAL_KEY = 'dshPtcPlus'
|
|
6
7
|
export const EDIT_TARGET_KEY = 'dshPtcPlusEdit'
|
|
@@ -365,7 +366,7 @@ export function migrateRecoveryBoundaryEvents(events) {
|
|
|
365
366
|
|
|
366
367
|
/** Resolve the persisted event identity for one named tool call being dispatched. */
|
|
367
368
|
export function liveToolCallSeq(session, callId, toolName) {
|
|
368
|
-
const events = session
|
|
369
|
+
const events = sessionEvents(session)
|
|
369
370
|
if (!Array.isArray(events) || typeof callId !== 'string' || callId.length === 0
|
|
370
371
|
|| typeof toolName !== 'string' || toolName.length === 0) return undefined
|
|
371
372
|
|
|
@@ -741,7 +742,7 @@ export function foldSessionTimeline(events) {
|
|
|
741
742
|
|
|
742
743
|
/** Fold the session log into the last exactly replayable frontier. */
|
|
743
744
|
export function recoverJournal(session, currentCallSeq, options = {}) {
|
|
744
|
-
const events = session
|
|
745
|
+
const events = sessionEvents(session)
|
|
745
746
|
if (!Array.isArray(events)) {
|
|
746
747
|
return { nodes: [], head: undefined, checkpoints: new Map(), volatileSuffix: [], available: true }
|
|
747
748
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
foldSessionTimeline,
|
|
3
3
|
} from './session-journal.js'
|
|
4
|
+
import { sessionEvents } from './session-events.js'
|
|
4
5
|
|
|
5
6
|
const SYSTEM_PROMPT_PLUGIN = '@deepseek-ai/dsh-system-prompt'
|
|
6
7
|
|
|
@@ -43,7 +44,7 @@ function cordisTranscriptFacts(timeline) {
|
|
|
43
44
|
|
|
44
45
|
/** Project session events into immutable facts consumed by prompt presentation. */
|
|
45
46
|
export function projectSessionLog(agent, requestedEdit) {
|
|
46
|
-
const events = agent?.session
|
|
47
|
+
const events = sessionEvents(agent?.session)
|
|
47
48
|
if (!Array.isArray(events)) {
|
|
48
49
|
return Object.freeze({
|
|
49
50
|
openTurn: false,
|
|
@@ -13,6 +13,10 @@ import { resolveConfig } from './runtime-config.js'
|
|
|
13
13
|
import { WorkerClient } from './worker-client.js'
|
|
14
14
|
import { BindingCatalog, durabilityState, transitionDurability } from './session-state.js'
|
|
15
15
|
import { SessionCellExecutor } from './session-cell-executor.js'
|
|
16
|
+
import {
|
|
17
|
+
createReplMemorySnapshot,
|
|
18
|
+
unavailableReplMemorySnapshot,
|
|
19
|
+
} from './repl-memory-projection.js'
|
|
16
20
|
|
|
17
21
|
const WORKER_URL = new URL('./kernel-worker.js', import.meta.url)
|
|
18
22
|
function recoveryDiagnostic(count) {
|
|
@@ -300,14 +304,14 @@ class SessionKernel {
|
|
|
300
304
|
callSeq: request.callSeq,
|
|
301
305
|
program: request.program,
|
|
302
306
|
bindingCatalog: active.appliedBindingCatalog
|
|
303
|
-
?? active.priorBindingCatalog.advance(prepared),
|
|
307
|
+
?? active.priorBindingCatalog.advance(prepared, request.program),
|
|
304
308
|
worker,
|
|
305
309
|
})
|
|
306
310
|
}
|
|
307
311
|
}
|
|
308
312
|
if (replay !== undefined && !terminate) {
|
|
309
313
|
this.bindingCatalog = active.appliedBindingCatalog
|
|
310
|
-
?? active.priorBindingCatalog.advance(prepared)
|
|
314
|
+
?? active.priorBindingCatalog.advance(prepared, request.program)
|
|
311
315
|
}
|
|
312
316
|
this.active = undefined
|
|
313
317
|
if (terminate) void this.client.reset(worker)
|
|
@@ -353,6 +357,18 @@ class SessionKernel {
|
|
|
353
357
|
}
|
|
354
358
|
}
|
|
355
359
|
|
|
360
|
+
replMemoryFor(journal) {
|
|
361
|
+
const tentative = this.tentatives.get(journal)
|
|
362
|
+
if (journal.status === 'discarded'
|
|
363
|
+
|| journal.operations.some(operation => operation.action === 'restore')) {
|
|
364
|
+
return unavailableReplMemorySnapshot()
|
|
365
|
+
}
|
|
366
|
+
if (tentative === undefined) {
|
|
367
|
+
return createReplMemorySnapshot(this.bindingCatalog.snapshot())
|
|
368
|
+
}
|
|
369
|
+
return createReplMemorySnapshot(tentative.bindingCatalog.snapshot())
|
|
370
|
+
}
|
|
371
|
+
|
|
356
372
|
finishStateOperations(operations, index, worker) {
|
|
357
373
|
const transition = reduceStateOperations(this.history, operations, index)
|
|
358
374
|
this.history.head = transition.head
|
|
@@ -487,6 +503,7 @@ export class SessionRuntime {
|
|
|
487
503
|
journal,
|
|
488
504
|
kernel,
|
|
489
505
|
sessionId,
|
|
506
|
+
replMemory: kernel.replMemoryFor(journal),
|
|
490
507
|
...(result.recoveryBoundaries === undefined
|
|
491
508
|
? {}
|
|
492
509
|
: { recoveryBoundaries: result.recoveryBoundaries }),
|
|
@@ -19,11 +19,23 @@ export function transitionDurability(state, transition) {
|
|
|
19
19
|
|
|
20
20
|
export class BindingCatalog {
|
|
21
21
|
#known
|
|
22
|
+
#kinds
|
|
23
|
+
#definitions
|
|
22
24
|
#imports
|
|
23
25
|
#namespaces
|
|
24
26
|
|
|
25
|
-
constructor(
|
|
27
|
+
constructor(
|
|
28
|
+
known = new Set(),
|
|
29
|
+
imports = new Map(),
|
|
30
|
+
namespaces = new Set(),
|
|
31
|
+
kinds = new Map(),
|
|
32
|
+
definitions = new Map(),
|
|
33
|
+
) {
|
|
26
34
|
this.#known = new Set(known)
|
|
35
|
+
this.#kinds = new Map([...this.#known].map(name => [name, kinds.get(name) ?? 'variable']))
|
|
36
|
+
this.#definitions = new Map([...this.#known]
|
|
37
|
+
.filter(name => definitions.has(name))
|
|
38
|
+
.map(name => [name, definitions.get(name)]))
|
|
27
39
|
this.#imports = new Map(imports)
|
|
28
40
|
this.#namespaces = new Set(namespaces)
|
|
29
41
|
Object.freeze(this)
|
|
@@ -37,9 +49,76 @@ export class BindingCatalog {
|
|
|
37
49
|
}
|
|
38
50
|
}
|
|
39
51
|
|
|
40
|
-
advance(prepared) {
|
|
52
|
+
advance(prepared, source = undefined) {
|
|
41
53
|
const known = new Set(this.#known)
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
const kinds = new Map(this.#kinds)
|
|
55
|
+
const definitions = new Map(this.#definitions)
|
|
56
|
+
const touched = new Set()
|
|
57
|
+
const extractDefinition = sourceDefinitionExtractor(source)
|
|
58
|
+
for (const declaration of prepared.declarations ?? []) {
|
|
59
|
+
if (typeof declaration?.name !== 'string') continue
|
|
60
|
+
touched.add(declaration.name)
|
|
61
|
+
kinds.set(declaration.name, declaration.kind ?? 'variable')
|
|
62
|
+
const definition = extractDefinition(declaration.definitionSpan)
|
|
63
|
+
if (definition !== undefined) definitions.set(declaration.name, definition)
|
|
64
|
+
}
|
|
65
|
+
for (const name of prepared.declared) touched.add(name)
|
|
66
|
+
for (const name of touched) {
|
|
67
|
+
known.delete(name)
|
|
68
|
+
known.add(name)
|
|
69
|
+
}
|
|
70
|
+
return new BindingCatalog(known, prepared.imports, prepared.importNamespaces, kinds, definitions)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
snapshot() {
|
|
74
|
+
return [...this.#known].reverse()
|
|
75
|
+
.filter(name => !this.#namespaces.has(name))
|
|
76
|
+
.map(name => ({
|
|
77
|
+
name,
|
|
78
|
+
kind: this.#kinds.get(name) ?? 'variable',
|
|
79
|
+
...(this.#definitions.has(name) ? { definition: this.#definitions.get(name) } : {}),
|
|
80
|
+
}))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const MAX_DEFINITION_SOURCE_LENGTH = 1024
|
|
85
|
+
|
|
86
|
+
function lineOffsets(source) {
|
|
87
|
+
const offsets = [0]
|
|
88
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
89
|
+
if (source.charCodeAt(index) === 10) offsets.push(index + 1)
|
|
90
|
+
}
|
|
91
|
+
return offsets
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function offsetAt(offsets, sourceLength, position) {
|
|
95
|
+
if (position === null || typeof position !== 'object'
|
|
96
|
+
|| !Number.isSafeInteger(position.line) || position.line < 1
|
|
97
|
+
|| !Number.isSafeInteger(position.column) || position.column < 1
|
|
98
|
+
|| position.line > offsets.length) return undefined
|
|
99
|
+
const lineStart = offsets[position.line - 1]
|
|
100
|
+
const lineEnd = position.line < offsets.length ? offsets[position.line] - 1 : sourceLength
|
|
101
|
+
const offset = lineStart + position.column - 1
|
|
102
|
+
return offset <= lineEnd ? offset : undefined
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function sourceDefinitionExtractor(source) {
|
|
106
|
+
const offsets = typeof source === 'string' ? lineOffsets(source) : undefined
|
|
107
|
+
const extracted = new Map()
|
|
108
|
+
return span => {
|
|
109
|
+
if (offsets === undefined || span === null || typeof span !== 'object') return undefined
|
|
110
|
+
const start = offsetAt(offsets, source.length, span)
|
|
111
|
+
const end = offsetAt(offsets, source.length, span.end)
|
|
112
|
+
if (start === undefined || end === undefined || end <= start) return undefined
|
|
113
|
+
const key = `${start}:${end}`
|
|
114
|
+
if (extracted.has(key)) return extracted.get(key)
|
|
115
|
+
const length = end - start
|
|
116
|
+
const bounded = length <= MAX_DEFINITION_SOURCE_LENGTH
|
|
117
|
+
? source.slice(start, end)
|
|
118
|
+
: `${source.slice(start, start + MAX_DEFINITION_SOURCE_LENGTH - 3)}...`
|
|
119
|
+
if (bounded.length === 0) return undefined
|
|
120
|
+
const definition = Object.freeze({ source: bounded, line: span.line, column: span.column })
|
|
121
|
+
extracted.set(key, definition)
|
|
122
|
+
return definition
|
|
44
123
|
}
|
|
45
124
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Install an optional settings section across current and legacy DSH settings APIs. */
|
|
2
|
+
export function installSettingsSectionCompat({
|
|
3
|
+
ctx,
|
|
4
|
+
settingsModule,
|
|
5
|
+
namespace,
|
|
6
|
+
schema,
|
|
7
|
+
entry,
|
|
8
|
+
hooks,
|
|
9
|
+
onProvider,
|
|
10
|
+
}) {
|
|
11
|
+
ctx.inject(['settings'], settingsContext => {
|
|
12
|
+
const provider = settingsContext.settings
|
|
13
|
+
onProvider(provider)
|
|
14
|
+
if (typeof provider?.installSection === 'function') {
|
|
15
|
+
provider.installSection(ctx, namespace, schema, entry, hooks)
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
if (typeof settingsModule?.installSettingsSection !== 'function') {
|
|
19
|
+
throw new Error('ptc-plus: incompatible settings service; expected installSection or installSettingsSection')
|
|
20
|
+
}
|
|
21
|
+
const mountedOwner = new Proxy(ctx, {
|
|
22
|
+
get(target, property) {
|
|
23
|
+
if (property === 'inject') {
|
|
24
|
+
return (_services, attach) => attach(settingsContext)
|
|
25
|
+
}
|
|
26
|
+
return Reflect.get(target, property, target)
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
settingsModule.installSettingsSection(mountedOwner, namespace, schema, entry, hooks)
|
|
30
|
+
})
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ptc-plus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "A session-bound agent-native REPL for DeepSeek Harness PTC mode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -15,17 +15,23 @@
|
|
|
15
15
|
"src",
|
|
16
16
|
"internal",
|
|
17
17
|
"docs",
|
|
18
|
-
"assets/dsh-ptc-plus-banner.webp",
|
|
19
|
-
"assets/ptc-plus-
|
|
20
|
-
"assets/ptc-plus-
|
|
18
|
+
"assets/dsh-ptc-plus-banner-en.webp",
|
|
19
|
+
"assets/dsh-ptc-plus-banner-zh.webp",
|
|
20
|
+
"assets/ptc-plus-repair-zh.png",
|
|
21
|
+
"assets/ptc-plus-repair-en.png",
|
|
22
|
+
"assets/ptc-plus-settings-en.png",
|
|
23
|
+
"assets/ptc-plus-settings-zh.png",
|
|
21
24
|
"cordis.patch.yml",
|
|
22
25
|
"README.md",
|
|
23
|
-
"README.
|
|
26
|
+
"README.en.md",
|
|
24
27
|
"LICENSE"
|
|
25
28
|
],
|
|
26
29
|
"engines": {
|
|
27
30
|
"node": "^22.19.0 || >=24.0.0"
|
|
28
31
|
},
|
|
32
|
+
"allowScripts": {
|
|
33
|
+
"esbuild": false
|
|
34
|
+
},
|
|
29
35
|
"dependencies": {
|
|
30
36
|
"@babel/code-frame": "^7.29.7",
|
|
31
37
|
"@babel/parser": "^7.29.0",
|
|
@@ -34,10 +40,10 @@
|
|
|
34
40
|
"acorn": "^8.15.0"
|
|
35
41
|
},
|
|
36
42
|
"peerDependencies": {
|
|
37
|
-
"@deepseek-ai/dsh-settings": "
|
|
38
|
-
"@deepseek-ai/dsh-skill-filesystem": "
|
|
39
|
-
"@deepseek-ai/dsh-tool-cordis": "
|
|
40
|
-
"@deepseek-ai/dsh-tools": "
|
|
43
|
+
"@deepseek-ai/dsh-settings": "*",
|
|
44
|
+
"@deepseek-ai/dsh-skill-filesystem": "*",
|
|
45
|
+
"@deepseek-ai/dsh-tool-cordis": "*",
|
|
46
|
+
"@deepseek-ai/dsh-tools": "*"
|
|
41
47
|
},
|
|
42
48
|
"scripts": {
|
|
43
49
|
"build": "node scripts/client-bundle.mjs build",
|
|
@@ -82,6 +88,7 @@
|
|
|
82
88
|
],
|
|
83
89
|
"inject": [
|
|
84
90
|
"@deepseek-ai/dsh-client-runtime",
|
|
91
|
+
"@deepseek-ai/dsh-client-locale",
|
|
85
92
|
"@deepseek-ai/dsh-client-ui-settings",
|
|
86
93
|
"@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
87
94
|
"@deepseek-ai/dsh-client-connection",
|
|
@@ -90,10 +97,10 @@
|
|
|
90
97
|
}
|
|
91
98
|
},
|
|
92
99
|
"devDependencies": {
|
|
93
|
-
"@deepseek-ai/dsh-settings": "
|
|
94
|
-
"@deepseek-ai/dsh-skill-filesystem": "
|
|
95
|
-
"@deepseek-ai/dsh-tool-cordis": "
|
|
96
|
-
"@deepseek-ai/dsh-tools": "
|
|
100
|
+
"@deepseek-ai/dsh-settings": "alpha",
|
|
101
|
+
"@deepseek-ai/dsh-skill-filesystem": "alpha",
|
|
102
|
+
"@deepseek-ai/dsh-tool-cordis": "alpha",
|
|
103
|
+
"@deepseek-ai/dsh-tools": "alpha",
|
|
97
104
|
"esbuild": "0.28.2",
|
|
98
105
|
"yaml": "^2.9.0"
|
|
99
106
|
}
|