fix(skill): a DeepSeek Harness worker on its setup guide is refused, not typed into

dsh-TUI 0.19.0 opens a setup guide ("Step 1 of 4") in every session
until a person has finished it once, and the guide's cursor is the same
glyph the skill waits for as the composer: the readiness mark matched on
it in 2 of 2 launches. An Enter there acts on the highlighted step,
which is a sign-in. A spawned worker was handed back "ready" on that
screen, and the first task prompt would have been typed into it.

After the mark, the rendered pane is now read once: a worker that shows
the guide is deleted and the spawn fails with what to do (finish the
guide once from the Run menu). For `local:deepseek` and for a plain
`deepseek` worker alike.

Also says which verb reads a local DeepSeek worker's answer: `sendmark`.
The harness reports the end of a turn, but dsh 0.2.2 renamed its
transcript file and Codeman reads an empty answer from it for now.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-11-11 10:16:18 +01:00
1 parent bdd882bce8
commit aa8afdf2f6
7 files changed
+166 -18

No files matched your search

+52
View File
@@ -551,6 +551,58 @@ describe.skipIf(!hasJq)('preamble spawn_worker <name> local', () => {
expect(run.calls[2].q).toContain('match=❯');
});
it('a DeepSeek Harness worker that opened its setup guide is deleted, never handed back: its cursor is the mark too', () => {
// dsh-TUI 0.19.0, as the rendered pane reads: the guide, with `❯` on its first step.
const guide = JSON.stringify({
success: true,
data: {
terminalBuffer:
'\u001b[1mWelcome to dsh-TUI\u001b[0m Step 1 of 4\r\n ✗ No DEEPSEEK_API_KEY yet\r\n❯ Sign in to a subscription (OAuth)\r\n',
},
});
const composer = JSON.stringify({
success: true,
data: {
terminalBuffer:
'╭────╮\r\n│ ❯ Say something, or type / for commands…\r\n╰────╯\r\n qwen3.6:35b-a3b · standard\r\n',
},
});
const answers = { 'lm-get': WITH_AGENTS, 'quick-start': QUICK_START, 'wait-output': MATCHED };
const blocked = runSkill('spawn_worker rev local:deepseek', {
...answers,
terminal: guide,
delete: JSON.stringify({ success: true, data: {} }),
});
expect(blocked.rc).toBe(1);
expect(blocked.stdout).toBe('');
expect(blocked.stderr).toMatch(/setup guide/);
expect(blocked.calls.map((call) => `${call.m} ${call.key}`)).toEqual([
'GET lm-get',
'POST quick-start',
'GET wait-output',
'GET terminal',
'DELETE delete',
]);
const ready = runSkill('spawn_worker rev local:deepseek', { ...answers, terminal: composer });
expect(ready.stderr).toBe('');
expect(ready.rc).toBe(0);
expect(ready.stdout).toBe(`${SID}\n`);
// The same look for a DeepSeek worker that is not on the local model.
const cloud = runSkill('spawn_worker rev deepseek', {
'quick-start': QUICK_START,
'wait-output': MATCHED,
terminal: guide,
delete: JSON.stringify({ success: true, data: {} }),
});
expect(cloud.rc).toBe(1);
expect(cloud.stdout).toBe('');
expect(cloud.stderr).toMatch(/setup guide/);
expect(cloud.calls.map((call) => call.key)).toEqual(['quick-start', 'wait-output', 'terminal', 'delete']);
});
it('a mark the server names wins over the one this skill measured, and LOCAL_READY_MARK over both', () => {
const named = status({
...INSTALLED,