@khorsheed/dsh-local-agent-dsh 0.1.0-rc.6

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.
Files changed (45) hide show
  1. package/README.en.md +150 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +151 -0
  4. package/cordis.patch.yml +24 -0
  5. package/lib/client.js +1115 -0
  6. package/lib/dsh-cli-provider-UhWvivte.js +1701 -0
  7. package/lib/dsh-cli-provider.js +3 -0
  8. package/lib/index.js +624 -0
  9. package/lib/invariant.js +33 -0
  10. package/lib/provision.js +602 -0
  11. package/lib/records.js +109 -0
  12. package/lib/session-log-DOsSz56-.js +88 -0
  13. package/lib/types/client/SettingsCard.d.ts +78 -0
  14. package/lib/types/client/SettingsCard.js +200 -0
  15. package/lib/types/client/icons.d.ts +18 -0
  16. package/lib/types/client/icons.js +2 -0
  17. package/lib/types/client/index.d.ts +45 -0
  18. package/lib/types/client/index.js +88 -0
  19. package/lib/types/client/locales.d.ts +76 -0
  20. package/lib/types/client/locales.js +67 -0
  21. package/lib/types/dsh-cli-provider.d.ts +213 -0
  22. package/lib/types/dsh-cli-provider.js +733 -0
  23. package/lib/types/index.d.ts +124 -0
  24. package/lib/types/index.js +347 -0
  25. package/lib/types/invariant.d.ts +16 -0
  26. package/lib/types/invariant.js +37 -0
  27. package/lib/types/live-driver.d.ts +180 -0
  28. package/lib/types/live-driver.js +887 -0
  29. package/lib/types/live-switch.d.ts +76 -0
  30. package/lib/types/live-switch.js +100 -0
  31. package/lib/types/model-broker.d.ts +86 -0
  32. package/lib/types/model-broker.js +149 -0
  33. package/lib/types/model-catalog.d.ts +27 -0
  34. package/lib/types/model-catalog.js +71 -0
  35. package/lib/types/provision.d.ts +382 -0
  36. package/lib/types/provision.js +656 -0
  37. package/lib/types/records.d.ts +41 -0
  38. package/lib/types/records.js +125 -0
  39. package/lib/types/session-log.d.ts +58 -0
  40. package/lib/types/session-log.js +83 -0
  41. package/lib/types/session-mirror.d.ts +155 -0
  42. package/lib/types/session-mirror.js +451 -0
  43. package/locale/en.json +6 -0
  44. package/locale/zh.json +6 -0
  45. package/package.json +121 -0
