dsh-loop-engine 1.0.0-rc10

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 (63) hide show
  1. package/README.md +121 -0
  2. package/README.zh.md +38 -0
  3. package/cordis.patch.yml +3 -0
  4. package/lib/client.js +37506 -0
  5. package/lib/index.js +6412 -0
  6. package/lib/invariant.js +108 -0
  7. package/lib/types/client/LoopEngineBadge.d.ts +34 -0
  8. package/lib/types/client/LoopEngineComposerSelect.d.ts +40 -0
  9. package/lib/types/client/LoopEngineSection.d.ts +34 -0
  10. package/lib/types/client/index.d.ts +29 -0
  11. package/lib/types/client/locales.d.ts +46 -0
  12. package/lib/types/client/store.d.ts +58 -0
  13. package/lib/types/commands.d.ts +69 -0
  14. package/lib/types/driver-core/context-files.d.ts +62 -0
  15. package/lib/types/driver-core/ownership.d.ts +40 -0
  16. package/lib/types/driver-core/permission-knobs.d.ts +26 -0
  17. package/lib/types/driver-core/prompt.d.ts +23 -0
  18. package/lib/types/driver-core/skill-inject.d.ts +59 -0
  19. package/lib/types/engine-claude/agent.d.ts +104 -0
  20. package/lib/types/engine-claude/loop.d.ts +111 -0
  21. package/lib/types/engine-claude/mapping.d.ts +83 -0
  22. package/lib/types/engine-claude/permission.d.ts +41 -0
  23. package/lib/types/engine-claude/process.d.ts +59 -0
  24. package/lib/types/engine-claude/sdk.d.ts +57 -0
  25. package/lib/types/engine-claude/types.d.ts +18 -0
  26. package/lib/types/engine-codex/agent.d.ts +111 -0
  27. package/lib/types/engine-codex/appserver/client.d.ts +49 -0
  28. package/lib/types/engine-codex/appserver/mapping.d.ts +67 -0
  29. package/lib/types/engine-codex/appserver/thread.d.ts +66 -0
  30. package/lib/types/engine-codex/appserver/types.d.ts +215 -0
  31. package/lib/types/engine-codex/loop.d.ts +114 -0
  32. package/lib/types/engine-codex/permission.d.ts +32 -0
  33. package/lib/types/engine-codex/skills.d.ts +29 -0
  34. package/lib/types/engine-codex/types.d.ts +19 -0
  35. package/lib/types/engine-kimi/acp/client.d.ts +76 -0
  36. package/lib/types/engine-kimi/acp/mapping.d.ts +44 -0
  37. package/lib/types/engine-kimi/acp/types.d.ts +95 -0
  38. package/lib/types/engine-kimi/agent.d.ts +123 -0
  39. package/lib/types/engine-kimi/commands.d.ts +40 -0
  40. package/lib/types/engine-kimi/loop.d.ts +108 -0
  41. package/lib/types/engine-kimi/mapping.d.ts +71 -0
  42. package/lib/types/engine-kimi/permission.d.ts +28 -0
  43. package/lib/types/engine-kimi/process.d.ts +61 -0
  44. package/lib/types/engine-kimi/skills.d.ts +57 -0
  45. package/lib/types/engine-kimi/types.d.ts +23 -0
  46. package/lib/types/engine-pi/agent.d.ts +135 -0
  47. package/lib/types/engine-pi/loop.d.ts +123 -0
  48. package/lib/types/engine-pi/permission.d.ts +43 -0
  49. package/lib/types/engine-pi/probe.d.ts +23 -0
  50. package/lib/types/engine-pi/rpc/client.d.ts +105 -0
  51. package/lib/types/engine-pi/rpc/mapping.d.ts +37 -0
  52. package/lib/types/engine-pi/rpc/types.d.ts +235 -0
  53. package/lib/types/engine-pi/skills.d.ts +55 -0
  54. package/lib/types/engine-pi/types.d.ts +27 -0
  55. package/lib/types/index.d.ts +114 -0
  56. package/lib/types/invariant.d.ts +23 -0
  57. package/lib/types/namespace.d.ts +9 -0
  58. package/lib/types/patch-manager.d.ts +59 -0
  59. package/lib/types/preset.d.ts +73 -0
  60. package/lib/types/provider-route.d.ts +49 -0
  61. package/lib/types/settings.d.ts +31 -0
  62. package/lib/types/skills.d.ts +93 -0
  63. package/package.json +103 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Claude Code loop Agent: drives one session through turn and step boundaries
