dsh-embedded-workbench 0.8.12 → 0.9.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-US.md +32 -9
- package/README.md +32 -9
- package/cordis.patch.yml +4 -0
- package/lib/client.js +214 -0
- package/lib/index.js +242 -211
- package/lib/types/index.d.ts +59 -51
- package/package.json +52 -33
- package/skills/embedded-workbench/SKILL.md +63 -78
- package/skills/embedded-workbench/references/platform-tool-mapping.md +59 -22
- package/skills/embedded-workbench/references/proactive-suggestions.md +27 -0
- package/src/client.js +214 -0
- package/src/index.ts +79 -35
package/lib/index.js
CHANGED
|
@@ -1,215 +1,246 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* embedded-workbench — DeepSeek Harness native plugin for the Embedded
|
|
3
|
-
* Workbench toolbox.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import {
|
|
31
|
-
import
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
1
|
+
/**
|
|
2
|
+
* embedded-workbench — DeepSeek Harness native plugin for the Embedded
|
|
3
|
+
* Workbench toolbox. The 8 skills ship in this package's `skills/` directory
|
|
4
|
+
* and are registered at apply time into dsh's `ctx.skills` registry through
|
|
5
|
+
* the standard filesystem provider, so they appear in every session catalog
|
|
6
|
+
* without a manual copy step. The plugin also folds a short gate text into the
|
|
7
|
+
* first model step of every agent session, mirroring the SessionStart hook the
|
|
8
|
+
* Claude Code plugin installs.
|
|
9
|
+
*
|
|
10
|
+
* Injection listens on agent/pre-step and appends the gate to the FIRST
|
|
11
|
+
* model step that runs, once per session (guarded by the session's durable
|
|
12
|
+
* history). Session-start inbox injection was dropped: a blank-session preset
|
|
13
|
+
* switch (agentPreset.select -> recompose) can clear the inbox before the
|
|
14
|
+
* first step, losing the gate for the whole session. The pre-step decision is
|
|
15
|
+
* the durable path - anchored/bootstrap presets that strip first-step injected
|
|
16
|
+
* reminders (skill catalog, AGENTS.md, gate plugins) simply defer this message
|
|
17
|
+
* to the first step after their promotion, and the history guard re-injects it
|
|
18
|
+
* there. The default gate text is the dsh-native adaptation of
|
|
19
|
+
* `hooks/session-start-content.md`: the behavior rules stay in sync (the Plan
|
|
20
|
+
* Verification Gate and the context-budget rule), while presentation is adapted
|
|
21
|
+
* to dsh's native skill catalog — no roster table (the model sees skills in its
|
|
22
|
+
* catalog) and no install instructions (those live in `.dsh/INSTALL.md`). The
|
|
23
|
+
* payload is deliberately small: it carries the verification gate and the
|
|
24
|
+
* budget rule, not the 1% Rule / Red Flags enforcement scaffolding, which
|
|
25
|
+
* measurably pushes capable models into rigid phases and unnecessary fan-out.
|
|
26
|
+
* Deployments override via Config.
|
|
27
|
+
*
|
|
28
|
+
* @module embedded-workbench-dsh
|
|
29
|
+
*/
|
|
30
|
+
import { fileURLToPath } from 'node:url';
|
|
31
|
+
import z from '@deepseek-ai/schemastery';
|
|
32
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
33
|
+
import { FileSystemSkillProvider } from '@deepseek-ai/dsh-skill-filesystem';
|
|
34
|
+
export const name = 'embedded-workbench';
|
|
35
|
+
// Skills are contributed through the registry service, which dsh-base always
|
|
36
|
+
// mounts before bundle rows such as this one apply.
|
|
37
|
+
export const inject = ['skills'];
|
|
38
|
+
// Absolute path of the package's shipped skills directory. `lib/index.js`
|
|
39
|
+
// lives one level below the package root, so `../skills` from the module URL
|
|
40
|
+
// lands on `<package>/skills` regardless of where the package was installed.
|
|
41
|
+
const SKILLS_DIR = fileURLToPath(new URL('../skills', import.meta.url));
|
|
42
|
+
const GATE_PLUGIN_ID = 'embedded-workbench';
|
|
43
|
+
/** Producer-owned message source kind declared in `MessageSourceMap` above. */
|
|
44
|
+
const GATE_SOURCE_KIND = 'plugin:embedded-workbench';
|
|
43
45
|
const DEFAULT_GATE_CONTENT = `<EXTREMELY_IMPORTANT>
|
|
44
|
-
Plugin embedded-workbench is active
|
|
46
|
+
Plugin embedded-workbench is active: embedded C/C++ firmware development skills are in your skill catalog. Load the one whose "Use when" matches before substantial work, with the skill tool.
|
|
45
47
|
|
|
46
|
-
**
|
|
48
|
+
**Plan Verification Gate**: before calling exit_plan_mode (or presenting a plan for approval), load the logicprobe skill — or the built-in fact-check skill when logicprobe is not installed — and append a "## Plan Verification" block to the plan. If you verify with neither, tell the user the plan is unverified before asking for approval; a silent skip is not an option. "This change is too small to check" and "I already read the code, the paths are right" are the two rationalizations this gate exists to catch.
|
|
47
49
|
|
|
48
|
-
**
|
|
50
|
+
**Context budget**: no token meter is visible to you, so never guess one. Act on what you can see — a pruned or spilled tool result means stop pulling it in whole, and a compaction checkpoint means move durable state into files. When a large step (many sources, a long sweep, several independent areas) shows no such signal, ask the user what to spend context on rather than deciding silently. If nobody can answer, take the reversible option and say so. When you do delegate, prefer \`subagent_fork\` over \`subagent\` if the sub-agent needs context you already built — its summary still lands here.
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
function
|
|
96
|
-
return {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
52
|
+
To load the workflows and engineering policies behind these skills: load the embedded-workbench skill.
|
|
53
|
+
</EXTREMELY_IMPORTANT>`;
|
|
54
|
+
/**
|
|
55
|
+
* Declare a field as live where this host's schemastery can — `.volatile()`
|
|
56
|
+
* arrived in 3.18.3 — and leave it an ordinary field where it cannot.
|
|
57
|
+
*
|
|
58
|
+
* The fallback is load-bearing, not defensive padding. `Config` below is built
|
|
59
|
+
* while this module is still being evaluated, so an unconditional `.volatile()`
|
|
60
|
+
* on a host shipping schemastery 3.18.2 (measured: dsh 0.1.5-rc.2 and
|
|
61
|
+
* 0.1.5-rc.3) throws during import; the loader entry then fails and takes the
|
|
62
|
+
* WHOLE plugin tree — and the host's boot — down with it. Degrading costs only
|
|
63
|
+
* the Plugins-page switch, because the settings service projects nothing but
|
|
64
|
+
* fields under a `.volatile()` node; the skills and the gate injection are
|
|
65
|
+
* untouched. The returned schema keeps the plain field's static type; the
|
|
66
|
+
* `Config` interface below carries the union the host actually hands over.
|
|
67
|
+
*/
|
|
68
|
+
function live(field) {
|
|
69
|
+
const probe = field;
|
|
70
|
+
return typeof probe.volatile === 'function' ? probe.volatile() : field;
|
|
71
|
+
}
|
|
72
|
+
export const Config = z.object({
|
|
73
|
+
// Live so the Web Plugins page can flip the gate injection inside a running
|
|
74
|
+
// session: dsh's settings service projects ONLY fields under a `.volatile()`
|
|
75
|
+
// node and rejects writes to every other path. The price is that the injection
|
|
76
|
+
// reads the reference per step instead of deciding once at mount, which is also
|
|
77
|
+
// what lets a toggle take effect without remounting the row.
|
|
78
|
+
//
|
|
79
|
+
// On by default, but deliberately small: the payload carries the verification
|
|
80
|
+
// gate and the context-budget rule only, so leaving it on costs a few hundred
|
|
81
|
+
// tokens once per session rather than the ~900 of the previous payload.
|
|
82
|
+
enabled: live(z.boolean().default(true)),
|
|
83
|
+
// Not volatile, deliberately: the settings projection feeds a GUI form, and a
|
|
84
|
+
// multi-kilobyte text field does not belong in one. Override it in the
|
|
85
|
+
// profile's `cordis.patch.yml` row instead.
|
|
86
|
+
gateContent: z.string().default(DEFAULT_GATE_CONTENT),
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* Read the injection switch as a boolean, whichever shape this host produced.
|
|
90
|
+
* @param config - the resolved plugin configuration.
|
|
91
|
+
* @returns whether the gate may be injected.
|
|
92
|
+
*/
|
|
93
|
+
function injectionEnabled(config) {
|
|
94
|
+
const value = config.enabled;
|
|
95
|
+
return typeof value === 'boolean' ? value : value.get();
|
|
96
|
+
}
|
|
97
|
+
function gateMessage(text) {
|
|
98
|
+
return createUserMessage({
|
|
99
|
+
content: [{ type: 'text', text }],
|
|
100
|
+
// `form` omitted — an undeclared context is the documented default.
|
|
101
|
+
source: { kind: GATE_SOURCE_KIND },
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function readSessionEvents(session) {
|
|
105
|
+
const source = session;
|
|
106
|
+
if (typeof source.snapshotEvents === 'function') {
|
|
107
|
+
const snapshot = source.snapshotEvents();
|
|
108
|
+
if (Array.isArray(snapshot))
|
|
109
|
+
return snapshot;
|
|
110
|
+
}
|
|
111
|
+
if (Array.isArray(source.events))
|
|
112
|
+
return source.events;
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Model-visible catalog entry (cordis_inspect_list / cordis_inspect_query):
|
|
117
|
+
* lets the model read this plugin's runtime status without guessing. Mirrors
|
|
118
|
+
* the registration pattern of the official dsh-tool-cordis host providers.
|
|
119
|
+
*/
|
|
120
|
+
function inspectProvider(config) {
|
|
121
|
+
return {
|
|
122
|
+
manifest: {
|
|
123
|
+
id: 'embedded-workbench',
|
|
124
|
+
description: 'Session-start gate injection for the Embedded Workbench toolbox — folds the Plan Verification Gate and the context-budget rule into the first model step of every agent session.',
|
|
125
|
+
methods: [
|
|
126
|
+
{
|
|
127
|
+
name: 'status',
|
|
128
|
+
description: 'Read whether the gate injection is active and how large the injected gate text is.',
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: 'object',
|
|
131
|
+
properties: {},
|
|
132
|
+
additionalProperties: false,
|
|
133
|
+
},
|
|
134
|
+
outputSchema: {
|
|
135
|
+
type: 'object',
|
|
136
|
+
description: 'Gate-injection plugin status.',
|
|
137
|
+
properties: {
|
|
138
|
+
enabled: { type: 'boolean', description: 'Whether the gate folds into the first model step.' },
|
|
139
|
+
gateContentLength: { type: 'integer', description: 'Length in characters of the injected gate text.' },
|
|
140
|
+
},
|
|
141
|
+
required: ['enabled', 'gateContentLength'],
|
|
142
|
+
additionalProperties: false,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
query: async (method) => {
|
|
148
|
+
if (method === 'status') {
|
|
149
|
+
return {
|
|
150
|
+
enabled: injectionEnabled(config),
|
|
151
|
+
gateContentLength: config.gateContent.length,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
export function apply(ctx, config) {
|
|
159
|
+
// Catalog visibility is optional: register only when the inspect registry
|
|
160
|
+
// service is mounted, so headless assemblies without it keep the gate
|
|
161
|
+
// injection working. The registry may be provided AFTER this row applies
|
|
162
|
+
// (base-bundle rows can mount later), so registration is retried on the
|
|
163
|
+
// first agent/session-start — by then the app is fully booted.
|
|
164
|
+
let providerRegistered = false;
|
|
165
|
+
const registerProvider = () => {
|
|
166
|
+
if (providerRegistered)
|
|
167
|
+
return;
|
|
168
|
+
const inspect = ctx.get('cordisInspect');
|
|
169
|
+
if (inspect === undefined)
|
|
170
|
+
return;
|
|
171
|
+
try {
|
|
172
|
+
ctx.effect(() => inspect.register(inspectProvider(config)), 'embedded-workbench: inspect provider');
|
|
173
|
+
providerRegistered = true;
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
console.warn('[embedded-workbench] inspect provider registration failed', err);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
registerProvider();
|
|
180
|
+
// Ship the bundled skills through the registry: reuse the standard
|
|
181
|
+
// filesystem provider over this package's own `skills/` directory, so
|
|
182
|
+
// catalog discovery, frontmatter parsing, and SKILL.md loading behave
|
|
183
|
+
// exactly like project/user skills while the plugin stays self-contained.
|
|
184
|
+
// Registration lands in the global registry layer (this row mounts at the
|
|
185
|
+
// profile root), so every agent preset sees the skills. `registerProvider`
|
|
186
|
+
// returns the effect disposer; its teardown unregisters and invalidates.
|
|
187
|
+
ctx.skills.registerProvider((control) => {
|
|
188
|
+
return new FileSystemSkillProvider(ctx, control, {
|
|
189
|
+
providerName: 'embedded-workbench',
|
|
190
|
+
includeDefaultRoots: false,
|
|
191
|
+
customSkillDirs: [SKILLS_DIR],
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
// Injection listens unconditionally, including while the switch is off: the
|
|
195
|
+
// switch is volatile, so `apply` runs once and the value behind it can turn on
|
|
196
|
+
// later from the Web Plugins page. Returning early on a false value here would
|
|
197
|
+
// freeze that decision for the lifetime of the mount, and turning the switch
|
|
198
|
+
// back on could never take effect without a profile restart.
|
|
199
|
+
//
|
|
200
|
+
// Inject the gate once per session on the FIRST model step that runs,
|
|
201
|
+
// instead of at session-start: session-start injection lands in the agent's
|
|
202
|
+
// inbox, which a blank-session preset switch (agentPreset.select ->
|
|
203
|
+
// recompose) can clear before the first step - the gate would then be lost
|
|
204
|
+
// for the whole session. The pre-step decision is the durable path a
|
|
205
|
+
// first-step injection takes: the gate is appended to the first step's
|
|
206
|
+
// decision and enters session history there, so every later step (and a
|
|
207
|
+
// resume) skips it. Anchored/bootstrap presets that strip first-step
|
|
208
|
+
// injected reminders (skill catalog, AGENTS.md, gate plugins) simply defer
|
|
209
|
+
// this message to the first step after their promotion - the history guard
|
|
210
|
+
// re-injects it there, so the gate still lands exactly once per session.
|
|
211
|
+
ctx.on('agent/pre-step', async ({ agent }, next) => {
|
|
212
|
+
const decision = await next();
|
|
213
|
+
if (decision.kind === 'reject')
|
|
214
|
+
return decision;
|
|
215
|
+
registerProvider();
|
|
216
|
+
if (!injectionEnabled(config))
|
|
217
|
+
return decision;
|
|
218
|
+
if (gateInHistory(agent.session))
|
|
219
|
+
return decision;
|
|
220
|
+
return {
|
|
221
|
+
kind: 'enter',
|
|
222
|
+
messages: [...decision.messages, gateMessage(config.gateContent)],
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Whether the gate already entered this session's durable history. The
|
|
228
|
+
* pre-step listener re-appends the gate until it does; once a step committed
|
|
229
|
+
* it, every later step (and a resume of a session that kept it) skips the
|
|
230
|
+
* injection. A session whose gate was dropped before any step ran (e.g. an
|
|
231
|
+
* inbox cleared by a blank-session preset switch) simply re-injects on the
|
|
232
|
+
* first step that runs.
|
|
233
|
+
*/
|
|
234
|
+
function gateInHistory(session) {
|
|
235
|
+
return readSessionEvents(session).some((event) => {
|
|
236
|
+
if (event.type !== 'user/message')
|
|
237
|
+
return false;
|
|
238
|
+
const source = event.data?.source;
|
|
239
|
+
if (source === undefined)
|
|
240
|
+
return false;
|
|
241
|
+
// The v4 producer-owned kind, plus the pre-v4 wrapper this bundle wrote
|
|
242
|
+
// before DSH 0.1.7-alpha.1 retired it.
|
|
243
|
+
return source.kind === GATE_SOURCE_KIND
|
|
244
|
+
|| (source.kind === 'plugin' && source.plugin === GATE_PLUGIN_ID);
|
|
245
|
+
});
|
|
246
|
+
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,51 +1,59 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* embedded-workbench — DeepSeek Harness native plugin for the Embedded
|
|
3
|
-
* Workbench toolbox.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import type {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
1
|
+
/**
|
|
2
|
+
* embedded-workbench — DeepSeek Harness native plugin for the Embedded
|
|
3
|
+
* Workbench toolbox. The 8 skills ship in this package's `skills/` directory
|
|
4
|
+
* and are registered at apply time into dsh's `ctx.skills` registry through
|
|
5
|
+
* the standard filesystem provider, so they appear in every session catalog
|
|
6
|
+
* without a manual copy step. The plugin also folds a short gate text into the
|
|
7
|
+
* first model step of every agent session, mirroring the SessionStart hook the
|
|
8
|
+
* Claude Code plugin installs.
|
|
9
|
+
*
|
|
10
|
+
* Injection listens on agent/pre-step and appends the gate to the FIRST
|
|
11
|
+
* model step that runs, once per session (guarded by the session's durable
|
|
12
|
+
* history). Session-start inbox injection was dropped: a blank-session preset
|
|
13
|
+
* switch (agentPreset.select -> recompose) can clear the inbox before the
|
|
14
|
+
* first step, losing the gate for the whole session. The pre-step decision is
|
|
15
|
+
* the durable path - anchored/bootstrap presets that strip first-step injected
|
|
16
|
+
* reminders (skill catalog, AGENTS.md, gate plugins) simply defer this message
|
|
17
|
+
* to the first step after their promotion, and the history guard re-injects it
|
|
18
|
+
* there. The default gate text is the dsh-native adaptation of
|
|
19
|
+
* `hooks/session-start-content.md`: the behavior rules stay in sync (the Plan
|
|
20
|
+
* Verification Gate and the context-budget rule), while presentation is adapted
|
|
21
|
+
* to dsh's native skill catalog — no roster table (the model sees skills in its
|
|
22
|
+
* catalog) and no install instructions (those live in `.dsh/INSTALL.md`). The
|
|
23
|
+
* payload is deliberately small: it carries the verification gate and the
|
|
24
|
+
* budget rule, not the 1% Rule / Red Flags enforcement scaffolding, which
|
|
25
|
+
* measurably pushes capable models into rigid phases and unnecessary fan-out.
|
|
26
|
+
* Deployments override via Config.
|
|
27
|
+
*
|
|
28
|
+
* @module embedded-workbench-dsh
|
|
29
|
+
*/
|
|
30
|
+
import type { Context, Volatile } from '@deepseek-ai/cordis';
|
|
31
|
+
import z from '@deepseek-ai/schemastery';
|
|
32
|
+
import type { ContextFormed } from '@deepseek-ai/dsh-llm';
|
|
33
|
+
declare module '@deepseek-ai/dsh-llm' {
|
|
34
|
+
interface MessageSourceMap {
|
|
35
|
+
'plugin:embedded-workbench': {
|
|
36
|
+
kind: 'plugin:embedded-workbench';
|
|
37
|
+
} & ContextFormed;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export declare const name = "embedded-workbench";
|
|
41
|
+
export declare const inject: string[];
|
|
42
|
+
export interface Config {
|
|
43
|
+
/**
|
|
44
|
+
* The injection switch the Web client's Plugins page edits live: a `Volatile`
|
|
45
|
+
* reference on a host whose schemastery supports one, an ordinary boolean on a
|
|
46
|
+
* host that predates `.volatile()`. Read it through {@link injectionEnabled},
|
|
47
|
+
* which accepts both shapes.
|
|
48
|
+
*/
|
|
49
|
+
enabled: Volatile<boolean> | boolean;
|
|
50
|
+
gateContent: string;
|
|
51
|
+
}
|
|
52
|
+
export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
53
|
+
enabled: z<boolean, boolean, "defined">;
|
|
54
|
+
gateContent: z<string, string, "defined">;
|
|
55
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
56
|
+
enabled: z<boolean, boolean, "defined">;
|
|
57
|
+
gateContent: z<string, string, "defined">;
|
|
58
|
+
}>>, "plain">;
|
|
59
|
+
export declare function apply(ctx: Context, config: Config): void;
|