@@ -0,0 +1,76 @@
1
+ /** `local-agent-dsh` namespace dictionaries. */
2
+ /** Dictionary namespace owned by this plugin (matches the settings namespace). */
3
+ export declare const NS = "local-agent-dsh";
4
+ /** Simplified Chinese dictionary (the key-set source of truth). */
5
+ export declare const zh: {
6
+ 'card.title': string;
7
+ 'card.description': string;
8
+ 'card.expand': string;
9
+ 'card.collapse': string;
10
+ 'auth.title': string;
11
+ 'model.title': string;
12
+ 'model.info.aria': string;
13
+ 'model.info': string;
14
+ 'model.placeholder': string;
15
+ 'model.menu': string;
16
+ 'model.menuDefault': string;
17
+ 'model.menuDefault.cli-config': string;
18
+ 'model.menuDefault.cli-builtin': string;
19
+ 'model.menuDefault.last-observed': string;
20
+ 'model.save': string;
21
+ 'model.applied': string;
22
+ 'model.error': string;
23
+ 'auth.host': string;
24
+ 'enable.title': string;
25
+ 'enable.switch': string;
26
+ 'enable.switch.aria': string;
27
+ 'enable.on': string;
28
+ 'enable.off': string;
29
+ 'live.title': string;
30
+ 'live.info.aria': string;
31
+ 'live.info': string;
32
+ 'live.applied': string;
33
+ 'live.error': string;
34
+ 'live.unavailable': string;
35
+ };
36
+ /** The local-agent-dsh namespace key union. */
37
+ export type LocalAgentDshKey = keyof typeof zh;
38
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
39
+ interface LocaleNamespaceMap {
40
+ /** The dsh harness settings card copy. */
41
+ 'local-agent-dsh': LocalAgentDshKey;
42
+ }
43
+ }
44
+ /** English dictionary, checked complete against the zh key set. */
45
+ export declare const en: {
46
+ 'card.title': string;
47
+ 'card.description': string;
48
+ 'card.expand': string;
49
+ 'card.collapse': string;
50
+ 'auth.title': string;
51
+ 'model.title': string;
52
+ 'model.info.aria': string;
53
+ 'model.info': string;
54
+ 'model.placeholder': string;
55
+ 'model.menu': string;
56
+ 'model.menuDefault': string;
57
+ 'model.menuDefault.cli-config': string;
58
+ 'model.menuDefault.cli-builtin': string;
59
+ 'model.menuDefault.last-observed': string;
60
+ 'model.save': string;
61
+ 'model.applied': string;
62
+ 'model.error': string;
63
+ 'auth.host': string;
64
+ 'enable.title': string;
65
+ 'enable.switch': string;
66
+ 'enable.switch.aria': string;
67
+ 'enable.on': string;
68
+ 'enable.off': string;
69
+ 'live.title': string;
70
+ 'live.info.aria': string;
71
+ 'live.info': string;
72
+ 'live.applied': string;
73
+ 'live.error': string;
74
+ 'live.unavailable': string;
75
+ };
76
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1,67 @@
1
+ /** `local-agent-dsh` namespace dictionaries. */
2
+ /** Dictionary namespace owned by this plugin (matches the settings namespace). */
3
+ export const NS = 'local-agent-dsh';
4
+ /** Simplified Chinese dictionary (the key-set source of truth). */
5
+ export const zh = {
6
+ 'card.title': 'Local Agent · dsh',
7
+ 'card.description': 'dsh 自委派:开关、认证状态与常驻模式(live)',
8
+ 'card.expand': '展开',
9
+ 'card.collapse': '收起',
10
+ 'auth.title': '认证',
11
+ 'model.title': '默认模型',
12
+ 'model.info.aria': '默认模型说明',
13
+ 'model.info': '留空 = 跟随默认(输入框里显示的就是当前跟随的模型)。从列表选择或手动输入一个模型后保存,之后的每轮委派都以它起子 dsh(`--model <provider/model>`;只写模型名则沿用宿主实例的 provider)。单次委派自带的模型优先级更高;成员会话里还可用作曲器按会话切换,不影响这里的默认。改动在下一轮委派生效,进行中的轮次不受影响;评测 run 的条件在建立时冻结,中途换模型会被下一轮的模型回读判为 misattributed 而拦下。',
14
+ 'model.placeholder': '留空 = 不传,用宿主实例的默认模型',
15
+ 'model.menu': '选择模型',
16
+ 'model.menuDefault': '默认(跟随宿主实例默认)',
17
+ 'model.menuDefault.cli-config': '默认(跟随宿主默认模型:{model})',
18
+ 'model.menuDefault.cli-builtin': '默认(跟随宿主默认:{model})',
19
+ 'model.menuDefault.last-observed': '默认(跟随宿主实例默认(最近:{model}))',
20
+ 'model.save': '保存',
21
+ 'model.applied': '已保存,下一轮委派生效;进行中的轮次不受影响',
22
+ 'model.error': '保存失败,请重试',
23
+ 'auth.host': 'dsh 凭据走宿主实例的凭证设置,无需单独登录。',
24
+ 'enable.title': 'DeepSeek 委派',
25
+ 'enable.switch': '启用',
26
+ 'enable.switch.aria': 'DeepSeek 委派开关',
27
+ 'enable.on': '已开启:模型可使用 subagent_dsh 委派给本机 dsh',
28
+ 'enable.off': '已关闭:委派只走官方内置子代理工具',
29
+ 'live.title': '常驻模式(live)',
30
+ 'live.info.aria': '常驻模式说明',
31
+ 'live.info': '常驻模式 = 成员进程常驻:输出实时流入成员会话、取消不杀进程、崩溃后自动续上原会话;关闭则每轮独立进程,跑完一次性出结果。设置为全局偏好,对所有后续委派生效。',
32
+ 'live.applied': '已保存,下一轮委派生效;进行中的轮次不受影响',
33
+ 'live.error': '保存失败,请重试',
34
+ 'live.unavailable': '设置服务不可用(宿主未注册 local-agent-dsh 命名空间)',
35
+ };
36
+ /** English dictionary, checked complete against the zh key set. */
37
+ export const en = {
38
+ 'card.title': 'Local Agent · dsh',
39
+ 'card.description': 'dsh self-delegation: toggle, credential status, and resident (live) mode',
40
+ 'card.expand': 'Expand',
41
+ 'card.collapse': 'Collapse',
42
+ 'auth.title': 'Authentication',
43
+ 'model.title': 'Default model',
44
+ 'model.info.aria': 'About the default model',
45
+ 'model.info': "Blank = follow the default (the input shows the model it currently follows). Pick from the list or type a model by hand and save, and every later delegation round starts the sub-dsh with it (`--model <provider/model>`; a bare id keeps the host instance provider). A model named by one delegation outranks this key; inside a member session the composer can also switch the model per session, without touching this default. A change applies to the next round and never disturbs a round in flight; an evaluation run freezes its condition at setup, so switching mid-run is caught by the model read-back on the next round and fails the run as misattributed.",
46
+ 'model.placeholder': "Blank = pass none, use the host instance default",
47
+ 'model.menu': 'Pick a model',
48
+ 'model.menuDefault': 'Default (follow the host instance default)',
49
+ 'model.menuDefault.cli-config': 'Default (follow the host default model: {model})',
50
+ 'model.menuDefault.cli-builtin': 'Default (follow the host default: {model})',
51
+ 'model.menuDefault.last-observed': 'Default (follow the host instance default (last: {model}))',
52
+ 'model.save': 'Save',
53
+ 'model.applied': 'Saved — takes effect on the next delegation round; rounds in flight are unaffected',
54
+ 'model.error': 'Save failed, please retry',
55
+ 'auth.host': 'dsh authenticates through the host instance’s credential settings — no separate sign-in.',
56
+ 'enable.title': 'DeepSeek delegation',
57
+ 'enable.switch': 'Enabled',
58
+ 'enable.switch.aria': 'DeepSeek delegation switch',
59
+ 'enable.on': 'ON: the model can delegate to the local dsh via subagent_dsh',
60
+ 'enable.off': 'OFF: delegation goes through the official in-process subagent tool only',
61
+ 'live.title': 'Resident mode (live)',
62
+ 'live.info.aria': 'About resident mode',
63
+ 'live.info': 'Resident mode keeps the member process alive: output streams into the member session in real time, cancelling does not kill the process, and a crash resumes the same session. Off means every round runs as an independent one-shot process. The setting is global and applies to every later delegation.',
64
+ 'live.applied': 'Saved — takes effect on the next delegation round; rounds in flight are unaffected',
65
+ 'live.error': 'Save failed, please retry',
66
+ 'live.unavailable': 'Settings service unavailable (the host did not register the local-agent-dsh namespace)',
67
+ };
@@ -0,0 +1,213 @@
1
+ /**
2
+ * One-shot and resumable dsh CLI subagent lifecycle: spawn the sub-dsh
3
+ * headless profile (`dsh --profile <name> --session-id <uuid> "<task>"` or
4
+ * `--resume <uuid>`) through the subprocess seam with the harness scoped home
5
+ * as the child's `$DSH_HOME` and the parent's resolved DeepSeek key injected
6
+ * explicitly (the shared env scrub drops credential-shaped names and every
7
+ * `DSH_*` fact; the explicit env layer is the sanctioned override). The
8
+ * caller-supplied session id is the same uuid on every round: the fresh round
9
+ * creates the sub-dsh session with it, and each resume round continues exactly
10
+ * that session. No stdout parsing — the sub-dsh session id is known a priori.
11
+ * @module @khorsheed/dsh-local-agent-dsh/dsh-cli-provider
12
+ */
13
+ import type { ContentBlock } from '@deepseek-ai/dsh-llm';
14
+ import { type ResolvedSubagentStartRequest, type SubagentCapabilities, type SubagentProvider, type SubagentRun, type SubagentStartRequest } from '@deepseek-ai/dsh-subagent';
15
+ import type { Context } from '@deepseek-ai/cordis';
16
+ import type { Session } from '@deepseek-ai/dsh-session';
17
+ import type { DelegationExecTarget } from '@khorsheed/dsh-local-agent/types';
18
+ import type { LocalAgentDshConfig } from './index.ts';
19
+ import type { DshLiveDriver } from './live-driver.ts';
20
+ /**
21
+ * Spawn-env name carrying the bridge entry path into the sub-dsh process,
22
+ * where the headless bundle's mcp-client row reads it (`!!js`). The name is a
23
+ * family-internal contract between this provider and
24
+ * `@khorsheed/dsh-local-agent-dsh-headless`'s cordis.patch.yml — the member
25
+ * bridge itself reads only the socket/token env.
26
+ */
27
+ export declare const MEMBER_BRIDGE_ENTRY_ENV = "DSH_MEMBER_BRIDGE_ENTRY";
28
+ /**
29
+ * The `NODE_OPTIONS` a containerized round carries. dsh's HTTP client is
30
+ * node's `fetch` (undici), which does NOT read `HTTP(S)_PROXY` by default: in
31
+ * an evaluation unit whose only egress is a whitelist proxy the CLI dials the
32
+ * API directly and fails with a transport error while the proxy never even
33
+ * receives a `CONNECT`. `--use-env-proxy` opens undici's `EnvHttpProxyAgent`,
34
+ * which does read those variables. Measured on the T16 image: without it the
35
+ * round fails, with it the same round answers in 1.3 s. dsh is the only one
36
+ * of the four CLIs that needs an extra knob to run inside a unit — the other
37
+ * three carry their own proxy support — so the injection is automatic rather
38
+ * than something every caller must remember, and the harness reports it in
39
+ * its effective settings so the condition file can see it.
40
+ */
41
+ export declare const CONTAINER_NODE_OPTIONS = "--use-env-proxy";
42
+ /** Default POSIX grace between subprocess termination tiers. */
43
+ export declare const DEFAULT_DISPOSE_GRACE_MS = 3000;
44
+ /** Default interval between live session-mirror polls during a run. */
45
+ export declare const DEFAULT_LIVE_MIRROR_INTERVAL_MS = 2000;
46
+ /**
47
+ * Member channel registration for one sub-dsh process lifetime: mint the
48
+ * per-run token and prepare the env the sub-dsh's mcp-client row reads (the
49
+ * headless bundle patch declares the bridge server with `!!js` env lookups;
50
+ * `@deepseek-ai/dsh-mcp-client` resolves from the installation's dependency
51
+ * closure linked into the scoped home's profiles/node_modules fallback).
52
+ * Returns undefined when the mounted core predates the member channel
53
+ * (declare-and-degrade: the run proceeds unchanged — the row's
54
+ * failOnStartupError is off, and the bridge itself fails closed on the absent
55
+ * token). Token-only auth: host 0.1.5 removed the child pid the parentage
56
+ * cross-check used; the per-run token is the sole credential (see the package
57
+ * README's threat model). The exec driver registers per round; the live driver
58
+ * registers per resident process and releases on reclaim.
59
+ */
60
+ export interface MemberRunHandle {
61
+ readonly env: Readonly<NodeJS.ProcessEnv>;
62
+ release(): void;
63
+ }
64
+ /** Register one member run with the channel; see {@link MemberRunHandle}. */
65
+ export declare function registerMemberRun(ctx: Context, providerName: string, childSessionId: string, parentSessionId: string): MemberRunHandle | undefined;
66
+ /**
67
+ * One-shot dsh CLI subagent provider: every accepted fresh run starts a fresh
68
+ * sub-dsh headless process in the delegating Session's workspace, under the
69
+ * harness scoped home; a resume round (the family tool's staged resume intent)
70
+ * continues the SAME sub-dsh session with `--resume <uuid>` inside the SAME
71
+ * dsh child session. Mirrors the other family providers' one-shot lifecycle,
72
+ * including `NO_START_CAPABILITIES` — continuation is the family's own resume
73
+ * mechanism, not the official Agent-type continuable seam. With the live
74
+ * driver configured (`live: true`), rounds instead go to the resident sub-dsh
75
+ * serve process (see live-driver.ts); the exec path below stays the fallback.
76
+ */
77
+ export declare class DshCliProvider implements SubagentProvider {
78
+ private readonly ctx;
79
+ private readonly config;
80
+ private readonly live?;
81
+ private readonly model?;
82
+ private readonly overrides?;
83
+ readonly name = "dsh-cli";
84
+ readonly capabilities: SubagentCapabilities;
85
+ readonly inheritsParentContext = false;
86
+ /**
87
+ * @param live - the live driver, or a resolver returning the current
88
+ * generation's driver per member (the settings toggle swaps generations;
89
+ * a resolver may return undefined to steer one member's round to exec
90
+ * while a retiring generation still hosts it).
91
+ */
92
+ /**
93
+ * @param model - resolver for the harness's `model` plugin-config key, read
94
+ * PER ROUND so a settings-card write reaches the next delegation without a
95
+ * reload. A delegation that names its own model outranks it.
96
+ * @param overrides - resolver for the member's session-level model override
97
+ * (the composer picker, owned by the model broker). It outranks BOTH the
98
+ * delegation's recorded model and the configured one: on the exec path it
99
+ * re-points the next round's `--model`, and on the live path it is the
100
+ * member's start model — a resident runtime bound to a different model is
101
+ * retired so the round respawns onto the override.
102
+ */
103
+ constructor(ctx: Context, config: LocalAgentDshConfig, live?: DshLiveDriver | ((childSessionId: string) => DshLiveDriver | undefined) | undefined, model?: (() => string | undefined) | undefined, overrides?: ((childSessionId: string) => string | undefined) | undefined);
104
+ /** Resolve the live driver for one round's member, if live is on for it. */
105
+ private liveDriver;
106
+ /** Per-round member-channel registration for the exec path (see {@link registerMemberRun}). */
107
+ private memberRun;
108
+ start(request: ResolvedSubagentStartRequest): Promise<SubagentRun>;
109
+ /** Fresh round: record the child session and delegation, spawn the sub-dsh create. */
110
+ private startDshFresh;
111
+ /** Resume round: continue the recorded sub-dsh session inside the existing child session. */
112
+ private startDshResume;
113
+ }
114
+ /** Fully resolved inputs for one sub-dsh CLI run. */
115
+ export interface DshCliRunSpec {
116
+ /** Parent Session workspace; also the sub-dsh process cwd. */
117
+ readonly cwd: string;
118
+ /** The `dsh` harness's scoped home, injected as the child's `$DSH_HOME`. */
119
+ readonly homeDir: string;
120
+ /**
121
+ * The named scope {@link DshCliRunSpec.homeDir} belongs to, when the round
122
+ * runs against one. Absent means the default scope. Carried so a completed
123
+ * round grades the credential of the scope it actually used.
124
+ */
125
+ readonly scope?: string | undefined;
126
+ /** dsh subagent session recording this delegation. */
127
+ readonly childSession?: Session | undefined;
128
+ /**
129
+ * The sub-dsh session id for this round — the caller-supplied uuid, passed
130
+ * as `--session-id` on a fresh round and `--resume` on a continuation.
131
+ */
132
+ readonly sessionId: string;
133
+ /**
134
+ * The model this round runs, spelled `provider/model` — passed to the
135
+ * sub-dsh as `--model`, which overrides the instance's default selection
136
+ * for that launch. Absent means no flag at all: the sub-dsh runs the
137
+ * instance's default, exactly as it did before the flag existed.
138
+ */
139
+ readonly model?: string | undefined;
140
+ readonly effort?: string | undefined;
141
+ /**
142
+ * Resume round: continue the sub-dsh session named by `sessionId` with
143
+ * `--resume` instead of a fresh `--session-id`, appending this round into
144
+ * the same child session under the given turn number.
145
+ */
146
+ readonly resume?: {
147
+ readonly cliSessionId: string;
148
+ readonly turn: number;
149
+ } | undefined;
150
+ /**
151
+ * Live-mirror poll interval during the run; absent applies the default
152
+ * ({@link DEFAULT_LIVE_MIRROR_INTERVAL_MS}). Tests inject a small value.
153
+ */
154
+ readonly liveMirrorIntervalMs?: number | undefined;
155
+ /**
156
+ * Member channel: the per-run bridge coordinates (socket path, token,
157
+ * bridge entry) merged into the explicit env layer — the sub-dsh's
158
+ * mcp-client row reads them via `!!js` env lookups.
159
+ */
160
+ readonly memberEnv?: Readonly<NodeJS.ProcessEnv> | undefined;
161
+ /**
162
+ * Run the sub-dsh inside this container instead of on the host: the argv
163
+ * below is wrapped in `docker exec` and the explicit env layer is forwarded
164
+ * through NAME-only `-e` flags (the resolved API key therefore never
165
+ * reaches the host process table). Absent means the host spawn, unchanged.
166
+ */
167
+ readonly exec?: DelegationExecTarget | undefined;
168
+ /**
169
+ * The dsh build the round runs, resolved lazily and cached by the family
170
+ * probe. The sub-dsh session log names its model but never its build, so
171
+ * this is the only version channel the round's read-back has.
172
+ */
173
+ readonly cliVersion?: (() => Promise<string | undefined>) | undefined;
174
+ }
175
+ /** Validate and join the one-shot task before crossing the process boundary. */
176
+ export declare function dshTextTask(prompt: readonly ContentBlock[]): string;
177
+ /**
178
+ * The dsh launch argv the provider replicates: the parent instance's own
179
+ * node + tsx import + entry point, so the sub-dsh runs the same dsh build as
180
+ * its parent. A configured `cliLaunch` replaces this entirely.
181
+ * @param config - plugin config carrying the optional override.
182
+ * @returns the launch prefix before the profile flag.
183
+ */
184
+ export declare function dshLaunchArgv(config: LocalAgentDshConfig): readonly string[];
185
+ /**
186
+ * The dsh build the sub-dsh runs, probed by asking the very launch argv the
187
+ * delegation would spawn for its `--version` (the sub-dsh replicates the
188
+ * parent instance's own node + entry point, so the parent's build IS the
189
+ * child's). Cached by the family probe against that entry script's identity,
190
+ * so a harness upgrade re-probes and an unchanged one never spawns twice.
191
+ * @param ctx - host context carrying the subprocess seam.
192
+ * @param config - plugin config carrying the optional launch override.
193
+ * @param homeDir - the harness's scoped home.
194
+ * @returns the version, or undefined when the launch cannot be asked.
195
+ */
196
+ export declare function dshCliVersion(ctx: Context, config: LocalAgentDshConfig, homeDir: string): Promise<string | undefined>;
197
+ /**
198
+ * Start the real sub-dsh headless child and publish its run. The final answer
199
+ * is printed to stdout; stderr is inherited for diagnostics. The run id is
200
+ * the child session id for a session-backed run, so the tool's
201
+ * `resume="<id>"` self-description names the same handle the registry
202
+ * records.
203
+ * @param request - resolved shared subagent request.
204
+ * @param spec - workspace, scoped home, child session, and resume facts.
205
+ * @returns the published run after the child starts.
206
+ */
207
+ export declare function startDshCliRun(request: SubagentStartRequest, spec: DshCliRunSpec & {
208
+ config: LocalAgentDshConfig;
209
+ ctx: Context;
210
+ }): Promise<SubagentRun>;
211
+ /** Resolve the sub-dsh credential or fail loud before any process spawns. */
212
+ export declare function resolveApiKey(ctx: Context, config: LocalAgentDshConfig): Promise<string>;
213
+ //# sourceMappingURL=dsh-cli-provider.d.ts.map