3
+ * with one Claude Agent SDK query per step. Claude Code owns its prompt,
4
+ * tools, and permissions; the durable session log remains the source of truth
5
+ * and the query prompt is a pure serialization of it.
6
+ *
7
+ * @module dsh-loop-engine/engine-claude/agent
8
+ */
9
+ import type { Agent, AgentCancelCause, AgentOptions, AgentStatus, CancelOptions, InboxTarget } from '@deepseek-ai/dsh-agent';
10
+ import { Inbox } from '@deepseek-ai/dsh-agent';
11
+ import type { Scope } from '@deepseek-ai/dsh-scope';
12
+ import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
13
+ import type { Context } from '@deepseek-ai/cordis';
14
+ import type { ResolvedConfig } from './types.ts';
15
+ /** Provider route label used for logged header snapshots and message provenance. */
16
+ export declare const PROVIDER = "claude-code";
17
+ /** Drives one session through turn and step boundaries on Claude Code. */
18
+ export declare class ClaudeCodeAgent implements Agent {
19
+ private loopCtx;
20
+ readonly id: SessionId;
21
+ readonly options: AgentOptions;
22
+ readonly session: Session;
23
+ private readonly config;
24
+ readonly inbox: Inbox;
25
+ private phase;
26
+ private activityDone;
27
+ /** The agent-scoped registration boundary; the lifecycle owner unwinds it after the driver exits. */
28
+ readonly scope: Scope;
29
+ readonly ctx: Context;
30
+ /** Fused dispatcher, built once in the constructor so hot-path dispatches never allocate. */
31
+ private readonly dispatch;
32
+ /** Whether this loop instance has appended its initial/resume request anchor. */
33
+ private requestHeaderLogged;
34
+ constructor(loopCtx: Context, id: SessionId, options: AgentOptions, session: Session, config: ResolvedConfig);
35
+ get status(): AgentStatus;
36
+ /** Commit a phase and publish its externally visible status transition. */
37
+ private setPhase;
38
+ send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;
39
+ /**
40
+ * Queue a message for the next turn and wake the driver.
41
+ * @param input - the user message to deliver.
42
+ */
43
+ followup(input: UserMessage): void;
44
+ /**
45
+ * Queue a message for the running step and wake the driver.
46
+ * @param input - the user message to deliver.
47
+ */
48
+ steer(input: UserMessage): void;
49
+ /**
50
+ * Queue a message for the running step without waking the driver.
51
+ * @param input - the user message to deliver.
52
+ */
53
+ inject(input: UserMessage): void;
54
+ cancel(cause: AgentCancelCause, options?: CancelOptions): void;
55
+ /**
56
+ * Run a maintenance job while the agent is idle.
57
+ * @param job - the maintenance operation, receiving the phase abort signal.
58
+ * @returns the maintenance result.
59
+ */
60
+ runMaintenance<T>(job: (signal: AbortSignal) => Promise<T>): Promise<T>;
61
+ /**
62
+ * Start one driver, or latch its wake behind maintenance or an aborted
63
+ * activity. A wake sent while idle always opens its turn boundary, even
64
+ * when its message was cleared; only a latched replay is suppressed when
65
+ * the queue no longer holds the wake.
66
+ * @param wakeAfterAbort - the {@link send} classification, captured before
67
+ * the inbox insertion so a reentrant cancel cannot reclassify it.
68
+ */
69
+ private wakeDriver;
70
+ whenIdle(): Promise<void>;
71
+ /** Report one failure at its live boundary, then preserve it for driver containment. */
72
+ private throwError;
73
+ private kick;
74
+ private preStep;
75
+ /**
76
+ * Scan the step's user messages for `/name` skill gestures, load each
77
+ * matching skill, and inject the rendered skill content into the message
78
+ * batch. This mirrors what dsh-tool-skill does for the in-process engine.
79
+ * @param messages - the current step's message batch.
80
+ * @param signal - cancellation signal (aborted loads are silently dropped).
81
+ * @returns the original batch when no skill was invoked, or an extended
82
+ * batch with injected skill-content messages appended.
83
+ */
84
+ private injectSkills;
85
+ /**
86
+ * Resolve the native permission handling for one query. A deployment-pinned
87
+ * mode wins outright; otherwise the session's durable dsh permission knobs
88
+ * decide per query (mid-session preset switches included): full access
89
+ * bypasses native checks, an `ask` policy forwards each native permission
90
+ * request to the dsh approval seam, and anything else fails closed with the
91
+ * unattended deny-all stance.
92
+ * @returns the permission fields of the query spec.
93
+ */
94
+ private queryPermission;
95
+ /** Open one turn before claiming its first proposed step. */
96
+ private turn;
97
+ /** Model label recorded in the request header for one lifecycle. */
98
+ private modelLabel;
99
+ /** Append the request header snapshot once per loop instance. */
100
+ private assertRequestHeader;
101
+ /** Run one Claude Code query for the current step and map its transcript into the session log. */
102
+ private step;
103
+ }
104
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Claude Code loop engine module: hosts the AgentFactory that drives every
3
+ * session through the official Claude Agent SDK, one stateless query per dsh
4
+ * step, with the durable session log as the sole source of model context.
5
+ * dsh-loop-engine constructs this factory when the Claude Code engine is
6
+ * selected; this module is a library, not a Cordis plugin entry.
7
+ *
8
+ * @module dsh-loop-engine/engine-claude
9
+ */
10
+ import { Service } from '@deepseek-ai/cordis';
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ import z from '@deepseek-ai/schemastery';
13
+ import type { AgentFactory, AgentHandle, CreateAgentOptions, ResumeAgentOptions } from '@deepseek-ai/dsh-agent';
14
+ import type { ClaudeCodePermissionMode, ResolvedConfig } from './types.ts';
15
+ /** Deployment-selectable non-interactive Claude Code permission modes. */
16
+ export declare const CLAUDE_CODE_PERMISSION_MODES: readonly ClaudeCodePermissionMode[];
17
+ /** Deployment-owned configuration for the Claude Code loop plugin. */
18
+ export interface Config {
19
+ /**
20
+ * Native non-interactive permission handling for every query. When omitted,
21
+ * each query follows the session's dsh permission knobs (`sandbox/mode` and
22
+ * `approval/policy`): full access bypasses native checks, an `ask` policy
23
+ * forwards requests to the dsh approval seam, and anything else auto-denies.
24
+ * A pinned mode overrides the session for every query: `dontAsk` auto-denies,
25
+ * `acceptEdits` accepts edits, `auto` uses the native classifier, `plan`
26
+ * returns a plan without approving execution, and `bypassPermissions`
27
+ * explicitly skips permission checks.
28
+ */
29
+ permissionMode?: ClaudeCodePermissionMode;
30
+ /** Explicit environment entries layered over the credential-scrubbed parent environment. */
31
+ env?: Record<string, string>;
32
+ /** Model label for the logged request header; Claude Code native settings own the actual model. */
33
+ model?: string;
34
+ /** Grace in milliseconds for Claude Code process-tree termination. */
35
+ disposeGraceMs?: number;
36
+ /** Cap on the number of conversation turns before each query stops. */
37
+ maxTurns?: number;
38
+ }
39
+ /** Schema of the Claude Code loop plugin configuration. */
40
+ export declare const Config: z<Config>;
41
+ /** Host-face ctx key for the Claude Code loop service. */
42
+ declare module '@deepseek-ai/cordis' {
43
+ interface Context {
44
+ agentLoopClaudeCode: ClaudeCodeLoop;
45
+ }
46
+ }
47
+ /**
48
+ * Concrete AgentFactory and driver service of the Claude Code loop. Creation
49
+ * and resume follow the registry factory contract and the shared publication
50
+ * transaction: prepare, run setup, then publish through both registries,
51
+ * announce, and emit `agent/session-start`.
52
+ */
53
+ export declare class ClaudeCodeLoop extends Service implements AgentFactory {
54
+ /** Services the loop resolves through its own fiber; blessed identically to the package-level entry inject. */
55
+ static inject: string[];
56
+ /** Validated configuration owned by the loop plugin. */
57
+ readonly config: ResolvedConfig;
58
+ private readonly ownership;
59
+ /** Plain holder prevents Cordis from re-tracing the factory's dependency context through a caller shadow. */
60
+ private readonly runtime;
61
+ constructor(ctx: Context, config: Config);
62
+ /**
63
+ * Construct the driver, scope, and one memoized reverse teardown for a new
64
+ * agent. The teardown is registered with the factory and the owner fiber
65
+ * BEFORE publication, so a mid-setup unload rolls everything back; `signal`
66
+ * fuses caller cancellation with lifecycle teardown for setup awaits.
67
+ */
68
+ private prepare;
69
+ /** Prepare one Agent around an acquired Session, run setup, and publish it. */
70
+ private setupAndPublish;
71
+ /**
72
+ * Create an agent and session under one caller-supplied identity, owned by
73
+ * the accessing fiber. When a persistence backend is mounted, the session's
74
+ * durable identity is stored before publication.
75
+ * @param ownerCtx - caller context that structurally owns the lifecycle.
76
+ * @param options - identities, session seed/metadata, loop options, setup, and cancellation.
77
+ * @returns the published handle.
78
+ */
79
+ createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>;
80
+ /**
81
+ * Take a fresh session's write ownership when persistence is mounted.
82
+ * Nothing is appended here: the constructor seed (which never re-emits
83
+ * through `session/event`) is stored by {@link appendUnstoredSuffix} at the
84
+ * publication commit point, so a failed or cancelled setup closes an
85
+ * unmaterialized handle and leaves no stored residue — the same id can be
86
+ * created again.
87
+ * @param session - the unpublished session to store.
88
+ * @param signal - optional cancellation forwarded to the backend create.
89
+ * @returns the owned handle and stored cursor, or `undefined` without a backend.
90
+ */
91
+ private createStoredSession;
92
+ /**
93
+ * Durably store the session events appended since the last stored cursor.
94
+ * Pre-publication appends (constructor seed markers, setup-window events)
95
+ * never re-emit through `session/event`, so publication must flush them
96
+ * through the handle before live events start routing into it.
97
+ * @param stored - the session's owned handle and stored cursor, if any.
98
+ * @param session - the unpublished session whose suffix is stored.
99
+ */
100
+ private appendUnstoredSuffix;
101
+ /**
102
+ * Resume an owned agent from the configured persistence service.
103
+ * @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
104
+ * @param options - persisted identity, loop options, setup, and cancellation.
105
+ * @returns the published handle.
106
+ */
107
+ resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>;
108
+ /** Resume through an explicit persistence service. */
109
+ private resumeWith;
110
+ }
111
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Pure translation from the Claude Agent SDK's message vocabulary to the dsh
3
+ * session-log vocabulary. Each function maps one SDK message to the durable
4
+ * event payloads the driver appends inside its current step, so the mapping
5
+ * stays unit-testable without any SDK process.
6
+ *
7
+ * @module dsh-loop-engine/engine-claude/mapping
8
+ */
9
+ import type { BetaMessage, BetaRawMessageStreamEvent, BetaUsage } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs';
10
+ import type { MessageParam } from '@anthropic-ai/sdk/resources';
11
+ import { ToolCallId, type ContentBlock, type StreamChunk, type TokenUsage, type ToolResultMessage } from '@deepseek-ai/dsh-llm';
12
+ /** One tool invocation surfaced from a Claude Code assistant message. */
13
+ export interface MappedToolCall {
14
+ /** SDK tool_use id, reused as the dsh call-id so results pair. */
15
+ readonly callId: ToolCallId;
16
+ /** Tool name exactly as the SDK reported it. */
17
+ readonly name: string;
18
+ /** Raw JSON arguments string as the SDK produced them. */
19
+ readonly arguments: string;
20
+ }
21
+ /** Result of translating one SDK assistant message. */
22
+ export interface MappedAssistantMessage {
23
+ /** dsh content blocks: text verbatim, tool calls as tool-call blocks. */
24
+ readonly content: ContentBlock[];
25
+ /** Tool invocations surfaced as dsh tool/call events. */
26
+ readonly toolCalls: readonly MappedToolCall[];
27
+ /** Provider-reported token accounting, when present. */
28
+ readonly usage: TokenUsage | undefined;
29
+ /** Model id reported by the SDK message. */
30
+ readonly model: string;
31
+ }
32
+ /**
33
+ * Render an SDK tool input as the raw JSON string carried by a dsh tool-call
34
+ * block. Values that cannot be stringified (undefined, functions, cyclic
35
+ * graphs) fall back to a stable placeholder instead of failing the mapping.
36
+ * @param input - the SDK tool input value.
37
+ * @returns the JSON string, or a placeholder when the input is not JSON-serializable.
38
+ */
39
+ export declare function stringifyToolInput(input: unknown): string;
40
+ /**
41
+ * Translate one SDK assistant message into dsh content blocks and tool calls.
42
+ * Text blocks map verbatim; tool_use blocks map to tool-call blocks and
43
+ * surfaced calls; thinking blocks map to reasoning blocks; redacted-thinking
44
+ * and unknown blocks are dropped.
45
+ * @param message - the SDK assistant message.
46
+ * @returns the mapped content, calls, usage, and model.
47
+ */
48
+ export declare function mapAssistantMessage(message: BetaMessage): MappedAssistantMessage;
49
+ /**
50
+ * Translate the tool_result blocks of one SDK user message into dsh
51
+ * tool-result messages. Non-tool_result blocks are ignored: Claude Code user
52
+ * messages inside a query carry only tool outcomes.
53
+ * @param message - the SDK user message.
54
+ * @returns the mapped tool-result messages, in block order.
55
+ */
56
+ export declare function mapToolResults(message: MessageParam): ToolResultMessage[];
57
+ /**
58
+ * Translate SDK token accounting into the dsh token-usage shape. Cache
59
+ * breakpoints are optional; absent or null SDK counters stay absent.
60
+ * @param usage - SDK-reported usage for one assistant message.
61
+ * @returns dsh token accounting, omitting absent optional counters.
62
+ */
63
+ export declare function mapUsage(usage: BetaUsage): TokenUsage;
64
+ /** Per-block-index tool-call identity captured at `content_block_start`, reused by `input_json_delta`. */
65
+ export interface StreamToolCall {
66
+ readonly callId: ToolCallId;
67
+ readonly name: string;
68
+ }
69
+ /**
70
+ * Translate one SDK raw stream event into the dsh assistant chunks that drive
71
+ * the live partial projection. Text blocks yield `block-start`/`text-delta`;
72
+ * thinking blocks yield `block-start`/`reasoning-delta`; tool_use blocks yield
73
+ * `block-start`/`tool-call-delta`. Redacted thinking, signature deltas,
74
+ * `content_block_stop`, and transport events yield nothing — the durable
75
+ * `assistant/message` is appended separately from the SDK's complete message,
76
+ * so the streamed chunks never have to carry the whole block.
77
+ * @param event - one raw stream event from an `includePartialMessages` query.
78
+ * @param toolCalls - per-block-index tool identity, mutated here at a tool
79
+ * `content_block_start` so later `input_json_delta` can name the call.
80
+ * @returns the chunks that change the visible partial (empty for non-visual events).
81
+ */
82
+ export declare function mapStreamEvent(event: BetaRawMessageStreamEvent, toolCalls: Map<number, StreamToolCall>): StreamChunk[];
83
+ //# sourceMappingURL=mapping.d.ts.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Mapping from the dsh session's durable permission knobs to one Claude Code
3
+ * query's native permission handling. The session log pins `sandbox/mode`
4
+ * and `approval/policy` events at creation and records every later switch;
5
+ * folding them per query keeps the Claude Code driver consistent with the
6
+ * permission preset the web surface shows, including mid-session switches.
7
+ *
8
+ * @module dsh-loop-engine/engine-claude/permission
9
+ */
10
+ import type { PermissionEvent } from '../driver-core/permission-knobs.ts';
11
+ /**
12
+ * The effective native permission stance for one query:
13
+ * - `bypass` — full access: skip every native permission check.
14
+ * - `ask` — forward each native permission request to the dsh approval seam.
15
+ * - `deny` — auto-deny every native permission request (unattended default).
16
+ */
17
+ export type SessionPermission = {
18
+ readonly kind: 'bypass';
19
+ } | {
20
+ readonly kind: 'ask';
21
+ } | {
22
+ readonly kind: 'deny';
23
+ };
24
+ /**
25
+ * Resolve the session's effective native permission stance. Full access wins
26
+ * outright (the web "full" preset pins it together with `never`); otherwise
27
+ * an `ask` policy forwards permission requests to the dsh approval seam and
28
+ * anything else — including a session with no recorded knobs — fails closed.
29
+ * @param events - the durable session log.
30
+ * @returns the stance one query should run under.
31
+ */
32
+ export declare function resolveSessionPermission(events: readonly PermissionEvent[]): SessionPermission;
33
+ /**
34
+ * Human-readable explanation of WHY a native permission request is asked,
35
+ * carrying a bounded excerpt of the exact tool input.
36
+ * @param toolName - the native tool being decided.
37
+ * @param input - the exact tool input.
38
+ * @returns the approval request's reason text.
39
+ */
40
+ export declare function approvalReason(toolName: string, input: Record<string, unknown>): string;
41
+ //# sourceMappingURL=permission.d.ts.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Projection from the shared managed-process handle to the official Claude
3
+ * Agent SDK's custom-spawn process interface.
4
+ *
5
+ * @module dsh-loop-engine/engine-claude/process
6
+ */
7
+ import type { SpawnedProcess, SpawnOptions } from '@anthropic-ai/claude-agent-sdk';
8
+ import { type SubprocessHandle, type SubprocessOutcome, type SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess';
9
+ /**
10
+ * Encode the SDK's complete child environment as a subprocess overlay.
11
+ * @param env - SDK-composed child environment after its removals and replacements.
12
+ * @returns explicit values plus tombstones for surviving ambient names the SDK removed.
13
+ */
14
+ export declare function sdkEnvironmentOverlay(env: SpawnOptions['env']): NodeJS.ProcessEnv;
15
+ /**
16
+ * Translate one official SDK spawn request to the shared process owner.
17
+ * @param options - command, arguments, workspace, environment, and forwarded signal from the SDK.
18
+ * @param graceMs - process-tree termination grace.
19
+ * @returns the fully explicit shared subprocess request.
20
+ */
21
+ export declare function claudeSpawnSpec(options: SpawnOptions, graceMs: number): SubprocessSpawnSpec;
22
+ /**
23
+ * SDK-facing view of one shared managed process. Protocol transport remains
24
+ * in the official SDK; this adapter only projects streams and exit events.
25
+ */
26
+ export declare class ManagedClaudeCodeProcess implements SpawnedProcess {
27
+ private readonly child;
28
+ readonly stdin: import("stream").Writable;
29
+ readonly stdout: import("stream").Readable;
30
+ private readonly events;
31
+ private outcomeValue;
32
+ private killRequested;
33
+ /**
34
+ * Project a managed process with piped stdin and stdout.
35
+ * @param child - shared handle that remains the process-tree authority.
36
+ */
37
+ constructor(child: SubprocessHandle);
38
+ /** Whether the SDK has requested managed tree termination. */
39
+ get killed(): boolean;
40
+ /** Direct-child exit code, or null while running or after signal exit. */
41
+ get exitCode(): number | null;
42
+ /** Direct-child terminating signal, if any. */
43
+ get signalCode(): NodeJS.Signals | null;
44
+ /** Exact managed-process outcome after exit, or undefined while running. */
45
+ get outcome(): SubprocessOutcome | undefined;
46
+ /**
47
+ * Route the SDK's termination request to the tree-scoped process owner.
48
+ * @param _signal - SDK-selected signal; the shared seam owns its escalation ladder.
49
+ * @returns false only after exit or a previous termination request.
50
+ */
51
+ kill(_signal: NodeJS.Signals): boolean;
52
+ /** Register a persistent process lifecycle listener. */
53
+ on(event: 'exit' | 'error', listener: ((code: number | null, signal: NodeJS.Signals | null) => void) | ((error: Error) => void)): void;
54
+ /** Register a one-shot process lifecycle listener. */
55
+ once(event: 'exit' | 'error', listener: ((code: number | null, signal: NodeJS.Signals | null) => void) | ((error: Error) => void)): void;
56
+ /** Remove a process lifecycle listener. */
57
+ off(event: 'exit' | 'error', listener: ((code: number | null, signal: NodeJS.Signals | null) => void) | ((error: Error) => void)): void;
58
+ }
59
+ //# sourceMappingURL=process.d.ts.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * One Claude Agent SDK query: options assembly, process seam projection, and
3
+ * the headless interaction policy. The driver runs exactly one query per dsh
4
+ * step; this module owns no session state.
5
+ *
6
+ * @module dsh-loop-engine/engine-claude/sdk
7
+ */
8
+ import type { Options, PermissionMode } from '@anthropic-ai/claude-agent-sdk';
9
+ import type { SubprocessHandle, SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess';
10
+ /** Native lock-down mode fixed for every query unless deployment overrides it. */
11
+ export declare const DEFAULT_PERMISSION_MODE: "dontAsk";
12
+ /** Grace in milliseconds for Claude Code process-tree termination. */
13
+ export declare const DEFAULT_DISPOSE_GRACE_MS = 3000;
14
+ export type { PermissionMode };
15
+ /** Deployment-owned process-spawn capability handed over from the plugin. */
16
+ export type SpawnCapability = (spec: SubprocessSpawnSpec) => SubprocessHandle;
17
+ /** Everything one SDK query needs, resolved at step time. */
18
+ export interface ClaudeCodeQuerySpec {
19
+ /** Absolute workspace the Claude Code process runs in. */
20
+ readonly cwd: string;
21
+ /** Native permission handling for this query. */
22
+ readonly permissionMode: PermissionMode;
23
+ /** Explicit environment entries layered over the scrubbed parent environment. */
24
+ readonly env?: Record<string, string>;
25
+ /** Grace in milliseconds for process-tree termination. */
26
+ readonly disposeGraceMs: number;
27
+ /** Model override for the SDK, when the deployment pins one. */
28
+ readonly model?: string;
29
+ /** Cap on the number of conversation turns before the query stops. */
30
+ readonly maxTurns?: number;
31
+ /**
32
+ * Decide one native permission request through the dsh approval seam.
33
+ * When present, `canUseTool` forwards to it instead of auto-denying.
34
+ */
35
+ readonly onToolPermission?: (toolName: string, input: Record<string, unknown>, signal: AbortSignal) => Promise<'allow' | 'deny'>;
36
+ /** Spawn the Claude Code child under the shared process owner. */
37
+ readonly spawn: SpawnCapability;
38
+ /** Receive a human-readable denial or decline for one unattended interaction. */
39
+ readonly onUnattended?: (description: string) => void;
40
+ }
41
+ /**
42
+ * Diagnose one auto-answered interaction in headless mode.
43
+ * @param mode - permission mode in force.
44
+ * @param kind - what the interaction was.
45
+ * @param answer - what the driver did.
46
+ * @param why - reason the driver cannot forward the interaction.
47
+ * @returns a stable one-line diagnostic.
48
+ */
49
+ export declare function unattendedDiagnostic(mode: PermissionMode, kind: string, answer: string, why: string): string;
50
+ /**
51
+ * Build the fixed official SDK options for one step's query.
52
+ * @param spec - workspace, environment, process seam, and disposal policy.
53
+ * @param controller - per-query cancellation owner.
54
+ * @returns the options for one stateless query.
55
+ */
56
+ export declare function claudeQueryOptions(spec: ClaudeCodeQuerySpec, controller: AbortController): Options;
57
+ //# sourceMappingURL=sdk.d.ts.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Public types of the Claude Code loop driver. Types only — no runtime code.
3
+ *
4
+ * @module dsh-loop-engine/engine-claude/types
5
+ */
6
+ import type { PermissionMode } from '@anthropic-ai/claude-agent-sdk';
7
+ /** Claude Code permission modes that never wait for a human response. */
8
+ export type ClaudeCodePermissionMode = Extract<PermissionMode, 'dontAsk' | 'acceptEdits' | 'auto' | 'plan' | 'bypassPermissions'>;
9
+ /** Driver configuration after defaults and load-time validation. */
10
+ export interface ResolvedConfig {
11
+ /** Pinned native mode; `undefined` follows the session's dsh permission knobs per query. */
12
+ readonly permissionMode: ClaudeCodePermissionMode | undefined;
13
+ readonly env: Record<string, string>;
14
+ readonly model: string | undefined;
15
+ readonly disposeGraceMs: number;
16
+ readonly maxTurns: number | undefined;
17
+ }
18
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Codex loop Agent: drives one session through turn and step boundaries by
3
+ * spawning a `codex app-server` child process and speaking JSON-RPC over stdio.
4
+ * Codex owns its prompt, tools, and sandbox; the durable session log remains
5
+ * the source of truth and the thread input is a pure serialization of it.
6
+ * The app-server streams token-level deltas via `item/agentMessage/delta` and
7
+ * `item/reasoning/summaryTextDelta`, so the visible partial paints
8
+ * progressively as the model generates — not all at once at the end. It offers
9
+ * no interactive approval callback, so permissions are folded declaratively
10
+ * into each thread's `sandboxMode`/`approvalPolicy`.
11
+ *
12
+ * @module dsh-loop-engine/engine-codex/agent
13
+ */
14
+ import type { Agent, AgentCancelCause, AgentOptions, AgentStatus, CancelOptions, InboxTarget } from '@deepseek-ai/dsh-agent';
15
+ import { Inbox } from '@deepseek-ai/dsh-agent';
16
+ import type { Scope } from '@deepseek-ai/dsh-scope';
17
+ import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
18
+ import type { Context } from '@deepseek-ai/cordis';
19
+ import type { ResolvedConfig } from './types.ts';
20
+ /** Provider route label used for logged header snapshots and message provenance. */
21
+ export declare const PROVIDER = "codex";
22
+ /** Drives one session through turn and step boundaries on Codex. */
23
+ export declare class CodexAgent implements Agent {
24
+ private loopCtx;
25
+ readonly id: SessionId;
26
+ readonly options: AgentOptions;
27
+ readonly session: Session;
28
+ private readonly config;
29
+ readonly inbox: Inbox;
30
+ private phase;
31
+ private activityDone;
32
+ /** The agent-scoped registration boundary; the lifecycle owner unwinds it after the driver exits. */
33
+ readonly scope: Scope;
34
+ readonly ctx: Context;
35
+ /** Fused dispatcher, built once in the constructor so hot-path dispatches never allocate. */
36
+ private readonly dispatch;
37
+ /** Whether this loop instance has appended its initial/resume request anchor. */
38
+ private requestHeaderLogged;
39
+ /** Lazily created app-server client, reused across steps and released on scope teardown. */
40
+ private appServer;
41
+ constructor(loopCtx: Context, id: SessionId, options: AgentOptions, session: Session, config: ResolvedConfig);
42
+ /** Return the cached app-server client, spawning one on first use or after a dead process. */
43
+ private appServerClient;
44
+ get status(): AgentStatus;
45
+ /** Commit a phase and publish its externally visible status transition. */
46
+ private setPhase;
47
+ send(message: UserMessage, target: InboxTarget, wakeup: boolean): void;
48
+ /**
49
+ * Queue a message for the next turn and wake the driver.
50
+ * @param input - the user message to deliver.
51
+ */
52
+ followup(input: UserMessage): void;
53
+ /**
54
+ * Queue a message for the running step and wake the driver.
55
+ * @param input - the user message to deliver.
56
+ */
57
+ steer(input: UserMessage): void;
58
+ /**
59
+ * Queue a message for the running step without waking the driver.
60
+ * @param input - the user message to deliver.
61
+ */
62
+ inject(input: UserMessage): void;
63
+ cancel(cause: AgentCancelCause, options?: CancelOptions): void;
64
+ /**
65
+ * Run a maintenance job while the agent is idle.
66
+ * @param job - the maintenance operation, receiving the phase abort signal.
67
+ * @returns the maintenance result.
68
+ */
69
+ runMaintenance<T>(job: (signal: AbortSignal) => Promise<T>): Promise<T>;
70
+ /**
71
+ * Start one driver, or latch its wake behind maintenance or an aborted
72
+ * activity. A wake sent while idle always opens its turn boundary, even
73
+ * when its message was cleared; only a latched replay is suppressed when
74
+ * the queue no longer holds the wake.
75
+ * @param wakeAfterAbort - the {@link send} classification, captured before
76
+ * the inbox insertion so a reentrant cancel cannot reclassify it.
77
+ */
78
+ private wakeDriver;
79
+ whenIdle(): Promise<void>;
80
+ /** Report one failure at its live boundary, then preserve it for driver containment. */
81
+ private throwError;
82
+ private kick;
83
+ private preStep;
84
+ /**
85
+ * Scan the step's user messages for `/name` skill gestures, load each
86
+ * matching skill, and inject the rendered skill content into the message
87
+ * batch. This mirrors what dsh-tool-skill does for the in-process engine.
88
+ * @param messages - the current step's message batch.
89
+ * @param signal - cancellation signal (aborted loads are silently dropped).
90
+ * @returns the original batch when no skill was invoked, or an extended
91
+ * batch with injected skill-content messages appended.
92
+ */
93
+ private injectSkills;
94
+ /**
95
+ * Resolve the declarative permission stance for one query. Deployment-pinned
96
+ * fields win per field; anything unpinned follows the session's durable dsh
97
+ * permission knobs, re-folded per query so mid-session preset switches take
98
+ * effect on the next step.
99
+ * @returns the permission fields of the query spec.
100
+ */
101
+ private queryPermission;
102
+ /** Open one turn before claiming its first proposed step. */
103
+ private turn;
104
+ /** Model label recorded in the request header for one lifecycle. */
105
+ private modelLabel;
106
+ /** Append the request header snapshot once per loop instance. */
107
+ private assertRequestHeader;
108
+ /** Run one Codex thread for the current step and map its transcript into the session log. */
109
+ private step;
110
+ }
111
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1,49 @@
1
+ /**
2
+ * JSON-RPC client over stdio for the codex app-server. Spawns
3
+ * `codex app-server` as a child process, sends JSON-RPC 2.0 requests over
4
+ * stdin, and reads newline-delimited JSON responses/notifications from stdout.
5
+ *
6
+ * @module dsh-loop-engine/engine-codex/appserver/client
7
+ */
8
+ import type { InitializeResult, ThreadResumeParams, ThreadStartParams, ThreadStartResult, TurnInterruptParams, TurnStartParams, TurnStartResult } from './types.ts';
9
+ /** Callback for receiving server notifications. */
10
+ export type NotificationHandler = (method: string, params: unknown) => void;
11
+ /** Callback for receiving raw stderr lines from the server process. */
12
+ export type StderrHandler = (line: string) => void;
13
+ /** JSON-RPC client for the codex app-server. */
14
+ export declare class AppServerClient {
15
+ private process;
16
+ private rl;
17
+ private reqId;
18
+ private pending;
19
+ private notificationHandler;
20
+ private stderrHandler;
21
+ private disposed;
22
+ /** Whether this client was disposed or its server process exited. */
23
+ get closed(): boolean;
24
+ /** Create a client by spawning `codex app-server`. */
25
+ private constructor();
26
+ /** Spawn the pinned app-server dependency and initialize the client. */
27
+ static create(): Promise<AppServerClient>;
28
+ /** Set the notification handler for streaming events. */
29
+ onNotification(handler: NotificationHandler): void;
30
+ /** Set the stderr handler for server log lines. */
31
+ onStderr(handler: StderrHandler): void;
32
+ /** Send the initialize handshake. */
33
+ initialize(): Promise<InitializeResult>;
34
+ /** Create a new thread. */
35
+ threadStart(params: ThreadStartParams): Promise<ThreadStartResult>;
36
+ /** Resume an existing thread. */
37
+ threadResume(params: ThreadResumeParams): Promise<ThreadStartResult>;
38
+ /** Start a turn with the given input. */
39
+ turnStart(params: TurnStartParams): Promise<TurnStartResult>;
40
+ /** Interrupt an active turn. */
41
+ turnInterrupt(params: TurnInterruptParams): Promise<unknown>;
42
+ /** Dispose the client and kill the server process. */
43
+ dispose(): void;
44
+ /** Send a JSON-RPC request and wait for the response. */
45
+ private request;
46
+ /** Handle one line of stdout from the server. */
47
+ private handleLine;
48
+ }
49
+ //# sourceMappingURL=client.d.ts.map