@sparkelf/dsh-patch-legacy-code-preset 0.1.0-rc.12
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/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +9 -0
- package/README.zh.md +9 -0
- package/package.json +38 -0
- package/patches/legacy-code-preset.patch +160 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write patches/npm/legacy-code-preset/README.md
|
|
5
|
+
README.md: dd7d80a595574e0c3b0d63379221ce7d53676976
|
|
6
|
+
README.zh.md: 80834862a9a18ca6cda3330f7772c5264ad168c3
|
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @sparkelf/dsh-patch-legacy-code-preset
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
This data-only package preserves sessions created before the official `code` agent preset was renamed to `ptc`. Resume first resolves a real `code` preset, then falls back to `ptc` only when `code` is absent; the browser labels that persisted legacy id as the localized PTC preset. Session logs remain unchanged.
|
|
6
|
+
|
|
7
|
+
The target is exact official source revision `0a53fb55bea101816fa226bb964ae2bed71c343b`. The payload is applied before that source tree is built. The package has no JavaScript entry, lifecycle script, Cordis plugin, accepted-fork fallback, or alternate variant.
|
|
8
|
+
|
|
9
|
+
Retire this package when official DSH provides equivalent legacy preset resolution and display behavior.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @sparkelf/dsh-patch-legacy-code-preset
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
该data-only package让official `code` agent preset改名为`ptc`之前创建的会话仍可恢复。恢复时先解析真实存在的`code` preset;只有`code`不存在时才回退到`ptc`。浏览器把该持久化旧id显示为本地化PTC preset,Session日志保持原样。
|
|
6
|
+
|
|
7
|
+
target是exact official source revision `0a53fb55bea101816fa226bb964ae2bed71c343b`,payload在该source tree build前应用。本package没有JavaScript entry、lifecycle script、Cordis plugin、accepted-fork fallback或alternate variant。
|
|
8
|
+
|
|
9
|
+
official DSH提供同等legacy preset解析与显示行为后,retire本package。
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Data-only exact official-source patch mapping persisted legacy code presets to PTC without rewriting Session logs",
|
|
3
|
+
"dshPatch": {
|
|
4
|
+
"formatVersion": 1,
|
|
5
|
+
"variants": [
|
|
6
|
+
{
|
|
7
|
+
"dsh": ">=0.1.2-alpha.2",
|
|
8
|
+
"file": "./patches/legacy-code-preset.patch",
|
|
9
|
+
"id": "legacy-code-preset-ptc-compatibility",
|
|
10
|
+
"target": {
|
|
11
|
+
"baseRevision": "0a53fb55bea101816fa226bb964ae2bed71c343b",
|
|
12
|
+
"kind": "dsh-source",
|
|
13
|
+
"paths": [
|
|
14
|
+
"packages/api/session-controller/src/",
|
|
15
|
+
"packages/api/session-controller/tests/",
|
|
16
|
+
"packages/client/ui-agent-preset/src/",
|
|
17
|
+
"packages/client/ui-agent-preset/tests/"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"patches/*.patch"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"name": "@sparkelf/dsh-patch-legacy-code-preset",
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"directory": "patches/npm/legacy-code-preset",
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/SparkElf/deepseek-harness-plus.git"
|
|
35
|
+
},
|
|
36
|
+
"type": "module",
|
|
37
|
+
"version": "0.1.0-rc.12"
|
|
38
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
diff --git a/packages/api/session-controller/src/agent.ts b/packages/api/session-controller/src/agent.ts
|
|
2
|
+
index c17929af5c..8fd0e9e590 100644
|
|
3
|
+
--- a/packages/api/session-controller/src/agent.ts
|
|
4
|
+
+++ b/packages/api/session-controller/src/agent.ts
|
|
5
|
+
@@ -11,10 +11,13 @@ import type {} from '@deepseek-ai/dsh-agent-presets'
|
|
6
|
+
import { ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
|
7
|
+
import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'
|
|
8
|
+
import { SessionQueryError, type SessionObservation } from '@deepseek-ai/dsh-session-query'
|
|
9
|
+
-import { RemoteError } from '@deepseek-ai/dsh-typert-protocol'
|
|
10
|
+
+import { RemoteError, remoteErrorOf } from '@deepseek-ai/dsh-typert-protocol'
|
|
11
|
+
import type {} from '@deepseek-ai/dsh-typert-registry'
|
|
12
|
+
import type { ModelSelection } from './types.ts'
|
|
13
|
+
|
|
14
|
+
+const LEGACY_PTC_PRESET = 'code'
|
|
15
|
+
+const PTC_PRESET = 'ptc'
|
|
16
|
+
+
|
|
17
|
+
/** Cold Session identity absent from persistence. */
|
|
18
|
+
export class ApiSessionNotFound extends Error {}
|
|
19
|
+
|
|
20
|
+
@@ -372,7 +375,15 @@ export class ApiSessionAgentController {
|
|
21
|
+
}> {
|
|
22
|
+
const presets = this.ctx.get('agentPresets')
|
|
23
|
+
if (presets === undefined) return { setup: (agentCtx) => { this.installSelection(agentCtx) } }
|
|
24
|
+
- const resolvedId = (await presets.resolve(presetId)).id
|
|
25
|
+
+ let resolved
|
|
26
|
+
+ try {
|
|
27
|
+
+ resolved = await presets.resolve(presetId)
|
|
28
|
+
+ } catch (error: unknown) {
|
|
29
|
+
+ if (presetId !== LEGACY_PTC_PRESET
|
|
30
|
+
+ || remoteErrorOf(error)?.code !== 'agent-preset/not-found') throw error
|
|
31
|
+
+ resolved = await presets.resolve(PTC_PRESET)
|
|
32
|
+
+ }
|
|
33
|
+
+ const resolvedId = resolved.id
|
|
34
|
+
return {
|
|
35
|
+
agentPreset: resolvedId,
|
|
36
|
+
setup: async (agentCtx) => {
|
|
37
|
+
diff --git a/packages/api/session-controller/tests/agent.host.spec.ts b/packages/api/session-controller/tests/agent.host.spec.ts
|
|
38
|
+
index 6bfea1609d..62bdef2405 100644
|
|
39
|
+
--- a/packages/api/session-controller/tests/agent.host.spec.ts
|
|
40
|
+
+++ b/packages/api/session-controller/tests/agent.host.spec.ts
|
|
41
|
+
@@ -8,6 +8,7 @@ import { agentPresetProjectionDefinition } from '@deepseek-ai/dsh-agent-presets'
|
|
42
|
+
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
|
|
43
|
+
import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session'
|
|
44
|
+
import type { SessionObservation } from '@deepseek-ai/dsh-session-query'
|
|
45
|
+
+import { RemoteError } from '@deepseek-ai/dsh-typert-protocol'
|
|
46
|
+
import TypertRegistry from '@deepseek-ai/dsh-typert-registry'
|
|
47
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
48
|
+
import {
|
|
49
|
+
@@ -390,6 +391,38 @@ describe('ApiSession create or adoption', () => {
|
|
50
|
+
expect(resume).toHaveBeenCalledWith(expect.objectContaining({ resumeSessionId: meta.id }))
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
+ it('resumes a persisted legacy code session through the ptc composition', async () => {
|
|
54
|
+
+ const { ctx, agents } = await harness()
|
|
55
|
+
+ const meta = { ...header('stored-legacy-code'), agentPreset: 'code' }
|
|
56
|
+
+ providePersistence(ctx, {
|
|
57
|
+
+ list: () => Promise.resolve([meta]),
|
|
58
|
+
+ inspect: () => Promise.resolve({ meta, events: [] }),
|
|
59
|
+
+ })
|
|
60
|
+
+ const resolve = vi.fn((id?: string) => id === 'code'
|
|
61
|
+
+ ? Promise.reject(new RemoteError(
|
|
62
|
+
+ 'agent-preset/not-found',
|
|
63
|
+
+ 'code is no longer shipped',
|
|
64
|
+
+ { agentPreset: 'code', available: ['ptc'] },
|
|
65
|
+
+ ))
|
|
66
|
+
+ : Promise.resolve({ id: id ?? 'ptc' }))
|
|
67
|
+
+ ctx.provide('agentPresets', { resolve, mount: () => Promise.resolve() } as never)
|
|
68
|
+
+ const resumed = {
|
|
69
|
+
+ id: meta.id,
|
|
70
|
+
+ session: { id: meta.id, header: meta, events: [] },
|
|
71
|
+
+ status: 'idle',
|
|
72
|
+
+ ctx,
|
|
73
|
+
+ } as unknown as Agent
|
|
74
|
+
+ vi.spyOn(ctx.agents, 'resume').mockResolvedValue({
|
|
75
|
+
+ agent: resumed,
|
|
76
|
+
+ dispose: () => Promise.resolve(),
|
|
77
|
+
+ })
|
|
78
|
+
+
|
|
79
|
+
+ await expect(agents.resolveAgent(meta.id)).resolves.toEqual({ agent: resumed })
|
|
80
|
+
+ expect(resolve).toHaveBeenNthCalledWith(1, 'code')
|
|
81
|
+
+ expect(resolve).toHaveBeenNthCalledWith(2, 'ptc')
|
|
82
|
+
+ expect(resumed.session.header.agentPreset).toBe('code')
|
|
83
|
+
+ })
|
|
84
|
+
+
|
|
85
|
+
it('rejects an ownership race before resume and a persisted cwd conflict', async () => {
|
|
86
|
+
const child = await harness()
|
|
87
|
+
const childMeta = header('resume-child-race')
|
|
88
|
+
@@ -431,4 +464,29 @@ describe('ApiSession create or adoption', () => {
|
|
89
|
+
const composition = await agents.composeAgent(undefined)
|
|
90
|
+
expect(() => composition.setup(new Context())).toThrow('Agent setup has no scoped Agent')
|
|
91
|
+
})
|
|
92
|
+
+
|
|
93
|
+
+ it('falls back from a missing legacy code preset to ptc', async () => {
|
|
94
|
+
+ const { ctx, agents } = await harness()
|
|
95
|
+
+ const resolve = vi.fn((id?: string) => id === 'code'
|
|
96
|
+
+ ? Promise.reject(new RemoteError(
|
|
97
|
+
+ 'agent-preset/not-found',
|
|
98
|
+
+ 'code is no longer shipped',
|
|
99
|
+
+ { agentPreset: 'code', available: ['ptc'] },
|
|
100
|
+
+ ))
|
|
101
|
+
+ : Promise.resolve({ id: id ?? 'ptc' }))
|
|
102
|
+
+ ctx.provide('agentPresets', { resolve, mount: () => Promise.resolve() } as never)
|
|
103
|
+
+
|
|
104
|
+
+ await expect(agents.composeAgent('code')).resolves.toMatchObject({ agentPreset: 'ptc' })
|
|
105
|
+
+ expect(resolve).toHaveBeenNthCalledWith(1, 'code')
|
|
106
|
+
+ expect(resolve).toHaveBeenNthCalledWith(2, 'ptc')
|
|
107
|
+
+ })
|
|
108
|
+
+
|
|
109
|
+
+ it('prefers an explicitly available code preset over the ptc fallback', async () => {
|
|
110
|
+
+ const { ctx, agents } = await harness()
|
|
111
|
+
+ const resolve = vi.fn((id?: string) => Promise.resolve({ id: id ?? 'ptc' }))
|
|
112
|
+
+ ctx.provide('agentPresets', { resolve, mount: () => Promise.resolve() } as never)
|
|
113
|
+
+
|
|
114
|
+
+ await expect(agents.composeAgent('code')).resolves.toMatchObject({ agentPreset: 'code' })
|
|
115
|
+
+ expect(resolve).toHaveBeenCalledExactlyOnceWith('code')
|
|
116
|
+
+ })
|
|
117
|
+
})
|
|
118
|
+
diff --git a/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx b/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx
|
|
119
|
+
index b40453e94a..0f22c6d0fc 100644
|
|
120
|
+
--- a/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx
|
|
121
|
+
+++ b/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx
|
|
122
|
+
@@ -19,6 +19,8 @@ import type { AgentPresetSettingsState } from './settings-store.ts'
|
|
123
|
+
import { presetDisplayText } from './locales.ts'
|
|
124
|
+
import css from './AgentPresetLabel.module.css'
|
|
125
|
+
|
|
126
|
+
+const LEGACY_PTC_PRESET = 'code'
|
|
127
|
+
+
|
|
128
|
+
/** Registration-side business face for the header label. */
|
|
129
|
+
export interface AgentPresetLabelInjected {
|
|
130
|
+
hooks: {
|
|
131
|
+
@@ -59,10 +61,11 @@ export function AgentPresetLabel({
|
|
132
|
+
|
|
133
|
+
const option = options.find(entry => entry.id === preset)
|
|
134
|
+
const text = option === undefined ? undefined : presetDisplayText(option, t)
|
|
135
|
+
+ const name = text?.name ?? (preset === LEGACY_PTC_PRESET ? t('presetPtcName') : preset)
|
|
136
|
+
return (
|
|
137
|
+
<span className={css.label} title={text?.description ?? t('headerHint')}>
|
|
138
|
+
<IconAgentPresetOutline16 size={14} className={css.icon} />
|
|
139
|
+
- {text?.name ?? preset}
|
|
140
|
+
+ {name}
|
|
141
|
+
</span>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
diff --git a/packages/client/ui-agent-preset/tests/components.client.spec.tsx b/packages/client/ui-agent-preset/tests/components.client.spec.tsx
|
|
145
|
+
index 5a3904efa3..c28e33565f 100644
|
|
146
|
+
--- a/packages/client/ui-agent-preset/tests/components.client.spec.tsx
|
|
147
|
+
+++ b/packages/client/ui-agent-preset/tests/components.client.spec.tsx
|
|
148
|
+
@@ -302,6 +302,12 @@ describe('the session-header label', () => {
|
|
149
|
+
expect(screen.getByTitle(en.headerHint).textContent).toBe('mine')
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
+ it('labels a persisted legacy code preset as PTC mode', () => {
|
|
153
|
+
+ renderLabel({ blank: false, projectionValues: { agentPreset: 'code' } })
|
|
154
|
+
+
|
|
155
|
+
+ expect(screen.getByTitle(en.headerHint).textContent).toBe(en.presetPtcName)
|
|
156
|
+
+ })
|
|
157
|
+
+
|
|
158
|
+
it('shows the id until the roster resolves it', () => {
|
|
159
|
+
renderLabel({
|
|
160
|
+
blank: false,
|