From 91fab01b712e10c054fe2b79c792d9af38c2c05b Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 14:02:50 +0800 Subject: [PATCH 01/12] feat: add DeepSeek Harness BYO reference integration Run pinned DSH over ACP using the existing BYO payload and A2A executor. Preserve native conversation state, cancellation and one-shot permissions. Proxy HTTP MCP bindings to honor headers, timeouts and session termination. Include the runtime image, dependency lock, deployment example and tests. AI-assisted development with Codex; human review is required before upstream submission. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- examples/dsh-byo/agent.yaml.tmpl | 44 + go/.dockerignore | 1 + go/harness/byo/dsh/.gitignore | 2 + go/harness/byo/dsh/Dockerfile | 37 + go/harness/byo/dsh/README.md | 120 + go/harness/byo/dsh/cmd/main.go | 114 + .../internal/bridge/a2a_integration_test.go | 199 + go/harness/byo/dsh/internal/bridge/events.go | 148 + .../dsh/internal/bridge/integration_test.go | 161 + go/harness/byo/dsh/internal/bridge/mcp.go | 136 + .../byo/dsh/internal/bridge/mcp_test.go | 96 + go/harness/byo/dsh/internal/bridge/rpc.go | 142 + .../byo/dsh/internal/bridge/rpc_test.go | 42 + go/harness/byo/dsh/internal/bridge/runner.go | 359 + .../byo/dsh/internal/bridge/runner_test.go | 239 + go/harness/byo/dsh/internal/config/config.go | 210 + .../byo/dsh/internal/config/config_test.go | 104 + go/harness/byo/dsh/package-lock.json | 9093 +++++++++++++++++ go/harness/byo/dsh/package.json | 9 + 19 files changed, 11256 insertions(+) create mode 100644 examples/dsh-byo/agent.yaml.tmpl create mode 100644 go/harness/byo/dsh/.gitignore create mode 100644 go/harness/byo/dsh/Dockerfile create mode 100644 go/harness/byo/dsh/README.md create mode 100644 go/harness/byo/dsh/cmd/main.go create mode 100644 go/harness/byo/dsh/internal/bridge/a2a_integration_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/events.go create mode 100644 go/harness/byo/dsh/internal/bridge/integration_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/mcp.go create mode 100644 go/harness/byo/dsh/internal/bridge/mcp_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/rpc.go create mode 100644 go/harness/byo/dsh/internal/bridge/rpc_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/runner.go create mode 100644 go/harness/byo/dsh/internal/bridge/runner_test.go create mode 100644 go/harness/byo/dsh/internal/config/config.go create mode 100644 go/harness/byo/dsh/internal/config/config_test.go create mode 100644 go/harness/byo/dsh/package-lock.json create mode 100644 go/harness/byo/dsh/package.json diff --git a/examples/dsh-byo/agent.yaml.tmpl b/examples/dsh-byo/agent.yaml.tmpl new file mode 100644 index 0000000000..5dadea9bbf --- /dev/null +++ b/examples/dsh-byo/agent.yaml.tmpl @@ -0,0 +1,44 @@ +apiVersion: api.kagent.dev/v1alpha3 +kind: ModelConfig +metadata: + name: dsh-model + namespace: kagent +spec: + provider: OpenAI + model: ${DSH_MODEL} + apiKeySecret: deepseek-api-key + apiKeySecretKey: OPENAI_API_KEY + openAI: + baseUrl: https://api.deepseek.com/v1 +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: Harness +metadata: + name: dsh-byo + namespace: kagent +spec: + byo: {} + workload: + image: ${DSH_BYO_IMAGE} + command: [/usr/local/bin/kagent-dsh-byo] + substrate: + workerPoolRef: + name: kagent-default + snapshotPolicy: + location: ${SNAPSHOT_LOCATION} +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: Agent +metadata: + name: dsh-agent + namespace: kagent +spec: + harnessRef: + name: dsh-byo + template: + inline: + description: Coding agent running DeepSeek Harness through BYO. + modelConfig: + name: dsh-model + systemPrompt: | + Work in the configured workspace. Explain the changes and report the checks you ran. diff --git a/go/.dockerignore b/go/.dockerignore index ed64053c2b..16e15f67c7 100644 --- a/go/.dockerignore +++ b/go/.dockerignore @@ -3,6 +3,7 @@ bin/ .cache/ **/.cache/ +harness/byo/dsh/node_modules/ # Test files *_test.go diff --git a/go/harness/byo/dsh/.gitignore b/go/harness/byo/dsh/.gitignore new file mode 100644 index 0000000000..d068546031 --- /dev/null +++ b/go/harness/byo/dsh/.gitignore @@ -0,0 +1,2 @@ +/node_modules/ +!package-lock.json diff --git a/go/harness/byo/dsh/Dockerfile b/go/harness/byo/dsh/Dockerfile new file mode 100644 index 0000000000..5c64ee02c2 --- /dev/null +++ b/go/harness/byo/dsh/Dockerfile @@ -0,0 +1,37 @@ +# Build from the go/ directory: docker build -f harness/byo/dsh/Dockerfile . +FROM --platform=$BUILDPLATFORM golang:1.27.0-bookworm@sha256:ded31c68586d2e49e760acc2e65a884b23d032e9bbbed0ae0c55abd3fcaf4452 AS builder +ARG TARGETOS +ARG TARGETARCH +WORKDIR /workspace +COPY go.mod go.sum ./ +RUN --mount=type=cache,target=/go/pkg/mod go mod download +COPY api/ api/ +COPY adk/ adk/ +COPY core/ core/ +COPY harness/ harness/ +COPY pkg/ pkg/ +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \ + go build -trimpath -o /kagent-dsh-byo ./harness/byo/dsh/cmd + +FROM node:24-bookworm-slim@sha256:d6aa754f16b3197301076f047b5def2f02ea1dbbc2ca920407d46d7ec7f87b20 +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash bubblewrap ca-certificates git ripgrep \ + && rm -rf /var/lib/apt/lists/* +WORKDIR /opt/dsh +# Commit the npm lockfile with this example; npm ci checks package integrity. +COPY harness/byo/dsh/package.json harness/byo/dsh/package-lock.json ./ +RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund \ + && ln -s /opt/dsh/node_modules/.bin/dsh /usr/local/bin/dsh \ + && dsh --version \ + && groupadd --gid 65532 kagent \ + && useradd --uid 65532 --gid 65532 --no-create-home --home-dir /data kagent \ + && mkdir -p /data/adapter /data/dsh/sessions /data/dsh/storages /data/workspace \ + && chown -R 65532:65532 /data +COPY --from=builder /kagent-dsh-byo /usr/local/bin/kagent-dsh-byo +USER 65532:65532 +WORKDIR /data/workspace +EXPOSE 80 8081 +LABEL org.opencontainers.image.source="https://github.com/kagent-dev/kagent" +LABEL org.opencontainers.image.description="DeepSeek Harness reference integration for kagent BYO" +ENTRYPOINT ["/usr/local/bin/kagent-dsh-byo"] diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md new file mode 100644 index 0000000000..fccdf76864 --- /dev/null +++ b/go/harness/byo/dsh/README.md @@ -0,0 +1,120 @@ +# DeepSeek Harness BYO reference integration + +This image runs DeepSeek Harness (DSH) `0.2.0-rc.2` behind kagent's existing +`spec.byo` contract. It adds no CRD fields or native runtime type. The bridge +reads `KAGENT_CONFIG_JSON` and `KAGENT_AGENT_CARD_JSON`, uses the shared A2A +executor, and serves private gRPC on port 80 and readiness on port 8081. + +## Supported configuration + +- OpenAI-compatible Chat Completions ModelConfig, including a custom base URL + and headers. Provider credentials remain gateway-injected Secret references. +- The compiled system prompt and one root conversation per Actor. +- Whole Streamable HTTP MCP servers with compiled headers, HTTP timeouts and + session termination policy, enforced by a loopback Go MCP proxy. +- Text replies and text tool results, including tool errors. +- ACP cancellation and session resumption after the DSH process exits. +- DSH one-shot permission requests mapped to kagent's approval messages. + +ACP emits committed semantic updates, rather than raw provider token deltas. +Context occupancy is not per-call token usage, so the bridge does not report +model token totals from ACP usage updates. DSH's own telemetry exporter and +auxiliary web tools are disabled; the kagent wrapper retains its telemetry path. + +Unsupported configuration is rejected at startup: Responses API, model +generation overrides, API-key passthrough, custom TLS, SSE/stdio MCP bindings, +tool subsets, SSE read-timeout overrides, forwarded caller headers, and kagent `requireApproval` bindings. +DSH's ACP server has no per-MCP-server approval policy, so accepting that field +would not enforce the requested gate. DSH sandbox permission requests are a +separate channel and can still be answered through kagent. + +The proxy discovers the remote tool catalog at each turn. It preserves the +CRD's default 30-second timeout and `terminateOnClose: true`; an explicit false +closes the local client without terminating the remote session. It does not +forward mid-turn catalog notifications, MCP resources, prompts or elicitation. + +kagent skills, Agent Plugins, subagent bindings, memory, structured output and +ADK-specific context settings are not translated. DSH keeps its own built-in +tools and plugin composition; those are not equivalent to kagent Agent Plugins. +The first version accepts text input and output only. + +## State and process lifetime + +Each turn starts a DSH ACP process and creates or resumes the Actor's private +DSH session. A pending permission request retains that process until the +decision arrives. Completion closes the session and stdin so DSH can flush its +state; cancellation is followed by bounded process-group cleanup. + +`/data/adapter/state.json` binds the Actor to one native session. DSH session +logs and storage live under `/data/dsh`, and the workspace is `/data/workspace`. +The CLI profile and compiled overlay use a disposable home outside `/data`. +Do not delete the native session logs while retaining the continuation binding. +Public tasks and history remain in kagent's controller-backed TaskStore. + +The local tests verify recovery after a DSH process restart. Full Substrate +snapshot/restore remains a separate cluster acceptance check. + +## Build and deploy + +From the repository root: + +```sh +docker build -f go/harness/byo/dsh/Dockerfile -t YOUR_REGISTRY/kagent-dsh-byo:dev go +docker push YOUR_REGISTRY/kagent-dsh-byo:dev +``` + +Record the pushed image's manifest digest. The example requires the full +`YOUR_REGISTRY/kagent-dsh-byo@sha256:...` reference, not its tag. + +Use a clean kagent 1.x alpha installation with a configured `kagent-default` +WorkerPool, snapshot storage, and Substrate credential gateway. In namespace +`kagent`, create the Secret `deepseek-api-key` with an `OPENAI_API_KEY` entry +using your normal secret-management workflow. Grant the Substrate atespace +access to that namespace as described in +[credential injection](../../../../docs/architecture/credential-injection.md). +The bridge honors the platform's Node CA and proxy environment. + +Set `DSH_MODEL` to a Chat Completions model available to your DeepSeek account, +`DSH_BYO_IMAGE` to the image digest, and `SNAPSHOT_LOCATION` to your installation's +snapshot storage URI. Render only those variables: + +```sh +envsubst '${DSH_MODEL} ${DSH_BYO_IMAGE} ${SNAPSHOT_LOCATION}' \ + < examples/dsh-byo/agent.yaml.tmpl > /tmp/dsh-agent.yaml +kubectl apply --dry-run=server -f /tmp/dsh-agent.yaml +kubectl apply -f /tmp/dsh-agent.yaml +kubectl get harness,agent -n kagent +``` + +After preparation succeeds, open `dsh-agent` in the kagent UI and create a +conversation. To bind an MCP server, add a normal `tools[].mcp` binding to the +inline AgentTemplate, omit the `tools` subset, and leave `requireApproval` unset. +The server must use Streamable HTTP and the platform trust bundle. + +## Verification + +From `go/`: + +```sh +go test -race ./harness/byo/dsh/... ./harness/runtime/... +``` + +The subprocess tests exercise permission decisions, cancellation, identity +validation, malformed protocol handling and cleanup without a model API. +For the published runtime tests, install the locked npm dependencies and run: + +```sh +npm ci --prefix harness/byo/dsh --ignore-scripts --no-audit --no-fund +DSH_TEST_BIN="$PWD/harness/byo/dsh/node_modules/.bin/dsh" \ + go test -race ./harness/byo/dsh/internal/bridge -run TestRealDSH -count=1 +``` + +These tests use a real DSH process, a local model fixture, and a local MCP +server. They verify MCP execution and resumed turns through A2A gRPC without +provider credentials. The transport test substitutes an SDK-local TaskStore +for the controller, so it does not prove full cluster settlement or snapshots. + +Before release, run the same scenarios in Substrate: two turns, MCP success and +failure, cancellation followed by another turn, approval allow/reject/cancel, +and conversation continuity after explicit suspend/resume and Actor replacement. +Do not advertise snapshot, fork or model-usage guarantees until those checks pass. diff --git a/go/harness/byo/dsh/cmd/main.go b/go/harness/byo/dsh/cmd/main.go new file mode 100644 index 0000000000..1296887143 --- /dev/null +++ b/go/harness/byo/dsh/cmd/main.go @@ -0,0 +1,114 @@ +// Command kagent-dsh-byo serves a DSH agent through the existing BYO contract. +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + "time" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + "github.com/a2aproject/a2a-go/v2/a2asrv" + + "github.com/kagent-dev/kagent/go/adk/pkg/app" + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/bridge" + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" + "github.com/kagent-dev/kagent/go/harness/runtime/continuation" + "github.com/kagent-dev/kagent/go/pkg/logging" + "github.com/kagent-dev/kagent/go/pkg/telemetry" +) + +func main() { + executable := flag.String("dsh-bin", "dsh", "DSH executable (must match the pinned version)") + dataDir := flag.String("data-dir", "/data", "absolute durable data directory") + port := flag.String("port", "80", "private A2A gRPC port") + check := flag.Bool("check", false, "validate compiled configuration and DSH version, then exit") + flag.Parse() + logger, err := logging.New(os.Stderr, "info") + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + ctx := logging.IntoContext(context.Background(), logger) + // These inputs are generated by the controller; this reference binary adds no CRD fields. + if err := run(ctx, *executable, *dataDir, *port, *check, os.Getenv, os.Environ()); err != nil { //nolint:forbidigo // BYO controller payloads and platform runtime environment. + logger.ErrorContext(ctx, "dsh byo stopped", "error", err) + os.Exit(1) + } +} + +func run(ctx context.Context, executable, dataDir, port string, check bool, getenv func(string) string, environment []string) error { + cfg, err := config.Parse([]byte(getenv("KAGENT_CONFIG_JSON"))) + if err != nil { + return err + } + var card a2atype.AgentCard + if err := json.Unmarshal([]byte(getenv("KAGENT_AGENT_CARD_JSON")), &card); err != nil { + return fmt.Errorf("failed to decode BYO agent card: %w", err) + } + if card.Name == "" { + return fmt.Errorf("agent card name is required") + } + runner, err := bridge.New(cfg, executable, dataDir, environment) + if err != nil { + return err + } + validateCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + if err := runner.Validate(validateCtx); err != nil { + return err + } + store, err := continuation.New(dataDir+"/adapter", "dsh-byo", bridge.ValidateSessionID) + if err != nil { + return err + } + if check { + return nil + } + runtimeConfig := cfg.Agent.ProcessConfig() + level := runtimeConfig.LogLevel + if level == "" { + level = "info" + } + logger, err := logging.New(os.Stderr, level) + if err != nil { + return err + } + ctx = logging.IntoContext(ctx, logger) + identity := runtimeConfig.Telemetry.WithEnvironment(environment) + // Leave runtime identity unset: the telemetry catalog has no DSH value. + executor, err := runtimea2a.New(runner, store, identity) + if err != nil { + return err + } + providers, err := telemetry.Init(ctx, telemetry.Options{Config: identity.ExporterConfig(), Identity: identity.ResourceIdentity(), Defaults: identity.ResourceDefaults(card.Name), DeferMetrics: true}) + if err != nil { + return fmt.Errorf("failed to initialize BYO telemetry: %w", err) + } + defer func() { + shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := providers.Shutdown(shutdownCtx); err != nil { + logging.FromContext(ctx).ErrorContext(ctx, "failed to shutdown byo telemetry", "error", err) + } + }() + application, err := app.New(app.AppConfig{ + AgentCard: card, Port: port, AppName: card.Name, ControlPlaneURL: runtimeConfig.ControlPlaneURL, + MaxContentLength: runtimeConfig.MaxContentLength, Logger: logging.FromContext(ctx), Telemetry: identity, Flush: providers.ForceFlush, + HandlerOpts: []a2asrv.RequestHandlerOption{a2asrv.WithExecutorContextInterceptor(startMetrics(providers.StartMetrics))}, + }, executor) + if err != nil { + return fmt.Errorf("failed to construct BYO A2A application: %w", err) + } + return application.Run() +} + +type startMetrics func() + +func (start startMetrics) Intercept(ctx context.Context, _ *a2asrv.ExecutorContext) (context.Context, error) { + start() + return ctx, nil +} diff --git a/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go new file mode 100644 index 0000000000..8cd95faac2 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go @@ -0,0 +1,199 @@ +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "io" + "iter" + "net" + "net/http" + "net/http/httptest" + "os" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + a2agrpc "github.com/a2aproject/a2a-go/v2/a2agrpc/v1" + a2apb "github.com/a2aproject/a2a-go/v2/a2apb/v1" + "github.com/a2aproject/a2a-go/v2/a2apb/v1/pbconv" + "github.com/a2aproject/a2a-go/v2/a2asrv" + "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" + "github.com/kagent-dev/kagent/go/harness/runtime/continuation" + "github.com/kagent-dev/kagent/go/pkg/tracing" +) + +func TestRealDSHThroughA2AGRPCAndMCP(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("set DSH_TEST_BIN to the pinned DSH executable") + } + var toolCalls atomic.Int32 + mcpServer := mcp.NewServer(&mcp.Implementation{Name: "arithmetic", Version: "1"}, nil) + type operands struct { + A int `json:"a"` + B int `json:"b"` + } + type product struct { + Product int `json:"product"` + } + mcp.AddTool(mcpServer, &mcp.Tool{Name: "multiply", Description: "Multiply two integers."}, func(_ context.Context, _ *mcp.CallToolRequest, input operands) (*mcp.CallToolResult, product, error) { + toolCalls.Add(1) + return nil, product{Product: input.A * input.B}, nil + }) + mcpHTTP := httptest.NewServer(mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return mcpServer }, &mcp.StreamableHTTPOptions{Stateless: true})) + defer mcpHTTP.Close() + var mu sync.Mutex + var requests []json.RawMessage + modelHTTP := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var body json.RawMessage + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, "bad request", 400) + return + } + mu.Lock() + requests = append(requests, body) + index := len(requests) + mu.Unlock() + if index == 1 { + var req struct { + Tools []struct { + Function struct { + Name string `json:"name"` + } `json:"function"` + } `json:"tools"` + } + if err := json.Unmarshal(body, &req); err != nil { + http.Error(w, "bad tools", 400) + return + } + name := "" + for _, tool := range req.Tools { + if strings.HasSuffix(tool.Function.Name, "multiply") { + name = tool.Function.Name + } + } + if name == "" { + http.Error(w, "MCP tool not registered", 500) + return + } + writeCompletion(w, map[string]any{"role": "assistant", "tool_calls": []any{map[string]any{"index": 0, "id": "multiply-1", "type": "function", "function": map[string]string{"name": name, "arguments": `{"a":6,"b":7}`}}}}, "tool_calls") + } else { + text := "product=42" + if index == 3 { + text = "resumed product=42" + } + writeCompletion(w, map[string]string{"role": "assistant", "content": text}, "stop") + } + })) + defer modelHTTP.Close() + data := fmt.Sprintf(`{"model":{"type":"openai","model":"mock","base_url":%q},"instruction":"Use arithmetic tools.","runtime":{"control_plane_url":"http://controller:8083"},"http_tools":[{"params":{"url":%q}}]}`, modelHTTP.URL+"/v1", mcpHTTP.URL) + cfg, err := config.Parse([]byte(data)) + require.NoError(t, err) + dataDir := t.TempDir() + runner, err := New(cfg, executable, dataDir, append(os.Environ(), "OPENAI_API_KEY=mock")) + require.NoError(t, err) + store, err := continuation.New(dataDir+"/adapter", "dsh-byo", ValidateSessionID) + require.NoError(t, err) + executor, err := runtimea2a.New(runner, store, tracing.RuntimeTelemetry{}) + require.NoError(t, err) + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + server := grpc.NewServer() + a2agrpc.NewHandler(a2asrv.NewHandler(transportFixture{executor})).RegisterWith(server) + serveDone := make(chan error, 1) + go func() { serveDone <- server.Serve(listener) }() + t.Cleanup(func() { server.Stop(); require.NoError(t, <-serveDone) }) + connection, err := grpc.NewClient(listener.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, connection.Close()) }) + client := a2apb.NewA2AServiceClient(connection) + ctx, cancel := context.WithTimeout(t.Context(), 90*time.Second) + defer cancel() + contextID := "" + for i, prompt := range []string{"Calculate six times seven.", "Continue the calculation."} { + message := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart(prompt)) + message.ContextID = contextID + request, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: message}) + require.NoError(t, err) + stream, err := client.SendStreamingMessage(ctx, request) + require.NoError(t, err) + var text strings.Builder + completed := false + for { + response, err := stream.Recv() + if err == io.EOF { + break + } + require.NoError(t, err) + event, err := pbconv.FromProtoStreamResponse(response) + require.NoError(t, err) + switch event := event.(type) { + case *a2atype.Task: + contextID = event.ContextID + case *a2atype.TaskArtifactUpdateEvent: + for _, part := range event.Artifact.Parts { + text.WriteString(part.Text()) + } + case *a2atype.TaskStatusUpdateEvent: + if event.Status.State == a2atype.TaskStateCompleted { + completed = true + } + require.NotEqual(t, a2atype.TaskStateFailed, event.Status.State) + } + } + require.True(t, completed) + want := "product=42" + if i == 1 { + want = "resumed product=42" + } + require.Equal(t, want, text.String()) + } + mu.Lock() + defer mu.Unlock() + require.Equal(t, int32(1), toolCalls.Load()) + require.Len(t, requests, 3) + require.Contains(t, string(requests[1]), "42") + require.Contains(t, string(requests[2]), "product=42") +} + +// The production App's controller-backed TaskStore publishes the initial task. +// This transport-only fixture substitutes an SDK-local task for that boundary. +type transportFixture struct{ a2asrv.AgentExecutor } + +func (f transportFixture) Execute(ctx context.Context, input *a2asrv.ExecutorContext) iter.Seq2[a2atype.Event, error] { + return func(yield func(a2atype.Event, error) bool) { + if input.TaskID == "" { + input.TaskID = a2atype.NewTaskID() + } + if input.ContextID == "" { + input.ContextID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa" + } + if !yield(a2atype.NewSubmittedTask(input, input.Message), nil) { + return + } + for event, err := range f.AgentExecutor.Execute(ctx, input) { + if !yield(event, err) { + return + } + } + } +} + +func writeCompletion(w http.ResponseWriter, delta any, finish string) { + w.Header().Set("Content-Type", "text/event-stream") + for _, choice := range []any{map[string]any{"delta": delta, "index": 0, "finish_reason": nil}, map[string]any{"delta": map[string]any{}, "index": 0, "finish_reason": finish}} { + data, _ := json.Marshal(map[string]any{"id": "chat-test", "object": "chat.completion.chunk", "model": "mock", "choices": []any{choice}}) + fmt.Fprintf(w, "data: %s\n\n", data) + } + fmt.Fprint(w, "data: [DONE]\n\n") +} diff --git a/go/harness/byo/dsh/internal/bridge/events.go b/go/harness/byo/dsh/internal/bridge/events.go new file mode 100644 index 0000000000..3c3f9c1cba --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/events.go @@ -0,0 +1,148 @@ +package bridge + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +type content struct { + Type string `json:"type"` + Text string `json:"text,omitempty"` +} +type toolContent struct { + Type string `json:"type"` + Content content `json:"content"` +} +type update struct { + SessionUpdate string `json:"sessionUpdate"` + ToolCallID string `json:"toolCallId"` + Title string `json:"title"` + Status string `json:"status"` + RawInput json.RawMessage `json:"rawInput"` + Content json.RawMessage `json:"content"` +} +type notification struct { + SessionID string `json:"sessionId"` + Update update `json:"update"` +} +type permission struct { + SessionID string `json:"sessionId"` + ToolCall struct { + ID string `json:"toolCallId"` + } `json:"toolCall"` + Options []struct { + ID string `json:"optionId"` + Kind string `json:"kind"` + } `json:"options"` +} + +type tool struct { + name string + args map[string]any + declined bool +} +type events struct { + sessionID string + tools map[string]tool +} + +func (e *events) apply(data json.RawMessage, sink runtime.EventSink) error { + var n notification + if err := json.Unmarshal(data, &n); err != nil { + return fmt.Errorf("failed to decode ACP update: %w", err) + } + if n.SessionID != e.sessionID { + return fmt.Errorf("ACP update has mismatched session identity") + } + u := n.Update + switch u.SessionUpdate { + case "agent_message_chunk": + var c content + if err := json.Unmarshal(u.Content, &c); err != nil { + return fmt.Errorf("failed to decode ACP text: %w", err) + } + if c.Type != "text" { + return fmt.Errorf("DSH BYO supports text output only") + } + return sink.TextDelta(runtime.TextDelta{Text: c.Text}) + case "tool_call": + if u.ToolCallID == "" || u.Title == "" { + return fmt.Errorf("ACP tool call omitted identity or name") + } + if _, exists := e.tools[u.ToolCallID]; exists { + return fmt.Errorf("ACP tool call identity was reused") + } + args := make(map[string]any) + if len(u.RawInput) != 0 && string(u.RawInput) != "null" { + if err := json.Unmarshal(u.RawInput, &args); err != nil { + return fmt.Errorf("ACP tool arguments must be an object") + } + } + e.tools[u.ToolCallID] = tool{name: u.Title, args: args} + return sink.ToolCall(runtime.ToolCall{ID: u.ToolCallID, Name: u.Title, Arguments: args}) + case "tool_call_update": + t, exists := e.tools[u.ToolCallID] + if !exists { + return fmt.Errorf("ACP tool result has no matching call") + } + if u.Status == "pending" || u.Status == "in_progress" { + return nil + } + if u.Status != "completed" && u.Status != "failed" { + return fmt.Errorf("unsupported ACP tool status") + } + var output []toolContent + if len(u.Content) != 0 { + if err := json.Unmarshal(u.Content, &output); err != nil { + return fmt.Errorf("failed to decode ACP tool result: %w", err) + } + } + delete(e.tools, u.ToolCallID) + // A2A data parts must contain JSON-compatible values, not private Go structs. + var text strings.Builder + for _, block := range output { + if block.Type != "content" || block.Content.Type != "text" { + return fmt.Errorf("DSH BYO supports text tool results only") + } + text.WriteString(block.Content.Text) + } + status := runtime.ToolRan + if t.declined { + status = runtime.ToolDeclined + } + return sink.ToolResult(runtime.ToolResult{ID: u.ToolCallID, Name: t.name, Result: text.String(), IsError: u.Status == "failed", Status: status}) + case "agent_thought_chunk", "usage_update", "config_option_update", "current_mode_update": + // Context occupancy is not per-request token usage. Do not invent ModelCall metrics. + return nil + default: + return fmt.Errorf("unsupported ACP session update") + } +} + +func (e *events) approval(id json.RawMessage, data json.RawMessage) (*runtime.ApprovalRequest, string, string, error) { + var p permission + if err := json.Unmarshal(data, &p); err != nil { + return nil, "", "", fmt.Errorf("failed to decode ACP permission request: %w", err) + } + t, exists := e.tools[p.ToolCall.ID] + if p.SessionID != e.sessionID || !exists { + return nil, "", "", fmt.Errorf("ACP permission request has no matching session and tool") + } + allow, reject := "", "" + for _, option := range p.Options { + switch option.Kind { + case "allow_once": + allow = option.ID + case "reject_once": + reject = option.ID + } + } + if allow == "" || reject == "" { + return nil, "", "", fmt.Errorf("ACP permission request must offer one-shot allow and reject") + } + request := &runtime.ApprovalRequest{ID: "dsh-acp:" + string(id), CallID: p.ToolCall.ID, Name: t.name, Args: t.args} + return request, allow, reject, nil +} diff --git a/go/harness/byo/dsh/internal/bridge/integration_test.go b/go/harness/byo/dsh/internal/bridge/integration_test.go new file mode 100644 index 0000000000..20af5f4244 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/integration_test.go @@ -0,0 +1,161 @@ +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +// This test uses the published DSH executable and a local OpenAI-compatible endpoint. +// It needs no provider credentials and checks conversation recovery after process exit. +func TestRealDSHResumesConversation(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("set DSH_TEST_BIN to the pinned DSH executable") + } + var mu sync.Mutex + var requests []json.RawMessage + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/v1/chat/completions" { + http.NotFound(w, r) + return + } + var body json.RawMessage + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, "invalid JSON", 400) + return + } + mu.Lock() + requests = append(requests, body) + index := len(requests) + mu.Unlock() + text := "first result" + if index == 2 { + text = "second result" + } + w.Header().Set("Content-Type", "text/event-stream") + for _, choice := range []any{ + map[string]any{"delta": map[string]string{"role": "assistant", "content": text}, "index": 0, "finish_reason": nil}, + map[string]any{"delta": map[string]any{}, "index": 0, "finish_reason": "stop"}, + } { + data, _ := json.Marshal(map[string]any{"id": "chat-test", "object": "chat.completion.chunk", "model": "mock", "choices": []any{choice}}) + fmt.Fprintf(w, "data: %s\n\n", data) + } + fmt.Fprint(w, "data: [DONE]\n\n") + })) + defer server.Close() + data, err := json.Marshal(struct { + Model struct { + Type string `json:"type"` + Model string `json:"model"` + BaseURL string `json:"base_url"` + } `json:"model"` + Instruction string `json:"instruction"` + Runtime struct { + ControlPlaneURL string `json:"control_plane_url"` + } `json:"runtime"` + }{Model: struct { + Type string `json:"type"` + Model string `json:"model"` + BaseURL string `json:"base_url"` + }{Type: "openai", Model: "mock", BaseURL: server.URL + "/v1"}, Instruction: "Keep answers short.", Runtime: struct { + ControlPlaneURL string `json:"control_plane_url"` + }{ControlPlaneURL: "http://controller:8083"}}) + require.NoError(t, err) + cfg, err := config.Parse(data) + require.NoError(t, err) + runner, err := New(cfg, executable, t.TempDir(), append(os.Environ(), "OPENAI_API_KEY=mock")) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 90*time.Second) + defer cancel() + require.NoError(t, runner.Validate(ctx)) + first := &recordingSink{} + out, err := runner.Run(ctx, runtime.Turn{Prompt: "Remember the number 27."}, first) + require.NoError(t, err) + require.Nil(t, out.Failure) + require.Nil(t, out.Pending) + require.Equal(t, "first result", strings.Join(first.texts, "")) + require.NotEmpty(t, first.id) + second := &recordingSink{} + out, err = runner.Run(ctx, runtime.Turn{Prompt: "Continue the previous conversation.", ContinuationID: first.id}, second) + require.NoError(t, err) + require.Nil(t, out.Failure) + require.Equal(t, first.id, second.id) + require.Equal(t, "second result", strings.Join(second.texts, "")) + mu.Lock() + defer mu.Unlock() + require.Len(t, requests, 2) + require.Contains(t, string(requests[0]), "Keep answers short.") + require.Contains(t, string(requests[1]), "first result") + require.Contains(t, string(requests[1]), "Remember the number 27.") +} + +func TestRealDSHCancelsAndResumes(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("set DSH_TEST_BIN to the pinned DSH executable") + } + started := make(chan struct{}) + cleanup := make(chan struct{}) + var requests atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if _, err := io.Copy(io.Discard, r.Body); err != nil { + return + } + if requests.Add(1) == 1 { + close(started) + select { + case <-r.Context().Done(): + case <-cleanup: + } + return + } + writeCompletion(w, map[string]string{"role": "assistant", "content": "recovered"}, "stop") + })) + defer func() { close(cleanup); server.Close() }() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock","base_url":%q},"runtime":{"control_plane_url":"http://controller:8083"}}`, server.URL+"/v1"))) + require.NoError(t, err) + runner, err := New(cfg, executable, t.TempDir(), append(os.Environ(), "OPENAI_API_KEY=mock")) + require.NoError(t, err) + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + sink := &recordingSink{} + done := make(chan error, 1) + go func() { _, err := runner.Run(ctx, runtime.Turn{Prompt: "Start a long operation."}, sink); done <- err }() + select { + case <-started: + cancel() + case <-time.After(30 * time.Second): + t.Fatal("DSH did not start the model request") + } + select { + case err := <-done: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(15 * time.Second): + t.Fatal("DSH cancellation did not settle") + } + require.NotEmpty(t, sink.id) + resumeCtx, resumeCancel := context.WithTimeout(t.Context(), 30*time.Second) + defer resumeCancel() + resumed := &recordingSink{} + out, err := runner.Run(resumeCtx, runtime.Turn{Prompt: "Continue after cancellation.", ContinuationID: sink.id}, resumed) + require.NoError(t, err) + require.Nil(t, out.Failure) + require.Equal(t, "recovered", strings.Join(resumed.texts, "")) + require.Equal(t, sink.id, resumed.id) + require.Equal(t, int32(2), requests.Load()) +} diff --git a/go/harness/byo/dsh/internal/bridge/mcp.go b/go/harness/byo/dsh/internal/bridge/mcp.go new file mode 100644 index 0000000000..a22f128485 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/mcp.go @@ -0,0 +1,136 @@ +package bridge + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "net/http" + "strings" + "time" + + "github.com/modelcontextprotocol/go-sdk/mcp" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" +) + +// mcpProxy keeps kagent's HTTP timeout and session-close policy outside ACP, +// whose MCP declarations cannot carry those settings. +type mcpProxy struct { + server *http.Server + done chan error + cancel context.CancelFunc + sessions []*mcp.ClientSession + transports []*http.Transport + servers []config.MCPServer +} + +func startMCP(ctx context.Context, cfg *config.Config, bindings []config.MCPServer) (_ *mcpProxy, returnErr error) { + root, cancel := context.WithCancel(context.WithoutCancel(ctx)) + p := &mcpProxy{cancel: cancel} + defer func() { + if returnErr != nil { + returnErr = errors.Join(returnErr, p.close()) + } + }() + mux := http.NewServeMux() + for i, binding := range bindings { + params := cfg.Agent.HttpTools[i].Params + timeout := 30 * time.Second + if params.Timeout != nil { + timeout = time.Duration(*params.Timeout * float64(time.Second)) + } + terminate := params.TerminateOnClose == nil || *params.TerminateOnClose + transport := http.DefaultTransport.(*http.Transport).Clone() + p.transports = append(p.transports, transport) + httpClient := &http.Client{Timeout: timeout, Transport: headerTransport{base: transport, headers: binding.Headers, terminate: terminate}} + connectCtx, connectCancel := context.WithTimeout(ctx, timeout) + session, err := mcp.NewClient(&mcp.Implementation{Name: "kagent-dsh-byo", Version: "1"}, nil).Connect(connectCtx, &mcp.StreamableClientTransport{Endpoint: binding.URL, HTTPClient: httpClient}, nil) + if err != nil { + connectCancel() + return nil, fmt.Errorf("failed to connect MCP binding %d: %w", i, err) + } + p.sessions = append(p.sessions, session) + server := mcp.NewServer(&mcp.Implementation{Name: binding.Name, Version: "1"}, nil) + cursor := "" + for { + listed, err := session.ListTools(connectCtx, &mcp.ListToolsParams{Cursor: cursor}) + if err != nil { + connectCancel() + return nil, fmt.Errorf("failed to discover MCP binding %d: %w", i, err) + } + for _, tool := range listed.Tools { + name := tool.Name + server.AddTool(tool, func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + callCtx, callCancel := context.WithTimeout(ctx, timeout) + defer callCancel() + return session.CallTool(callCtx, &mcp.CallToolParams{Name: name, Arguments: request.Params.Arguments}) + }) + } + if listed.NextCursor == "" { + break + } + if listed.NextCursor == cursor { + connectCancel() + return nil, fmt.Errorf("MCP binding %d repeated a discovery cursor", i) + } + cursor = listed.NextCursor + } + connectCancel() + path := fmt.Sprintf("/mcp/%d", i) + mux.Handle(path, mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return server }, &mcp.StreamableHTTPOptions{Stateless: true})) + p.servers = append(p.servers, config.MCPServer{Type: "http", Name: binding.Name, URL: path, Headers: []config.Header{}}) + } + if len(bindings) == 0 { + return p, nil + } + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, fmt.Errorf("failed to listen for local MCP bridge: %w", err) + } + for i := range p.servers { + p.servers[i].URL = "http://" + listener.Addr().String() + p.servers[i].URL + } + p.server = &http.Server{Handler: mux, ReadHeaderTimeout: 5 * time.Second, BaseContext: func(net.Listener) context.Context { return root }} + p.done = make(chan error, 1) + go func() { p.done <- p.server.Serve(listener) }() + return p, nil +} + +func (p *mcpProxy) close() error { + p.cancel() + var err error + if p.server != nil { + err = errors.Join(err, p.server.Close()) + if serveErr := <-p.done; serveErr != nil && !errors.Is(serveErr, http.ErrServerClosed) { + err = errors.Join(err, serveErr) + } + } + for _, session := range p.sessions { + err = errors.Join(err, session.Close()) + } + for _, transport := range p.transports { + transport.CloseIdleConnections() + } + return err +} + +type headerTransport struct { + base http.RoundTripper + headers []config.Header + terminate bool +} + +var _ http.RoundTripper = headerTransport{} + +func (t headerTransport) RoundTrip(request *http.Request) (*http.Response, error) { + if request.Method == http.MethodDelete && !t.terminate { + return &http.Response{StatusCode: http.StatusOK, Header: make(http.Header), Body: io.NopCloser(strings.NewReader("")), Request: request}, nil + } + request = request.Clone(request.Context()) + for _, header := range t.headers { + request.Header.Set(header.Name, header.Value) + } + return t.base.RoundTrip(request) +} diff --git a/go/harness/byo/dsh/internal/bridge/mcp_test.go b/go/harness/byo/dsh/internal/bridge/mcp_test.go new file mode 100644 index 0000000000..f613b5d815 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/mcp_test.go @@ -0,0 +1,96 @@ +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "sync/atomic" + "testing" + "time" + + "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" +) + +func TestMCPProxyHonorsHeadersAndSessionTermination(t *testing.T) { + for _, terminate := range []bool{true, false} { + t.Run(fmt.Sprint(terminate), func(t *testing.T) { + var deletes atomic.Int32 + remote := mcp.NewServer(&mcp.Implementation{Name: "remote", Version: "1"}, nil) + type input struct { + A int `json:"a"` + B int `json:"b"` + } + type output struct { + Product int `json:"product"` + } + mcp.AddTool(remote, &mcp.Tool{Name: "multiply"}, func(_ context.Context, _ *mcp.CallToolRequest, arguments input) (*mcp.CallToolResult, output, error) { + return nil, output{Product: arguments.A * arguments.B}, nil + }) + handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return remote }, nil) + httpServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "kagent-credential-injected" { + http.Error(w, "missing auth", http.StatusUnauthorized) + return + } + if r.Method == http.MethodDelete { + deletes.Add(1) + } + handler.ServeHTTP(w, r) + })) + defer httpServer.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"},"http_tools":[{"params":{"url":%q,"timeout":30,"terminate_on_close":%t,"headers":{"Authorization":"__KAGENT_ENV[KAGENT_CREDENTIAL_TEST]__"}}}]}`, httpServer.URL, terminate))) + require.NoError(t, err) + bindings, err := cfg.Bindings([]string{"KAGENT_CREDENTIAL_TEST=kagent-credential-injected"}) + require.NoError(t, err) + proxy, err := startMCP(t.Context(), cfg, bindings) + require.NoError(t, err) + client, err := mcp.NewClient(&mcp.Implementation{Name: "test", Version: "1"}, nil).Connect(t.Context(), &mcp.StreamableClientTransport{Endpoint: proxy.servers[0].URL}, nil) + require.NoError(t, err) + result, err := client.CallTool(t.Context(), &mcp.CallToolParams{Name: "multiply", Arguments: map[string]int{"a": 6, "b": 7}}) + require.NoError(t, err) + data, err := json.Marshal(result.StructuredContent) + require.NoError(t, err) + require.JSONEq(t, `{"product":42}`, string(data)) + require.NoError(t, client.Close()) + require.NoError(t, proxy.close()) + want := int32(0) + if terminate { + want = 1 + } + require.Equal(t, want, deletes.Load()) + }) + } +} + +func TestMCPProxyAppliesConfiguredTimeout(t *testing.T) { + release := make(chan struct{}) + remote := mcp.NewServer(&mcp.Implementation{Name: "slow", Version: "1"}, nil) + mcp.AddTool(remote, &mcp.Tool{Name: "wait"}, func(ctx context.Context, _ *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, struct{}, error) { + select { + case <-ctx.Done(): + return nil, struct{}{}, ctx.Err() + case <-release: + return &mcp.CallToolResult{}, struct{}{}, nil + } + }) + httpServer := httptest.NewServer(mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return remote }, &mcp.StreamableHTTPOptions{Stateless: true})) + defer func() { close(release); httpServer.Close() }() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"},"http_tools":[{"params":{"url":%q,"timeout":0.2,"terminate_on_close":true}}]}`, httpServer.URL))) + require.NoError(t, err) + proxy, err := startMCP(t.Context(), cfg, cfg.MCP) + require.NoError(t, err) + defer func() { require.NoError(t, proxy.close()) }() + client, err := mcp.NewClient(&mcp.Implementation{Name: "test", Version: "1"}, nil).Connect(t.Context(), &mcp.StreamableClientTransport{Endpoint: proxy.servers[0].URL}, nil) + require.NoError(t, err) + defer func() { require.NoError(t, client.Close()) }() + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) + defer cancel() + _, err = client.CallTool(ctx, &mcp.CallToolParams{Name: "wait", Arguments: struct{}{}}) + require.Error(t, err) + require.NoError(t, ctx.Err(), "the shorter binding timeout must fail before the caller's deadline") +} diff --git a/go/harness/byo/dsh/internal/bridge/rpc.go b/go/harness/byo/dsh/internal/bridge/rpc.go new file mode 100644 index 0000000000..d2864cdeca --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/rpc.go @@ -0,0 +1,142 @@ +package bridge + +import ( + "bufio" + "context" + "encoding/json" + "fmt" + "io" + "sync" +) + +const maxFrameBytes = 4 << 20 + +type rpcError struct { + Code int `json:"code"` + Message string `json:"message"` +} +type message struct { + JSONRPC string `json:"jsonrpc"` + ID json.RawMessage `json:"id,omitempty"` + Method string `json:"method,omitempty"` + Params json.RawMessage `json:"params,omitempty"` + Result json.RawMessage `json:"result,omitempty"` + Error *rpcError `json:"error,omitempty"` +} +type frame struct { + message message + err error +} + +type wire struct { + writer io.Writer + mu sync.Mutex + frames chan frame + done chan struct{} + readDone chan struct{} +} + +func newWire(writer io.Writer, reader io.Reader) *wire { + w := &wire{writer: writer, frames: make(chan frame, 16), done: make(chan struct{}), readDone: make(chan struct{})} + go w.read(reader) + return w +} + +func (w *wire) read(reader io.Reader) { + defer close(w.frames) + defer close(w.readDone) + scanner := bufio.NewScanner(reader) + scanner.Buffer(make([]byte, 4096), maxFrameBytes) + for scanner.Scan() { + var m message + err := json.Unmarshal(scanner.Bytes(), &m) + if err != nil || m.JSONRPC != "2.0" { + w.deliver(frame{err: fmt.Errorf("invalid DSH ACP frame")}) + return + } + if !w.deliver(frame{message: m}) { + return + } + } + if err := scanner.Err(); err != nil { + w.deliver(frame{err: fmt.Errorf("failed to read DSH ACP frame: %w", err)}) + } +} + +func (w *wire) deliver(f frame) bool { + select { + case w.frames <- f: + return true + case <-w.done: + return false + } +} + +func (w *wire) send(m message, params any) error { + if params != nil { + data, err := json.Marshal(params) + if err != nil { + return fmt.Errorf("failed to encode ACP parameters: %w", err) + } + m.Params = data + } + data, err := json.Marshal(m) + if err != nil { + return fmt.Errorf("failed to encode ACP message: %w", err) + } + w.mu.Lock() + defer w.mu.Unlock() + if _, err := w.writer.Write(append(data, '\n')); err != nil { + return fmt.Errorf("failed to write ACP message: %w", err) + } + return nil +} + +func (w *wire) respond(id json.RawMessage, result any) error { + data, err := json.Marshal(result) + if err != nil { + return fmt.Errorf("failed to encode ACP response: %w", err) + } + return w.send(message{JSONRPC: "2.0", ID: id, Result: data}, nil) +} + +func (w *wire) next(ctx context.Context) (message, error) { + select { + case <-ctx.Done(): + return message{}, ctx.Err() + case f, ok := <-w.frames: + if !ok { + return message{}, fmt.Errorf("DSH ACP stream closed") + } + return f.message, f.err + } +} + +// Setup calls have no active turn, so requests are rejected and updates ignored. +func (w *wire) call(ctx context.Context, id string, method string, params any) (json.RawMessage, error) { + if err := w.send(message{JSONRPC: "2.0", ID: json.RawMessage(id), Method: method}, params); err != nil { + return nil, err + } + for { + m, err := w.next(ctx) + if err != nil { + return nil, err + } + if m.Method != "" { + if len(m.ID) != 0 { + return nil, fmt.Errorf("unexpected ACP request during initialization") + } + continue + } + if string(m.ID) != id { + return nil, fmt.Errorf("unexpected ACP response identity") + } + if m.Error != nil { + return nil, fmt.Errorf("DSH ACP %s failed (code %d)", method, m.Error.Code) + } + if len(m.Result) == 0 { + return nil, fmt.Errorf("ACP response omitted result") + } + return m.Result, nil + } +} diff --git a/go/harness/byo/dsh/internal/bridge/rpc_test.go b/go/harness/byo/dsh/internal/bridge/rpc_test.go new file mode 100644 index 0000000000..090926936a --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/rpc_test.go @@ -0,0 +1,42 @@ +package bridge + +import ( + "context" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWireRejectsMalformedAndOversizedFrames(t *testing.T) { + for _, test := range []struct{ name, data string }{ + {"not JSON", "startup log\n"}, + {"wrong version", `{"jsonrpc":"1.0","id":1,"result":{}}` + "\n"}, + {"oversized", strings.Repeat("x", maxFrameBytes+1) + "\n"}, + } { + t.Run(test.name, func(t *testing.T) { + w := newWire(io.Discard, strings.NewReader(test.data)) + _, err := w.next(context.Background()) + require.Error(t, err) + close(w.done) + <-w.readDone + }) + } +} + +func TestWireChecksResponseIdentityAndHidesErrorContent(t *testing.T) { + for _, test := range []struct{ name, data string }{ + {"wrong response", `{"jsonrpc":"2.0","id":2,"result":{}}`}, + {"remote error", `{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"secret"}}`}, + } { + t.Run(test.name, func(t *testing.T) { + w := newWire(io.Discard, strings.NewReader(test.data+"\n")) + _, err := w.call(t.Context(), "1", "initialize", struct{}{}) + require.Error(t, err) + require.NotContains(t, err.Error(), "secret") + close(w.done) + <-w.readDone + }) + } +} diff --git a/go/harness/byo/dsh/internal/bridge/runner.go b/go/harness/byo/dsh/internal/bridge/runner.go new file mode 100644 index 0000000000..8e7790614a --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/runner.go @@ -0,0 +1,359 @@ +// Package bridge supervises a pinned DSH ACP process behind the existing A2A executor. +package bridge + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/internal/utils" + "github.com/kagent-dev/kagent/go/harness/runtime" + runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" +) + +const ( + setupTimeout = 30 * time.Second + stopTimeout = 5 * time.Second + promptID = "3" +) + +type Runner struct { + config *config.Config + executable string + dataDir string + workspace string + environment []string + servers []config.MCPServer +} + +var _ runtimea2a.Runner = (*Runner)(nil) + +func New(cfg *config.Config, executable, dataDir string, environment []string) (*Runner, error) { + if cfg == nil || !filepath.IsAbs(dataDir) { + return nil, fmt.Errorf("configuration and an absolute data directory are required") + } + for _, path := range []string{dataDir, filepath.Join(dataDir, "workspace"), filepath.Join(dataDir, "dsh", "sessions"), filepath.Join(dataDir, "dsh", "storages")} { + if err := utils.EnsurePrivateDir(path); err != nil { + return nil, err + } + } + servers, err := cfg.Bindings(environment) + if err != nil { + return nil, err + } + return &Runner{config: cfg, executable: executable, dataDir: dataDir, workspace: filepath.Join(dataDir, "workspace"), environment: append([]string(nil), environment...), servers: servers}, nil +} + +func (r *Runner) Validate(ctx context.Context) error { + command := exec.CommandContext(ctx, r.executable, "--version") + command.Env = r.environment + output, err := command.Output() + if err != nil { + return fmt.Errorf("failed to check DSH version: %w", err) + } + if strings.TrimSpace(string(output)) != config.Version { + return fmt.Errorf("DSH BYO requires version %s", config.Version) + } + return nil +} + +type process struct { + command *exec.Cmd + stdin io.WriteCloser + wire *wire + done chan struct{} + waitErr error + home string + events events + mcp *mcpProxy +} + +func (r *Runner) start(ctx context.Context) (*process, error) { + home, err := os.MkdirTemp("", "kagent-dsh-") + if err != nil { + return nil, fmt.Errorf("failed to create DSH launch directory: %w", err) + } + patch, err := r.config.Patch(r.dataDir) + if err != nil { + return nil, errors.Join(err, os.RemoveAll(home)) + } + path := filepath.Join(home, "compiled.patch.json") + if err := utils.ReplacePrivateFile(path, patch); err != nil { + return nil, errors.Join(err, os.RemoveAll(home)) + } + cmd := exec.Command(r.executable, "--profile", "acp", "--patch", path) + cmd.Dir, cmd.Env, cmd.Stderr = r.workspace, config.Environment(r.environment, home), io.Discard + utils.ConfigureProcessGroup(cmd) + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, errors.Join(fmt.Errorf("failed to open DSH stdin: %w", err), os.RemoveAll(home)) + } + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, errors.Join(fmt.Errorf("failed to open DSH stdout: %w", err), stdin.Close(), os.RemoveAll(home)) + } + if err := cmd.Start(); err != nil { + return nil, errors.Join(fmt.Errorf("failed to start DSH: %w", err), stdin.Close(), stdout.Close(), os.RemoveAll(home)) + } + p := &process{command: cmd, stdin: stdin, wire: newWire(stdin, stdout), done: make(chan struct{}), home: home, events: events{tools: make(map[string]tool)}} + go func() { p.waitErr = cmd.Wait(); close(p.done) }() + proxy, err := startMCP(ctx, r.config, r.servers) + if err != nil { + return nil, errors.Join(err, p.stop()) + } + p.mcp = proxy + return p, nil +} + +func (r *Runner) Run(ctx context.Context, turn runtime.Turn, sink runtime.EventSink) (out runtime.Outcome, returnErr error) { + if strings.TrimSpace(turn.Prompt) == "" { + return out, fmt.Errorf("DSH prompt is required") + } + p, err := r.start(ctx) + if err != nil { + return out, err + } + defer func() { + if out.Pending == nil { + returnErr = errors.Join(returnErr, p.stop()) + } + }() + setupCtx, cancel := context.WithTimeout(ctx, setupTimeout) + defer cancel() + result, err := p.wire.call(setupCtx, "1", "initialize", struct { + ProtocolVersion int `json:"protocolVersion"` + ClientCapabilities struct{} `json:"clientCapabilities"` + }{ProtocolVersion: 1}) + if err != nil { + return out, err + } + var init struct { + ProtocolVersion int `json:"protocolVersion"` + AgentCapabilities struct { + MCP struct { + HTTP bool `json:"http"` + } `json:"mcpCapabilities"` + Sessions struct { + Resume json.RawMessage `json:"resume"` + } `json:"sessionCapabilities"` + } `json:"agentCapabilities"` + } + if err := json.Unmarshal(result, &init); err != nil { + return out, fmt.Errorf("failed to decode ACP initialization: %w", err) + } + if init.ProtocolVersion != 1 || (len(r.config.MCP) > 0 && !init.AgentCapabilities.MCP.HTTP) { + return out, fmt.Errorf("DSH ACP does not advertise required protocol capabilities") + } + method := "session/new" + if turn.ContinuationID != "" { + if len(init.AgentCapabilities.Sessions.Resume) == 0 { + return out, fmt.Errorf("DSH ACP does not advertise session resume") + } + method = "session/resume" + } + servers := p.mcp.servers + if servers == nil { + servers = []config.MCPServer{} + } + result, err = p.wire.call(setupCtx, "2", method, struct { + SessionID string `json:"sessionId,omitempty"` + CWD string `json:"cwd"` + MCPServers []config.MCPServer `json:"mcpServers"` + }{SessionID: turn.ContinuationID, CWD: r.workspace, MCPServers: servers}) + if err != nil { + return out, err + } + id := turn.ContinuationID + if id == "" { + var created struct { + SessionID string `json:"sessionId"` + } + if err := json.Unmarshal(result, &created); err != nil { + return out, fmt.Errorf("failed to decode ACP session: %w", err) + } + id = created.SessionID + } + if err := ValidateSessionID(id); err != nil { + return out, err + } + p.events.sessionID = id + if err := sink.SessionStarted(runtime.SessionStarted{ContinuationID: id}); err != nil { + return out, err + } + if err := p.wire.send(message{JSONRPC: "2.0", ID: json.RawMessage(promptID), Method: "session/prompt"}, struct { + SessionID string `json:"sessionId"` + Prompt []content `json:"prompt"` + }{SessionID: id, Prompt: []content{{Type: "text", Text: turn.Prompt}}}); err != nil { + return out, err + } + return p.collect(ctx, sink) +} + +func ValidateSessionID(id string) error { + if id == "" || len(id) > 256 || strings.ContainsAny(id, "/\\\x00\r\n\t ") { + return fmt.Errorf("invalid DSH session identity") + } + return nil +} + +func (p *process) collect(ctx context.Context, sink runtime.EventSink) (runtime.Outcome, error) { + for { + m, err := p.wire.next(ctx) + if err != nil { + if ctx.Err() != nil { + return runtime.Outcome{}, errors.Join(ctx.Err(), p.cancel()) + } + return runtime.Outcome{}, err + } + switch { + case m.Method == "session/update" && len(m.ID) == 0: + if err := p.events.apply(m.Params, sink); err != nil { + return runtime.Outcome{}, err + } + case m.Method == "session/request_permission" && len(m.ID) != 0: + request, allow, reject, err := p.events.approval(m.ID, m.Params) + if err != nil { + return runtime.Outcome{}, err + } + return runtime.Outcome{Pending: &pending{process: p, id: m.ID, request: request, allow: allow, reject: reject}}, nil + case m.Method != "" && len(m.ID) != 0: + return runtime.Outcome{}, fmt.Errorf("unsupported ACP server request") + case m.Method != "": + return runtime.Outcome{}, fmt.Errorf("unsupported ACP notification") + default: + if string(m.ID) != promptID { + return runtime.Outcome{}, fmt.Errorf("unexpected ACP prompt response identity") + } + if m.Error != nil { + return runtime.Outcome{Failure: &runtime.Failure{Message: fmt.Sprintf("DSH ACP prompt failed (code %d)", m.Error.Code)}}, nil + } + var result struct { + StopReason string `json:"stopReason"` + } + if err := json.Unmarshal(m.Result, &result); err != nil { + return runtime.Outcome{}, fmt.Errorf("failed to decode ACP completion: %w", err) + } + switch result.StopReason { + case "end_turn", "max_tokens", "max_turn_requests": + case "refusal", "cancelled": + return runtime.Outcome{Failure: &runtime.Failure{Message: "DSH stopped: " + result.StopReason}}, nil + default: + return runtime.Outcome{}, fmt.Errorf("unsupported ACP stop reason") + } + closeCtx, cancel := context.WithTimeout(context.Background(), stopTimeout) + defer cancel() + _, err := p.wire.call(closeCtx, "4", "session/close", sessionParams{SessionID: p.events.sessionID}) + return runtime.Outcome{}, err + } + } +} + +type sessionParams struct { + SessionID string `json:"sessionId"` +} +type permissionResponse struct { + Outcome permissionOutcome `json:"outcome"` +} +type permissionOutcome struct { + Outcome string `json:"outcome"` + OptionID string `json:"optionId,omitempty"` +} + +type pending struct { + process *process + id json.RawMessage + request *runtime.ApprovalRequest + allow, reject string +} + +var _ runtime.PendingTurn = (*pending)(nil) + +func (p *pending) Request() runtime.InputRequest { return p.request } + +func (p *pending) Resume(ctx context.Context, response runtime.InputResponse, sink runtime.EventSink) (out runtime.Outcome, returnErr error) { + defer func() { + if out.Pending == nil { + returnErr = errors.Join(returnErr, p.process.stop()) + } + }() + decision, ok := response.(*runtime.ApprovalDecision) + if !ok || decision.ID != p.request.ID { + return out, fmt.Errorf("approval decision does not match pending DSH request") + } + option := p.reject + if decision.Approved { + option = p.allow + } else { + tool := p.process.events.tools[p.request.CallID] + tool.declined = true + p.process.events.tools[p.request.CallID] = tool + } + if err := p.process.wire.respond(p.id, permissionResponse{Outcome: permissionOutcome{Outcome: "selected", OptionID: option}}); err != nil { + return out, err + } + return p.process.collect(ctx, sink) +} + +func (p *pending) Cancel(_ context.Context, _ runtime.ModelCallSink) error { + err := p.process.wire.respond(p.id, permissionResponse{Outcome: permissionOutcome{Outcome: "cancelled"}}) + return errors.Join(err, p.process.cancel(), p.process.stop()) +} + +func (p *process) cancel() error { + if err := p.wire.send(message{JSONRPC: "2.0", Method: "session/cancel"}, sessionParams{SessionID: p.events.sessionID}); err != nil { + return err + } + ctx, cancel := context.WithTimeout(context.Background(), stopTimeout) + defer cancel() + for { + m, err := p.wire.next(ctx) + if err != nil { + return err + } + if string(m.ID) == promptID && m.Method == "" { + return nil + } + if m.Method != "" && len(m.ID) != 0 { + if m.Method != "session/request_permission" { + return fmt.Errorf("unsupported ACP request during cancellation") + } + if err := p.wire.respond(m.ID, permissionResponse{Outcome: permissionOutcome{Outcome: "cancelled"}}); err != nil { + return err + } + } + } +} + +// EOF lets DSH flush persistence; escalation is bounded and reaps the process group. +func (p *process) stop() error { + close(p.wire.done) + err := p.stdin.Close() + select { + case <-p.done: + case <-time.After(stopTimeout): + if signalErr := utils.TerminateProcessGroup(p.command.Process); signalErr != nil && !errors.Is(signalErr, os.ErrProcessDone) { + err = errors.Join(err, signalErr) + } + select { + case <-p.done: + case <-time.After(stopTimeout): + if signalErr := utils.KillProcessGroup(p.command.Process); signalErr != nil && !errors.Is(signalErr, os.ErrProcessDone) { + err = errors.Join(err, signalErr) + } + <-p.done + } + } + <-p.wire.readDone + if p.mcp != nil { + err = errors.Join(err, p.mcp.close()) + } + return errors.Join(err, p.waitErr, os.RemoveAll(p.home)) +} diff --git a/go/harness/byo/dsh/internal/bridge/runner_test.go b/go/harness/byo/dsh/internal/bridge/runner_test.go new file mode 100644 index 0000000000..4a315d6139 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/runner_test.go @@ -0,0 +1,239 @@ +package bridge + +import ( + "bufio" + "context" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +type recordingSink struct { + id string + texts []string + calls []runtime.ToolCall + results []runtime.ToolResult + callReady chan struct{} +} + +func (s *recordingSink) SessionStarted(v runtime.SessionStarted) error { + s.id = v.ContinuationID + return nil +} +func (s *recordingSink) TextDelta(v runtime.TextDelta) error { + s.texts = append(s.texts, v.Text) + return nil +} +func (s *recordingSink) ToolCall(v runtime.ToolCall) error { + s.calls = append(s.calls, v) + if s.callReady != nil { + close(s.callReady) + s.callReady = nil + } + return nil +} +func (s *recordingSink) ToolResult(v runtime.ToolResult) error { + s.results = append(s.results, v) + return nil +} +func (s *recordingSink) ModelCall(runtime.ModelCall) {} + +func testRunner(t *testing.T, mode string) *Runner { + t.Helper() + c, err := config.Parse([]byte(`{"model":{"type":"openai","model":"mock","base_url":"http://localhost:1234/v1"},"instruction":"system","runtime":{"control_plane_url":"http://controller:8083"}}`)) + require.NoError(t, err) + executable, err := os.Executable() + require.NoError(t, err) + path := filepath.Join(t.TempDir(), "dsh") + quoted := "'" + strings.ReplaceAll(executable, "'", "'\\''") + "'" + require.NoError(t, os.WriteFile(path, []byte("#!/bin/sh\nexec "+quoted+" -test.run=TestACPHelperProcess -- \"$@\"\n"), 0700)) + r, err := New(c, path, t.TempDir(), append(os.Environ(), "KAGENT_DSH_TEST_HELPER=1", "KAGENT_DSH_TEST_MODE="+mode)) + require.NoError(t, err) + require.NoError(t, r.Validate(context.Background())) + return r +} + +func TestTurnsResumeAndEmitToolResults(t *testing.T) { + r := testRunner(t, "") + for _, id := range []string{"", "session-test"} { + sink := &recordingSink{} + out, err := r.Run(t.Context(), runtime.Turn{Prompt: "work", ContinuationID: id}, sink) + require.NoError(t, err) + require.Nil(t, out.Pending) + require.Nil(t, out.Failure) + require.Equal(t, "session-test", sink.id) + require.Equal(t, []string{"finished"}, sink.texts) + require.Len(t, sink.calls, 1) + require.Equal(t, "read", sink.calls[0].Name) + require.Len(t, sink.results, 1) + require.False(t, sink.results[0].IsError) + } +} + +func TestPermissionResumeAndCancel(t *testing.T) { + for _, mode := range []string{"allow", "reject", "cancel"} { + t.Run(mode, func(t *testing.T) { + r := testRunner(t, "approval") + sink := &recordingSink{} + out, err := r.Run(t.Context(), runtime.Turn{Prompt: "work"}, sink) + require.NoError(t, err) + require.NotNil(t, out.Pending) + request := out.Pending.Request().(*runtime.ApprovalRequest) + require.Equal(t, "tool-1", request.CallID) + if mode == "cancel" { + require.NoError(t, out.Pending.Cancel(t.Context(), sink)) + return + } + out, err = out.Pending.Resume(t.Context(), &runtime.ApprovalDecision{ID: request.ID, Approved: mode == "allow"}, sink) + require.NoError(t, err) + require.Nil(t, out.Pending) + require.Equal(t, mode == "reject", sink.results[0].IsError) + }) + } +} + +func TestActiveCancellationReapsProcessAndAllowsNextTurn(t *testing.T) { + r := testRunner(t, "hang") + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + ready := make(chan struct{}) + sink := &recordingSink{callReady: ready} + done := make(chan error, 1) + go func() { _, err := r.Run(ctx, runtime.Turn{Prompt: "work"}, sink); done <- err }() + select { + case <-ready: + cancel() + case <-time.After(10 * time.Second): + t.Fatal("prompt did not start") + } + select { + case err := <-done: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(10 * time.Second): + t.Fatal("cancellation did not settle") + } + r.environment = append(r.environment, "KAGENT_DSH_TEST_MODE=") + _, err := r.Run(t.Context(), runtime.Turn{Prompt: "next", ContinuationID: "session-test"}, &recordingSink{}) + require.NoError(t, err) +} + +func TestRejectsWrongSessionAndSanitizesRemoteErrors(t *testing.T) { + for _, mode := range []string{"wrong-session", "remote-error"} { + t.Run(mode, func(t *testing.T) { + out, err := testRunner(t, mode).Run(t.Context(), runtime.Turn{Prompt: "work"}, &recordingSink{}) + if mode == "remote-error" { + require.NoError(t, err) + require.NotNil(t, out.Failure) + require.NotContains(t, out.Failure.Message, "secret") + } else { + require.Error(t, err) + } + }) + } +} + +// A real subprocess exercises framing, request correlation, EOF cleanup and cancellation. +func TestACPHelperProcess(t *testing.T) { + if os.Getenv("KAGENT_DSH_TEST_HELPER") != "1" { + return + } + for _, arg := range os.Args { + if arg == "--version" { + fmt.Println(config.Version) + os.Exit(0) + } + } + mode := os.Getenv("KAGENT_DSH_TEST_MODE") + writer := bufio.NewWriter(os.Stdout) + write := func(m message) { + data, err := json.Marshal(m) + if err != nil { + os.Exit(2) + } + fmt.Fprintln(writer, string(data)) + if err := writer.Flush(); err != nil { + os.Exit(3) + } + } + result := func(id json.RawMessage, value any) { + data, _ := json.Marshal(value) + write(message{JSONRPC: "2.0", ID: id, Result: data}) + } + notify := func(u any) { + data, _ := json.Marshal(struct { + SessionID string `json:"sessionId"` + Update any `json:"update"` + }{SessionID: "session-test", Update: u}) + write(message{JSONRPC: "2.0", Method: "session/update", Params: data}) + } + finish := func(failed bool) { + status := "completed" + if failed { + status = "failed" + } + notify(map[string]any{"sessionUpdate": "tool_call_update", "toolCallId": "tool-1", "status": status, "content": []any{}}) + notify(map[string]any{"sessionUpdate": "agent_message_chunk", "content": content{Type: "text", Text: "finished"}}) + result(json.RawMessage(promptID), map[string]string{"stopReason": "end_turn"}) + } + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + var m message + if err := json.Unmarshal(scanner.Bytes(), &m); err != nil { + os.Exit(4) + } + switch m.Method { + case "initialize": + result(m.ID, json.RawMessage(`{"protocolVersion":1,"agentCapabilities":{"mcpCapabilities":{"http":true},"sessionCapabilities":{"resume":{}}}}`)) + case "session/new": + result(m.ID, map[string]string{"sessionId": "session-test"}) + case "session/resume": + var p sessionParams + _ = json.Unmarshal(m.Params, &p) + if p.SessionID != "session-test" { + os.Exit(5) + } + result(m.ID, struct{}{}) + case "session/prompt": + if mode == "remote-error" { + write(message{JSONRPC: "2.0", ID: m.ID, Error: &rpcError{Code: -32603, Message: "secret credential"}}) + continue + } + if mode == "wrong-session" { + write(message{JSONRPC: "2.0", Method: "session/update", Params: json.RawMessage(`{"sessionId":"other","update":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"wrong"}}}`)}) + continue + } + notify(map[string]any{"sessionUpdate": "tool_call", "toolCallId": "tool-1", "title": "read", "status": "in_progress", "rawInput": map[string]string{"path": "file"}}) + if mode == "approval" { + write(message{JSONRPC: "2.0", ID: json.RawMessage("99"), Method: "session/request_permission", Params: json.RawMessage(`{"sessionId":"session-test","toolCall":{"toolCallId":"tool-1"},"options":[{"optionId":"allow-once","kind":"allow_once"},{"optionId":"reject-once","kind":"reject_once"}]}`)}) + } else if mode != "hang" { + finish(false) + } + case "session/cancel": + result(json.RawMessage(promptID), map[string]string{"stopReason": "cancelled"}) + case "session/close": + result(m.ID, struct{}{}) + case "": + var response permissionResponse + _ = json.Unmarshal(m.Result, &response) + if response.Outcome.Outcome != "cancelled" { + finish(response.Outcome.OptionID == "reject-once") + } + default: + os.Exit(6) + } + } + if err := scanner.Err(); err != nil && !errors.Is(err, os.ErrClosed) { + os.Exit(7) + } + os.Exit(0) +} diff --git a/go/harness/byo/dsh/internal/config/config.go b/go/harness/byo/dsh/internal/config/config.go new file mode 100644 index 0000000000..2b8748cf39 --- /dev/null +++ b/go/harness/byo/dsh/internal/config/config.go @@ -0,0 +1,210 @@ +// Package config translates the existing BYO payload into DSH launch inputs. +package config + +import ( + "encoding/json" + "fmt" + "net/url" + "path/filepath" + "slices" + "strings" + "time" + + "github.com/kagent-dev/kagent/go/api/adk" +) + +const ( + Version = "0.2.0-rc.2" + Provider = "kagent-byo" +) + +type Header struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type MCPServer struct { + Type string `json:"type"` + Name string `json:"name"` + URL string `json:"url"` + Headers []Header `json:"headers"` +} + +// Config retains the controller-owned payload without inventing another public API. +type Config struct { + Agent adk.AgentConfig + Model *adk.OpenAI + MCP []MCPServer +} + +func Parse(data []byte) (*Config, error) { + var agent adk.AgentConfig + if err := json.Unmarshal(data, &agent); err != nil { + return nil, fmt.Errorf("failed to decode BYO configuration: %w", err) + } + if err := agent.ValidateRuntime(); err != nil { + return nil, err + } + model, ok := agent.Model.(*adk.OpenAI) + if !ok || model.Model == "" { + return nil, fmt.Errorf("DSH BYO requires an OpenAI-compatible ModelConfig") + } + if model.APIFormat != "" && model.APIFormat != "chatCompletions" { + return nil, fmt.Errorf("DSH BYO supports only chatCompletions") + } + if model.APIKeyPassthrough || model.TokenExchange != nil || model.TLSCACertPath != nil || model.TLSDisableSystemCAs != nil || (model.TLSInsecureSkipVerify != nil && *model.TLSInsecureSkipVerify) { + return nil, fmt.Errorf("DSH BYO requires gateway-injected credentials and platform trust") + } + if model.FrequencyPenalty != nil || model.MaxTokens != nil || model.MaxCompletionTokens != nil || model.N != nil || model.PresencePenalty != nil || model.ReasoningEffort != nil || model.Seed != nil || model.Temperature != nil || model.Timeout != nil || model.TopP != nil { + return nil, fmt.Errorf("DSH BYO does not yet map OpenAI generation overrides") + } + if agent.Runtime == nil || agent.Runtime.ControlPlaneURL == "" { + return nil, fmt.Errorf("runtime.control_plane_url is required") + } + if agent.Runtime.TokenPropagation.Enabled { + return nil, fmt.Errorf("DSH BYO does not support token propagation") + } + if agent.Stream != nil && !*agent.Stream { + return nil, fmt.Errorf("DSH BYO requires streaming model requests") + } + if len(agent.SubAgents) != 0 || len(agent.RemoteAgents) != 0 || agent.AgentPlugins != nil || agent.Memory != nil || agent.ContextConfig != nil || agent.Output != nil || agent.SkillsDirectory != "" || len(agent.SseTools) != 0 || len(agent.StdioTools) != 0 || agent.Network != nil { + return nil, fmt.Errorf("DSH BYO supports a root agent and whole Streamable HTTP MCP servers; kagent skills, plugins, subagents and ADK-specific settings are unsupported") + } + baseURL := model.BaseUrl + if baseURL == "" { + baseURL = "https://api.openai.com/v1" + } + if err := httpURL(baseURL); err != nil { + return nil, err + } + model.BaseUrl = baseURL + c := &Config{Agent: agent, Model: model} + for i, server := range agent.HttpTools { + if len(server.Tools) != 0 || server.RequireApproval || len(server.AllowedHeaders) != 0 { + return nil, fmt.Errorf("MCP binding %d: tool selection, requireApproval and forwarded headers are unsupported by DSH ACP", i) + } + if server.Params.SseReadTimeout != nil || server.Params.TLSCACertPath != nil || server.Params.TLSDisableSystemCAs != nil || (server.Params.TLSInsecureSkipVerify != nil && *server.Params.TLSInsecureSkipVerify) { + return nil, fmt.Errorf("MCP binding %d: connection overrides are unsupported by DSH ACP", i) + } + if server.Params.Timeout != nil && time.Duration(*server.Params.Timeout*float64(time.Second)) <= 0 { + return nil, fmt.Errorf("MCP binding %d: timeout must be positive and fit a Go duration", i) + } + if err := httpURL(server.Params.Url); err != nil { + return nil, err + } + headers := make([]Header, 0, len(server.Params.Headers)) + for name, value := range server.Params.Headers { + headers = append(headers, Header{Name: name, Value: value}) + } + slices.SortFunc(headers, func(a, b Header) int { return strings.Compare(a.Name, b.Name) }) + c.MCP = append(c.MCP, MCPServer{Type: "http", Name: fmt.Sprintf("kagent_%d", i), URL: server.Params.Url, Headers: headers}) + } + return c, nil +} + +func httpURL(value string) error { + u, err := url.Parse(value) + if err != nil || u.Hostname() == "" || u.User != nil || (u.Scheme != "http" && u.Scheme != "https") { + return fmt.Errorf("DSH endpoint must be an absolute HTTP(S) URL without userinfo") + } + return nil +} + +type patch struct { + ID string `json:"id"` + Config any `json:"config,omitempty"` + Disabled bool `json:"disabled,omitempty"` +} + +type route struct { + Provider string `json:"provider"` + Model string `json:"model"` +} +type persona struct { + Prefix string `json:"personaPrefix"` +} +type directory struct { + Root string `json:"root"` +} +type providerConfig struct { + Providers map[string]provider `json:"providers"` +} +type provider struct { + API string `json:"api"` + BaseURL string `json:"baseURL"` + APIKeyEnv string `json:"apiKeyEnv"` + Headers map[string]string `json:"headers,omitempty"` + Models []modelEntry `json:"models"` +} +type modelEntry struct { + ID string `json:"id"` + Input []string `json:"input"` +} + +// Patch generates JSON (valid YAML) without interpolating user text into code. +// Only runtime-private session data is durable; the launcher profile is disposable. +func (c *Config) Patch(dataDir string) ([]byte, error) { + rows := []patch{ + {ID: "llm-pi-ai", Config: providerConfig{Providers: map[string]provider{Provider: { + API: "openai-completions", BaseURL: c.Model.BaseUrl, APIKeyEnv: "OPENAI_API_KEY", Headers: c.Model.Headers, + Models: []modelEntry{{ID: c.Model.Model, Input: []string{"text"}}}, + }}}}, + {ID: "acp", Config: route{Provider: Provider, Model: c.Model.Model}}, + {ID: "agent-default-model", Config: route{Provider: Provider, Model: c.Model.Model}}, + {ID: "system-prompt", Config: persona{Prefix: c.Agent.Instruction}}, + {ID: "session-persistence-jsonl", Config: directory{Root: filepath.Join(dataDir, "dsh", "sessions")}}, + {ID: "storage-json", Config: directory{Root: filepath.Join(dataDir, "dsh", "storages")}}, + // These optional network consumers are outside the compiled ModelConfig/MCP egress contract. + {ID: "tool-web", Disabled: true}, + {ID: "otel", Disabled: true}, + {ID: "otel-exporter", Disabled: true}, + } + data, err := json.Marshal(rows) + if err != nil { + return nil, fmt.Errorf("failed to encode DSH patch: %w", err) + } + return data, nil +} + +// Environment preserves platform CA/proxy settings and gateway placeholders. +// Per-process homes prevent persisted profile edits from changing composition. +func Environment(environment []string, home string) []string { + result := make([]string, 0, len(environment)+3) + for _, entry := range environment { + name, _, _ := strings.Cut(entry, "=") + if name == "DSH_HOME" || name == "DSH_AGENTS_HOME" || name == "DSH_TELEMETRY_DISABLED" || name == "KAGENT_TOKEN" { + continue + } + result = append(result, entry) + } + return append(result, "DSH_HOME="+home, "DSH_AGENTS_HOME="+filepath.Join(home, "agents"), "DSH_TELEMETRY_DISABLED=1") +} + +// Bindings resolves the ADK compiler's MCP header references to inert gateway +// placeholders. Actual Secret values must never enter DSH's persisted session. +func (c *Config) Bindings(environment []string) ([]MCPServer, error) { + values := make(map[string]string, len(environment)) + for _, entry := range environment { + name, value, ok := strings.Cut(entry, "=") + if ok { + values[name] = value + } + } + servers := append([]MCPServer(nil), c.MCP...) + for i := range servers { + servers[i].Headers = slices.Clone(servers[i].Headers) + for j, header := range servers[i].Headers { + const prefix, suffix = "__KAGENT_ENV[", "]__" + if !strings.HasPrefix(header.Value, prefix) || !strings.HasSuffix(header.Value, suffix) { + continue + } + name := strings.TrimSuffix(strings.TrimPrefix(header.Value, prefix), suffix) + value := values[name] + if !strings.HasPrefix(name, "KAGENT_CREDENTIAL_") || value != "kagent-credential-injected" { + return nil, fmt.Errorf("MCP credential reference requires a gateway-injected placeholder") + } + servers[i].Headers[j].Value = value + } + } + return servers, nil +} diff --git a/go/harness/byo/dsh/internal/config/config_test.go b/go/harness/byo/dsh/internal/config/config_test.go new file mode 100644 index 0000000000..86002f22a3 --- /dev/null +++ b/go/harness/byo/dsh/internal/config/config_test.go @@ -0,0 +1,104 @@ +package config + +import ( + "encoding/json" + "maps" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +const valid = `{"model":{"type":"openai","model":"deepseek-chat","base_url":"https://api.deepseek.com/v1"},"instruction":"Answer accurately.","runtime":{"control_plane_url":"http://controller:8083"}}` + +func TestParseRejectsUnsupportedSemantics(t *testing.T) { + for _, test := range []struct{ name, field string }{ + {"missing model", `"model":null`}, + {"responses", `"model":{"type":"openai","model":"x","api_format":"responses"}`}, + {"generation overrides", `"model":{"type":"openai","model":"x","temperature":0.2}`}, + {"credential passthrough", `"model":{"type":"openai","model":"x","api_key_passthrough":true}`}, + {"model userinfo", `"model":{"type":"openai","model":"x","base_url":"https://key@example.com/v1"}`}, + {"subagents", `"sub_agents":[{}]`}, + {"plugins", `"agent_plugins":{}`}, + {"memory", `"memory":{}`}, + {"SSE", `"sse_tools":[{}]`}, + {"non-streaming", `"stream":false`}, + {"MCP tool subset", `"http_tools":[{"params":{"url":"https://tools.example/mcp"},"tools":["read"]}]`}, + {"MCP approval", `"http_tools":[{"params":{"url":"https://tools.example/mcp"},"require_approval":true}]`}, + {"MCP forwarded headers", `"http_tools":[{"params":{"url":"https://tools.example/mcp"},"allowed_headers":["authorization"]}]`}, + } { + t.Run(test.name, func(t *testing.T) { + var fields map[string]json.RawMessage + require.NoError(t, json.Unmarshal([]byte(valid), &fields)) + var change map[string]json.RawMessage + require.NoError(t, json.Unmarshal([]byte("{"+test.field+"}"), &change)) + maps.Copy(fields, change) + data, err := json.Marshal(fields) + require.NoError(t, err) + _, err = Parse(data) + require.Error(t, err) + }) + } +} + +func TestMCPReferencesUseOnlyGatewayPlaceholders(t *testing.T) { + c, err := Parse([]byte(valid)) + require.NoError(t, err) + c.MCP = []MCPServer{{Type: "http", Name: "tools", URL: "https://tools.example/mcp", Headers: []Header{{Name: "Authorization", Value: "__KAGENT_ENV[KAGENT_CREDENTIAL_TEST]__"}}}} + servers, err := c.Bindings([]string{"KAGENT_CREDENTIAL_TEST=kagent-credential-injected"}) + require.NoError(t, err) + require.Equal(t, "kagent-credential-injected", servers[0].Headers[0].Value) + require.Equal(t, "__KAGENT_ENV[KAGENT_CREDENTIAL_TEST]__", c.MCP[0].Headers[0].Value) + for _, env := range [][]string{nil, {"KAGENT_CREDENTIAL_TEST=actual-secret"}} { + _, err = c.Bindings(env) + require.Error(t, err) + require.NotContains(t, err.Error(), "actual-secret") + } +} + +func TestPatchPreservesInstructionAndUsesDurableState(t *testing.T) { + c, err := Parse([]byte(valid)) + require.NoError(t, err) + c.Agent.Instruction = "quotes: \"\n!!js doNotExecute()\n$variable" + data, err := c.Patch("/data") + require.NoError(t, err) + var rows []struct { + ID string `json:"id"` + Config json.RawMessage `json:"config"` + } + require.NoError(t, json.Unmarshal(data, &rows)) + for _, row := range rows { + if row.ID == "system-prompt" { + var p persona + require.NoError(t, json.Unmarshal(row.Config, &p)) + require.Equal(t, c.Agent.Instruction, p.Prefix) + } + if row.ID == "session-persistence-jsonl" { + require.JSONEq(t, `{"root":"/data/dsh/sessions"}`, string(row.Config)) + } + } + require.Contains(t, string(data), `"apiKeyEnv":"OPENAI_API_KEY"`) +} + +func TestWholeHTTPMCPAndEnvironment(t *testing.T) { + data := strings.TrimSuffix(valid, "}") + `,"http_tools":[{"params":{"url":"https://tools.example/mcp","headers":{"z":"last","a":"first"}}}]}` + c, err := Parse([]byte(data)) + require.NoError(t, err) + require.Equal(t, []Header{{Name: "a", Value: "first"}, {Name: "z", Value: "last"}}, c.MCP[0].Headers) + env := Environment([]string{"NODE_EXTRA_CA_CERTS=/run/trust.pem", "OPENAI_API_KEY=placeholder", "DSH_HOME=/old", "DSH_TELEMETRY_DISABLED=0", "KAGENT_TOKEN=controller-token"}, "/tmp/dsh") + require.Contains(t, env, "NODE_EXTRA_CA_CERTS=/run/trust.pem") + require.Contains(t, env, "OPENAI_API_KEY=placeholder") + require.NotContains(t, env, "DSH_HOME=/old") + require.Contains(t, env, "DSH_TELEMETRY_DISABLED=1") + require.NotContains(t, env, "KAGENT_TOKEN=controller-token") +} + +func TestBindingsPreserveEmptyHeaderArray(t *testing.T) { + c, err := Parse([]byte(strings.TrimSuffix(valid, "}") + `,"http_tools":[{"params":{"url":"https://tools.example/mcp"}}]}`)) + require.NoError(t, err) + servers, err := c.Bindings(nil) + require.NoError(t, err) + data, err := json.Marshal(servers) + require.NoError(t, err) + require.Contains(t, string(data), `"headers":[]`) +} diff --git a/go/harness/byo/dsh/package-lock.json b/go/harness/byo/dsh/package-lock.json new file mode 100644 index 0000000000..3c5acacf29 --- /dev/null +++ b/go/harness/byo/dsh/package-lock.json @@ -0,0 +1,9093 @@ +{ + "name": "kagent-dsh-byo-runtime", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "kagent-dsh-byo-runtime", + "version": "0.1.0", + "dependencies": { + "@deepseek-ai/dsh": "0.2.0-rc.2" + } + }, + "node_modules/@agentclientprotocol/sdk": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-1.4.0.tgz", + "integrity": "sha512-/eufudw+aFY1LKLolT6yFE6UMmYRl7fMJ/DEONSIyR6wI3slHWITBsANRGqXEY8FRzqUxwh7QEaGiZHcJPVThg==", + "license": "Apache-2.0", + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.124.0.tgz", + "integrity": "sha512-cN5O8i9UVxHeOQAzj/XjshWXG8KiibJDw9OGpH2Z/eR3n/RBxdoLxDJOcfqAJWvjaMDFfHTBADU04hWRJVkDyA==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1", + "standardwebhooks": "^1.0.0" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1127.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1127.0.tgz", + "integrity": "sha512-IDl/lrPb90aH+pZFHGNDmgH9nAUQj5PlZH1sJ3w7RikctyjHSnY3oNjZhrLoaBoQn/rNK0zsP6OHEqEhj2tdLA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/credential-provider-node": "^3.972.82", + "@aws-sdk/eventstream-handler-node": "^3.972.34", + "@aws-sdk/middleware-eventstream": "^3.972.29", + "@aws-sdk/middleware-websocket": "^3.972.52", + "@aws-sdk/token-providers": "3.1127.0", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/fetch-http-handler": "^5.7.2", + "@smithy/node-http-handler": "^4.11.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.978.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.3.tgz", + "integrity": "sha512-nslpzUCTI9b2IQMWSd6mSAXldBexPc8rr0d3dXUutXYFLFaTdsHa2GD7sJdsn3PhyjK0O5K8ypd6zi+RXXPVlg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.6", + "@aws-sdk/xml-builder": "^3.972.41", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.35.2", + "@smithy/signature-v4": "^5.7.4", + "@smithy/types": "^4.19.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.74", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.74.tgz", + "integrity": "sha512-rsRJcW2iFUhCgclyD6OSbMEaPl8Eu0qSeRZb2uuCK1ViZ66hl5wOe/p6Vr6MO3b+ydyKgFeqza2p6tZThvILlw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.76", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.76.tgz", + "integrity": "sha512-pnKdh0Br7OJPj+7qKjzgTfDTFW0RhEMKXNDR2jv9CAM4oHuG/4z3hRh8KtutLfpmItuRtDbKBmwWkDqHwwAWXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.19", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.19.tgz", + "integrity": "sha512-kcjvAxqQEV8yuwkX58RelNn3ne65o7JgRWf3Z/gVvbi7Xuw1qSDLJlatrLD76+40cmRxmNkLxBoyp/vAQChQ5g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/credential-provider-env": "^3.972.74", + "@aws-sdk/credential-provider-http": "^3.972.76", + "@aws-sdk/credential-provider-login": "^3.972.81", + "@aws-sdk/credential-provider-process": "^3.972.74", + "@aws-sdk/credential-provider-sso": "^3.973.18", + "@aws-sdk/credential-provider-web-identity": "^3.972.80", + "@aws-sdk/nested-clients": "^3.997.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.81", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.81.tgz", + "integrity": "sha512-CeQHSbE2CnVdaHIJ/NayRaCecIER+Pm9faUPkmRATO54rCoMTEPSbVieGHzEwvm1dZM2HIs6qQZCznhayNTWJQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/nested-clients": "^3.997.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.86", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.86.tgz", + "integrity": "sha512-WNttSyr6e8innPtBSty//CdnqJcgZN6eAbtw3v/CR2IObz6MYZEo8eusdtuCHJ2ujwFqC2bSPHVyhXGHx8HruQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.74", + "@aws-sdk/credential-provider-http": "^3.972.76", + "@aws-sdk/credential-provider-ini": "^3.973.19", + "@aws-sdk/credential-provider-process": "^3.972.74", + "@aws-sdk/credential-provider-sso": "^3.973.18", + "@aws-sdk/credential-provider-web-identity": "^3.972.80", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.74", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.74.tgz", + "integrity": "sha512-Yj6kZFJQdbR+PygTkqdVLPHHpdDpOS9GCYVcDCuweCRRig9LF24ELQBMfyUw1vspvrZJUfnOGVyMjhaL094ahw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.18", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.18.tgz", + "integrity": "sha512-FnpPhdY4qUGtX/8X6eKxh+uD+9Y19i9FYibgk4SBe0M935s9vocHkHzaxaMNk+YkHmvzgdu8cHA5SCoeU+kkew==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/nested-clients": "^3.997.48", + "@aws-sdk/token-providers": "3.1150.0", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.1150.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1150.0.tgz", + "integrity": "sha512-wDU36ofhabZYu+d2KSriyDbwzxNoaOp+4dG0p3qkabk7HeALR5nIWyQbjoyJZLn3iqWkv/xNdyUfbfevDVDzzg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/nested-clients": "^3.997.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.80", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.80.tgz", + "integrity": "sha512-TJF25Ndwy2HxcVj6oxMgp8qVlJAawlExHYBXqhuC6Zt2m+A7WpdkjBD6QglNbiArlteYljZHEY3R7KKmno6ISA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/nested-clients": "^3.997.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.36", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.36.tgz", + "integrity": "sha512-HFaKXA6ugPVvpR7W/3UT3hylWIPndqGMwduwNVrmGsRT5+OESHN8/ven4eeofraQF5Kxp8A8QgGVrv7iQsTRKQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.31.tgz", + "integrity": "sha512-4yvdTVwPGKCnrwuwlYEmwLqQXKwk0unx3f/FvBi4FA9ruK/WGoPJyqfK7hOYurheIyQL44FR0ovgOHqvkfdpAQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.56", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.56.tgz", + "integrity": "sha512-32d9EnnNM5UMwjVp/qnL0K4XYiZv+YlSbULI3BaoBdJvebAS6cD0bKfPJ7lzovN0qrelvmSh5jo/3tk0KoTuGQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/signature-v4": "^5.7.4", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.48", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.48.tgz", + "integrity": "sha512-B01jdXJtAW/XOiUzGdI2mz67WyEHbGEc9X6Euzw3bjLAa+txTqdZDER4X2FsIEcXzV2ABqudVZ5thali8tCCzQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.3", + "@aws-sdk/signature-v4-multi-region": "^3.996.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.48", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.48.tgz", + "integrity": "sha512-cFDXfEbXaGwbnpvR/DyqfxfjxpjXVRVthQLgkwvcfDS5u3+8G9WSj1X1Ag/pTRg/QOeOno1Tq3ycEdrKsCUcOA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.6", + "@smithy/signature-v4": "^5.7.4", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1127.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1127.0.tgz", + "integrity": "sha512-Dv2TMWBshJ+tF6ahs2Sy5bh4Iabsd4GAQqVvE9XZmYmnoaVbpS2QKIKE/HRacc7bTtbjEEvP+laGzHvHlf1CiQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/nested-clients": "^3.997.44", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.6.tgz", + "integrity": "sha512-v/clNZzZnDxGyvpHMOGpJKVXFAExJzUNAAjaWGdcx8QAcXLGwTaOkw33p5SHAi0YAioK32xB3hWwOekRVfmfKg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.41.tgz", + "integrity": "sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.10.tgz", + "integrity": "sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@deepseek-ai/cordis": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis/-/cordis-4.0.4.tgz", + "integrity": "sha512-obgyxqWAmFn3Re8kvsuUnyW+ihrz6eJCnJO4fh1cQzDtmPYz/zzVeUkH9R94I0OwSVOocK67Kgakm04j/oQXzg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "@standard-schema/spec": "^1.1.0" + }, + "bin": { + "cordis": "bin.js" + }, + "peerDependencies": { + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-include": { + "optional": true + }, + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/cordis-plugin-group": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-group/-/cordis-plugin-group-1.0.4.tgz", + "integrity": "sha512-/7tuY5pMQetHava4v6QUeOa4CwZA+mleNvbIoj+iqEmzkYUtlXbLqhzJIcbnDa/Hxgr1jaCwROrI77nuLyeCFg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-include": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-include/-/cordis-plugin-include-1.0.9.tgz", + "integrity": "sha512-Xmekm7u5Kpeym6nABL4T1/Mg6aQYFZxsipB0WycmCctvX1DqAv8nCFwRmg2XMx/f7EbZgNEbXQwJfabcMu8zxQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-loader": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-loader/-/cordis-plugin-loader-1.0.5.tgz", + "integrity": "sha512-200huL2ttWcjyeYllvPYn+qMR7I89qy8MhZasbHltPzB/KMrSfsyoCYKdCGc5KqPGj5iJugcmibQzjINMO9I+Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "node-addon-require-builtin": "^0.1.6" + }, + "peerDependenciesMeta": { + "node-addon-require-builtin": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/cordis-plugin-timer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-timer/-/cordis-plugin-timer-1.1.6.tgz", + "integrity": "sha512-/nZC7G637LIDF8G+lhF4OSXl1uFRuNAZqv1x11CDGLSjUpmIayePfzABEGTDEKAY+IBivg2DIXBr/sjjaLZxqg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/cosmokit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cosmokit/-/cosmokit-1.8.5.tgz", + "integrity": "sha512-LXsrlem9z8dq4sLflj2yuCuYX7KqhdzF5hZly3eZyuTo8d6oDSOXuEgC5DbQWKW+lksm6zmOutQLsP/ma6wR6A==", + "license": "MIT" + }, + "node_modules/@deepseek-ai/dsh": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.2.0-rc.2.tgz", + "integrity": "sha512-EAJ3gPNcVt/uv8X19PMm9NkVhWgT7xXNMk0UKCVm+IQ5rpSQOcsMUa0HWlnYYVybKMsccjcRB21vVVsaXQ6IdA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-acp-app": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-instructions": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-preset": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-tool-presentation": "0.2.0-rc.2", + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2", + "@deepseek-ai/dsh-base": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-agent-preset": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-cordis": "0.2.0-rc.2", + "@deepseek-ai/dsh-cmdline": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-compact": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-basic": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.2.0-rc.2", + "@deepseek-ai/dsh-cordis-client-runner": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-agent-team-profile": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-auto-review": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-schedule-bundle": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-voice-input-bundle": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-goal-round-driver": "0.2.0-rc.2", + "@deepseek-ai/dsh-headless": "0.2.0-rc.2", + "@deepseek-ai/dsh-hmr": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2", + "@deepseek-ai/dsh-hooks-claude-code": "0.2.0-rc.2", + "@deepseek-ai/dsh-hooks-codex": "0.2.0-rc.2", + "@deepseek-ai/dsh-http-proxy": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-mcp-client": "0.2.0-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.2.0-rc.2", + "@deepseek-ai/dsh-persona": "0.2.0-rc.2", + "@deepseek-ai/dsh-plan-mode": "0.2.0-rc.2", + "@deepseek-ai/dsh-plugin-manager": "0.2.0-rc.2", + "@deepseek-ai/dsh-pwsh-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-pwsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-schedule": "0.2.0-rc.2", + "@deepseek-ai/dsh-sdk-app": "0.2.0-rc.2", + "@deepseek-ai/dsh-sdk-minimal": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-reference": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill-filesystem": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill-office": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal-bash": "0.2.0-rc.2", + "@deepseek-ai/dsh-time-context": "0.2.0-rc.2", + "@deepseek-ai/dsh-tmux-context": "0.2.0-rc.2", + "@deepseek-ai/dsh-token-meter": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-ask-user": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-bash-persistent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-cordis": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-fs-search": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-present": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-pwsh-persistent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-ralph": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-str-replace-editor": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-subagent-control": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-web": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-workflow": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-workspace-dependencies": "0.2.0-rc.2", + "@deepseek-ai/dsh-web-app": "0.2.0-rc.2", + "@deepseek-ai/dsh-webhook": "0.2.0-rc.2", + "@deepseek-ai/dsh-webhook-github": "0.2.0-rc.2", + "@deepseek-ai/dsh-workflow-ptc": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0", + "js-yaml": "^4.2.0", + "node-addon-require-builtin": "^0.1.6" + }, + "bin": { + "dsh": "lib/bin.js" + } + }, + "node_modules/@deepseek-ai/dsh-acp": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-acp/-/dsh-acp-0.2.0-rc.2.tgz", + "integrity": "sha512-UbejJaK2DycmUbIw+N3LCdcENeD7I3fgs5xvieHQNUjEK4PKnmv8Z2em+74FG2ltKZs9l77PL3AWO0d4KcfPJg==", + "license": "MIT", + "dependencies": { + "@agentclientprotocol/sdk": "1.4.0", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-mcp-client": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-token-meter": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-token-meter": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-acp-app": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-acp-app/-/dsh-acp-app-0.2.0-rc.2.tgz", + "integrity": "sha512-4eL+Cj/kGKvf1VSEE8NFmrh+uELCUUAFesaFh0NMTxUWO9HP8f71qjkWvNl2tUcNCP9DiIxSzNTmV1PPCZ0ovw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-acp": "0.2.0-rc.2", + "@deepseek-ai/dsh-cmdline": "0.2.0-rc.2", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-agent": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent/-/dsh-agent-0.2.0-rc.2.tgz", + "integrity": "sha512-CUkbU+c1G0ETXkpoLkpAFo5midz66FQGtlgQOP9pzvU9H3zJQVl4H5LrhhGVbEXKLFgdbtQiOynEW8hpWn3y0Q==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-workspace": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-agent-default-model": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-default-model/-/dsh-agent-default-model-0.2.0-rc.2.tgz", + "integrity": "sha512-m0obV++p2V7nJp0X/04VntPisDUcNQfuyV+AuG9XhUxdm3tvFvBtY6wgNjAcqE2GMLwFVnZovCnO7GqnhBbB8A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-config-editor": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-instructions": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-instructions/-/dsh-agent-instructions-0.2.0-rc.2.tgz", + "integrity": "sha512-jasnwitU5efx5WT8X0OBapbdfssUdo+YpK7aquN7tSItCgVodN5RmGjm83zNw9awvlXjVlt7QMYeRcFUfZrZ6Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-loop": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-loop/-/dsh-agent-loop-0.2.0-rc.2.tgz", + "integrity": "sha512-Ayi1L7s1LIJAq3iCCRFDCGM9Y2lriGlV6nblIYXhKrq+J8bUFQtOdfBYNE1N39WcYb3CwSvTNHDtzZ4oW6MZ6A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-preset": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-preset/-/dsh-agent-preset-0.2.0-rc.2.tgz", + "integrity": "sha512-hrRWLO0ow0lVWqDL0nWPPZqsjUR+J05JgDoTuz1qJrpvGbXMykayOx+ZkKWy64ErkqW2pMIgT4JGYeOPoH7kmA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-preset-registry": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-preset-registry/-/dsh-agent-preset-registry-0.2.0-rc.2.tgz", + "integrity": "sha512-Awdhxsnm85ZrQASUc/fLpBHnggAnI2ar7RIJL++Lcy04Hx9q/INqJlFfCKVL68ugZGh14iJNy5/OM+ZfcmbjUw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "js-yaml": "^4.2.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-settings": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-tool-presentation": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-tool-presentation/-/dsh-agent-tool-presentation-0.2.0-rc.2.tgz", + "integrity": "sha512-TDoipfVMvuuwZglKn8eW3oVCRcMb10A1SPgj8xn753F6IWo4sDnlQ5I3/+xZ5lNfWowKJcQlBCobokHSAs/TIg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-anonymous-user-id": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-anonymous-user-id/-/dsh-anonymous-user-id-0.2.0-rc.2.tgz", + "integrity": "sha512-/VDAUjcv/xj+iPDrTTt6rC/+jo8r/H8WXEQPmjbB8W9q/cDnlp3KzM87Dy/6jT085G7a3BjsXTk0K6Bol0AcTg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-account-controller": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-account-controller/-/dsh-api-account-controller-0.2.0-rc.2.tgz", + "integrity": "sha512-auwEoRLEBcWbtdxpEoeQjeQ72dk9igh/fNJHEVPbmDLK7oXR+Yxn+hTxoT3v4IsLfQjKKljeEN4zz6aNgdbqjw==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-account": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-gateway": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-gateway/-/dsh-api-gateway-0.2.0-rc.2.tgz", + "integrity": "sha512-syeclzuoVpGor6JyDHcxg2Iwy9oeM76y4dK8abY19x1s/eMgJMCO3kL/IeKPg+d0Go7aHPTEyWRvCmfkA35U1g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "ws": "^8.21.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-client-connection": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-job-controller": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-job-controller/-/dsh-api-job-controller-0.2.0-rc.2.tgz", + "integrity": "sha512-AAAi3SaeLUHyz/qbY5iiGnU9T+d44z82b5oyQaf6HdU8tnHe7dJsO/y2YRRB52AuS+KWpXpwka1qW5XT8/9N6g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-api-remotes": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-remotes/-/dsh-api-remotes-0.2.0-rc.2.tgz", + "integrity": "sha512-mfDctTtpM26rS5O0upviPofuyiiNCkaSgRifc5wgaCiBPJ5rG1FE2lxMQSfUiBASs7s+xXR5JVZlDrrZCzYTLg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-session-controller": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-session-controller/-/dsh-api-session-controller-0.2.0-rc.2.tgz", + "integrity": "sha512-WDmk1aWOHbzIKRRt7rtHDxSupw/XLB+BgMyKHlzB7QGinXrK/Dnht6JIdgE1iSShnf1RNANGAGh2G94VzDpl5Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-deque": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "mime-types": "^3.0.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-gateway": "0.2.0-rc.2", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-connection": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-file-upload": "0.2.0-rc.2", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-file-reference": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-native-command": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-query": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-settings": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-time": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-settings": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-api-settings-controller": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-settings-controller/-/dsh-api-settings-controller-0.2.0-rc.2.tgz", + "integrity": "sha512-+tWsZLldhUVPwEKhz3o/oYVMEjnFndYwaDJnpN5PqeuEctU3PgZ/xYd5QxH44Ob/g5ROokHAkUWP8wER7+EwWA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-native-command": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-settings": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-terminal-controller": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-terminal-controller/-/dsh-api-terminal-controller-0.2.0-rc.2.tgz", + "integrity": "sha512-Cn+kZR2kHG2JH+e5eU2J7aS31c4UUGNcEkSfUizJ5SPLEa413qyFKlvVMU0DhITpljJSarpxrG6tfGqsF6mX1A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.2.0-rc.2", + "@deepseek-ai/dsh-lazy-require": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@xterm/addon-serialize": "^0.14.0", + "@xterm/headless": "^6.0.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-workspace-controller": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-workspace-controller/-/dsh-api-workspace-controller-0.2.0-rc.2.tgz", + "integrity": "sha512-3CoKQUgGxJ8yH++j/HurB4ZTrVLMZXS0cMm8Fb3ZaMB1dTseroaMoepvnBtzJF1hQx6YArNu8XvXO5qPRA6Fgg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.2.0-rc.2", + "@deepseek-ai/dsh-native-command": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-api-gateway": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-connection": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-directory-picker": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-workspace-files": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-workspace-files/-/dsh-api-workspace-files-0.2.0-rc.2.tgz", + "integrity": "sha512-X2mKXzaWOjTv2rBvZl4GyKsB63ZUHJZaq9KX2r+yaMJfguxMkWMCx0to6bdp2BPrzaD826X1D672hFY6Ps/0jA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-app-boot": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-app-boot/-/dsh-app-boot-0.2.0-rc.2.tgz", + "integrity": "sha512-WvgNhBHSj85Z7u9vC1oQr9C7yZQ/L/JS+eVK4bueWEkaoqdEna504V5bi7qtWXxAz5JkeVZTy1sX86p8XG7LJg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2", + "@deepseek-ai/dsh-package-manifest": "0.2.0-rc.2", + "@eslint-community/regexpp": "^4.12.2", + "ajv": "^8.20.0", + "js-yaml": "^4.2.0", + "node-addon-require-builtin": "^0.1.6", + "resolve.exports": "^2.0.3", + "semver": "^7.8.5" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-group": "~1.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-atomic-write": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-atomic-write/-/dsh-atomic-write-0.2.0-rc.2.tgz", + "integrity": "sha512-CezxdPmADDnOyG/ed9R18In/NifnLgu8hfJEjTBKxd7kbu0XXenyqnk25jeWD6bJYwu8AWAwcpVFuf438EJPJA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-attachment": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-attachment/-/dsh-attachment-0.2.0-rc.2.tgz", + "integrity": "sha512-asUDLv+mfb30vjjlQtMI9aBnC+kmPoUxS1ooadhwAd8wssIlLetq97nzC5W1qd0GQGwZtPG/gpljVAMcSwPr1g==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-attachment-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-attachment-local/-/dsh-attachment-local-0.2.0-rc.2.tgz", + "integrity": "sha512-VDyHGvKoN59D+3t3rwkZYNFJJJ1PbCV/6z9ngL5lErd1H98NqmFqFzGgGypGPvBGdmi42ckhVldBPq8ZJWzKcA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "sharp": "^0.35.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-authorization": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-authorization/-/dsh-authorization-0.2.0-rc.2.tgz", + "integrity": "sha512-hcvguIxKa6P5zhb6API9gLNLveQ2H2dXUo8vf2aTzoc9J4madUFltR2suUDfvusgN13qCWtbbUcgWdZt79uVuw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-base": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-base/-/dsh-base-0.2.0-rc.2.tgz", + "integrity": "sha512-AclHClefnPmUe2qoPrKMUvauA/KelYevYlxFdHLZGcPRqrDH+D21HyrwJmj4f7Iu5OO0IqfjB4zBOkwMp5h1ug==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-instructions": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-loop": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-gateway": "0.2.0-rc.2", + "@deepseek-ai/dsh-attachment-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-authorization": "0.2.0-rc.2", + "@deepseek-ai/dsh-bash-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-compact": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-feedback": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-basic": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-image-offload": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.2.0-rc.2", + "@deepseek-ai/dsh-config-editor": "0.2.0-rc.2", + "@deepseek-ai/dsh-credentials-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-account-platform": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs-observation-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-goal-round-driver": "0.2.0-rc.2", + "@deepseek-ai/dsh-hmr": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-deepseek-account": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-deepseek-api-key": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-retry": "0.2.0-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.2.0-rc.2", + "@deepseek-ai/dsh-otel": "0.2.0-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.2.0-rc.2", + "@deepseek-ai/dsh-plan-mode": "0.2.0-rc.2", + "@deepseek-ai/dsh-plugin-manager": "0.2.0-rc.2", + "@deepseek-ai/dsh-plugin-package-inventory-deepseek": "0.2.0-rc.2", + "@deepseek-ai/dsh-ptc-runtime-node": "0.2.0-rc.2", + "@deepseek-ai/dsh-pwsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-repeat-tool-reminder": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-checkpoint-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-log-deepseek": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence-jsonl": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-query-sqlite": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-telemetry-otel": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title-first-prompt-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-settings": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell-env": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill-badge": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill-filesystem": "0.2.0-rc.2", + "@deepseek-ai/dsh-spill-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-spill-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage-json": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent-fork-in-process": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent-spawn-in-process": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-token-meter": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-call-timeout-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-fs-search": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-present": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-ralph": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-subagent-control": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-web": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-workflow": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-loader": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-questions": "0.2.0-rc.2", + "@deepseek-ai/dsh-web": "0.2.0-rc.2", + "@deepseek-ai/dsh-web-fetch-http": "0.2.0-rc.2", + "@deepseek-ai/dsh-web-search-deepseek": "0.2.0-rc.2", + "@deepseek-ai/dsh-workflow-ptc": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-bash-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-bash-local/-/dsh-bash-local-0.2.0-rc.2.tgz", + "integrity": "sha512-38cihtu0JSBfj4GAH8pPX0v2tPDZBcPbgX9CjjMTPbhNRF30C+Ncg5zhJo5weaHQR0RnqOIJVuDHxcJ3yT50gg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-bash-sandbox": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-bash-sandbox/-/dsh-bash-sandbox-0.2.0-rc.2.tgz", + "integrity": "sha512-PNTarU5/b5rmkpMVqk5iHq12dktFL68B7dGofWoG9S3xKe7QXTmjQCZXPxyfMqEujtTxDE8HyLcLDE+46Nlchw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-bash-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-brand": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-brand/-/dsh-brand-0.2.0-rc.2.tgz", + "integrity": "sha512-A5XlN4tIgP0qObkYFhcZ7Oz/tM2oESEZqLwS0Qq+sM1ivGx6o4AMPgJdfKQlwLzqk0cMLNtAaVBHfiYoElt4lw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-chunked-list": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-chunked-list/-/dsh-chunked-list-0.2.0-rc.2.tgz", + "integrity": "sha512-3KJhtGoWL39UIY6dyQ/FNuwRssPzxf3Abe6BuYdGwEh8FJcEG1JgSFIltKL+mfhbp4idV3cF7EnTVutGlurMDw==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-connection": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-connection/-/dsh-client-connection-0.2.0-rc.2.tgz", + "integrity": "sha512-eL66YSZ0+HlWRzAPGU8jtCLd322WXBoMGN1g1OsM5T7Skqbbo9hSwV1FO3Lm0IcMZR3Y07sGPQBwZwf/l66T3w==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-client-file-upload": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-file-upload/-/dsh-client-file-upload-0.2.0-rc.2.tgz", + "integrity": "sha512-+uU8KHjLyHoMpslnRQZp02BtBSSBvRsJdYlH2vnVYE00b86fVtrBOvtzcF3jv1f7b0pYbph5z6ikIH8hvhzdOQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-client-hmr": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-hmr/-/dsh-client-hmr-0.2.0-rc.2.tgz", + "integrity": "sha512-hE/+LDYFelYY5ayisx1UkBVXe7hygvgI7Ts9IyJa7nZNoppsChoZQbf5iHMO/ogS5efeeyy/yS0nKOzJB9RYPw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-locale": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-locale/-/dsh-client-locale-0.2.0-rc.2.tgz", + "integrity": "sha512-JdZPMv/8hLOQNxHk1dM6YbNbChB5S6lGaGAPtraP0670i9Tb4dX+yKOAUgkS7nSoO5TYZztXgI1kgcEregRPJA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-modules": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-modules/-/dsh-client-modules-0.2.0-rc.2.tgz", + "integrity": "sha512-eDF7dycEl8QJ8CAZTSTz+dZh2PFHsf/ESAsjWjhcHxueLji7LF8/MY54PgU051Ho0V7zQKCAAeFWK2/GyIpgIg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-product-analytics": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-product-analytics/-/dsh-client-product-analytics-0.2.0-rc.2.tgz", + "integrity": "sha512-gAxwso7bK4S+5M4KURB/JzUWX55z+gZBSNpzy6dyiIwUg6SZo536hVUjzmb+Tlu72vULgZ4K/uO2zO0d1WcceQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-resources": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-resources/-/dsh-client-resources-0.2.0-rc.2.tgz", + "integrity": "sha512-fij1KTx7rBMyZHHnghZyXYWGpli9j3KrcfDBq+XhzNY2n5nidoIMIPj647DTajH+CaHFrb7f0Btj2/7Rs0d0Ng==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-shortcuts": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-shortcuts/-/dsh-client-shortcuts-0.2.0-rc.2.tgz", + "integrity": "sha512-/mgW9+qbx/XMFODH58vtBsMeZr0lFE4i+mZWqGXfHbmwG9b5POBWi6QQOcCB6tQGE1TPSeiWC8GbCJL7lGAYSg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-crypto": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-store": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-store/-/dsh-client-store-0.2.0-rc.2.tgz", + "integrity": "sha512-unHIDNnHudDIj05W99m+dVPXLYy7qNvMJ/D5FWb7cov0CbiQvliqbvFeMAU6LzC+u3vTkVJgSMIAwAVdQgYHEA==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-agent-preset": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-agent-preset/-/dsh-client-ui-agent-preset-0.2.0-rc.2.tgz", + "integrity": "sha512-G4d4OFNoqQoLrIHDu4yy0xkvJhtZdTDPAEglmAkfDt03I6ypZxNO/cer6hasDne+gqUw7iwQB35Hvo1Gg1gAFw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-approval": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-approval/-/dsh-client-ui-approval-0.2.0-rc.2.tgz", + "integrity": "sha512-r85w95YxSwl/VlwAp5G9Y984KetesWGwsoV7ZYt0lV3gAo69GwH05EkUsZr1YmrQGdpu+hHUx4GOc24Qvgdz/g==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-attachment": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-attachment/-/dsh-client-ui-attachment-0.2.0-rc.2.tgz", + "integrity": "sha512-KwJC64HYqhsT/evoYZ2EjueCRWTknwTLVTth2LrL5XXtt5tMkDYDLgr3D/SHbb6gRpmtAgEClskj3kVYJUQ6fw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-brand-official": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-brand-official/-/dsh-client-ui-brand-official-0.2.0-rc.2.tgz", + "integrity": "sha512-R0rHBtD1YWEDU0X7Tu+GvTyj1zqJUkvZmu08wXAyNGlCWvlOWyMNQyBmOjqDM7tBDuNh9yQlKw9WpcHtb0zPGw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-chat": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-chat/-/dsh-client-ui-chat-0.2.0-rc.2.tgz", + "integrity": "sha512-1rsCHGvWNLaO6B6t1fJa8Qsov0OvJC6bnhpyK2NmDCaLu9uzb4dC4DxCH3OzmJwJkEByHrb3j3l9kbpaV+dTCw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-commands": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-commands/-/dsh-client-ui-commands-0.2.0-rc.2.tgz", + "integrity": "sha512-2bbQT/isVZX+xr+Wd2FA8Wfr3Ltomt3eFapvH8EGU2Ygf9bF+msGVm3DzqfHkTAUcU6C5n6WczzGdmnFUFk33g==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-conversation": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-conversation/-/dsh-client-ui-conversation-0.2.0-rc.2.tgz", + "integrity": "sha512-Y1eWKVeh84cbB0fcV0MFOMUHBeptlzBCzsw6xslZS7p1a8l9PeFcjx5ZVTkKFuFMCfwEHWTeV9HcYqWLYH0bhw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-cordis": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-cordis/-/dsh-client-ui-cordis-0.2.0-rc.2.tgz", + "integrity": "sha512-5ScFoWmk2S0+e4a0ZxthBicpE53edBprpA3j86wdpaYbK6wAQI3nzlTYAvtuIfC+rLIBNm0mQR+GFabKnFJkpA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-deliverables": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-deliverables/-/dsh-client-ui-deliverables-0.2.0-rc.2.tgz", + "integrity": "sha512-zsPP0ZB38O+otSib61XM37jUeUWlfXMHMUO3upb2O9Rz0RhAuXyjrk7/0ZLCAtN4q+qawVnLlEMHvwIk10kheg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-browse": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-directory-picker-browse/-/dsh-client-ui-directory-picker-browse-0.2.0-rc.2.tgz", + "integrity": "sha512-RxHNr6jUawkQvMLlrwQok6CrFcZKc3TsrJS4UWGGEFZd54D0AtpnhMP5NDVo4mL/LNti6m1VSlL/8nNgMQJa1w==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-native": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-directory-picker-native/-/dsh-client-ui-directory-picker-native-0.2.0-rc.2.tgz", + "integrity": "sha512-MaFnBCKvcr4cZ1Zx6QJ3+0+n4JHB3GISNEcYWtvUPmRh1WEZCIx/MOfWdcs0bltMUezGQ7RwV6VB43lxRo3FqA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-goal": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-goal/-/dsh-client-ui-goal-0.2.0-rc.2.tgz", + "integrity": "sha512-VmboGx4kq+9EigTdvvbqiekXB0443MpS+sLBBUlr6wREL8kBjiSzkTNYX1XNHMtGXgKJULYTuTIrcaKWK/bftA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-input-trigger": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-input-trigger/-/dsh-client-ui-input-trigger-0.2.0-rc.2.tgz", + "integrity": "sha512-X63sYrlwQflDyzCbT/rBxXJtq9hEmKbzwggYmXQ3x1N+ZgNT3RQsd8Q7D3DWycNHnavoJ3R84smxY+GB6nW7MA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-jobs": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-jobs/-/dsh-client-ui-jobs-0.2.0-rc.2.tgz", + "integrity": "sha512-UhiL5YGvHSXXg9PRyOFuqu79XIMsgxCSeGxpiX+mr5JK41mZ9MX4NSDNXh8yyuwzjKQlt/HPpOYuv5uTfaGG0w==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-layout": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-layout/-/dsh-client-ui-layout-0.2.0-rc.2.tgz", + "integrity": "sha512-OZzGxqoAV5zHPgFveJnw599J0j0pWbJiD5c5hdPeLyNMdRdTa2CC2gR7fbn63XGu08O+OruTDXHkCrOVuvkdQw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-message-feedback": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-message-feedback/-/dsh-client-ui-message-feedback-0.2.0-rc.2.tgz", + "integrity": "sha512-de4g5/IjIMEUHOGTWr6yqduBkmYfpA0BmqGchqQbsrYvmnvGqOOzo/rkcyC8uq1XIF55HfHEhgqKFmA1R0AwqA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-model-selection": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-model-selection/-/dsh-client-ui-model-selection-0.2.0-rc.2.tgz", + "integrity": "sha512-fL6Iyirvk4xOMjbioguxv3E/iAf4AlfqnA9WhEPwdK/0wV7StMKhuAcZkbz2o3kEFHBE98yroyzrbM//yJv4ow==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-open-in-app": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-open-in-app/-/dsh-client-ui-open-in-app-0.2.0-rc.2.tgz", + "integrity": "sha512-T8xjc7I2YAB4iPC4XlmiTFfksKkOPRt7iSX8yWD+rJCjznbqWVS9fiPDI0IaNwrQRf9mR9mGdc14jkHpWcEG3g==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-permission-presets": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-permission-presets/-/dsh-client-ui-permission-presets-0.2.0-rc.2.tgz", + "integrity": "sha512-qeawIA9Q2rBpn0wlv7cCpkk0zssb8vR1nhrh0igeXJOHpz27CA3jEwy31pfc9hcR24PAWgXcwfZnqWu00HwRAA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-plan": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-plan/-/dsh-client-ui-plan-0.2.0-rc.2.tgz", + "integrity": "sha512-uXaj8o+CKLGd56rsl8rfJporCAnzX+XArs5lTRq6DvD7tyO3iah2wy/e3Hsa3RLdv5dz19S6oUqldn/mNxIcEA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-plugin-manager": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-plugin-manager/-/dsh-client-ui-plugin-manager-0.2.0-rc.2.tgz", + "integrity": "sha512-AncAiGUMawllpfnqirmABN7KXwmVEhu0E8ClJvfsLDhEd2oazZ6nk2nUPHHPu1tVKq+e8IbiTHqwpnlDR7mPUA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-primitives": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-primitives/-/dsh-client-ui-primitives-0.2.0-rc.2.tgz", + "integrity": "sha512-Zx/MRT8NH6rYEvPnk4FQaHrADM6Dh1PQCprieqdvKj6yFhD/CJUVjSN08suGF6FPQekfVTJtS0WxY1XbQ5Ed9Q==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-reference": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-reference/-/dsh-client-ui-reference-0.2.0-rc.2.tgz", + "integrity": "sha512-HCdQto0tHfERzxNSDHZRKYVu+lBPjhfzf0F/rblzda2znMxNE5pjHtFfHZHkaQwUH3lPhFHkuGzP/AvBtamISQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-renderer": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-renderer/-/dsh-client-ui-renderer-0.2.0-rc.2.tgz", + "integrity": "sha512-vQ/LH4A53K1J/UeF5fQs1Dj8km5cnVos7vO0rmj+pJROhE6Vs7pAAKGz5P2e02t2/2to6+iMDu2+SSITrcYWTQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-schedule": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-schedule/-/dsh-client-ui-schedule-0.2.0-rc.2.tgz", + "integrity": "sha512-aBWxbwbbrLzqKIi8BU5gc82clY4totY+ikE4ypaanxr8qDgJ/ZOe3SVaZRHWWSAsunLP/rYtsamIRE/2eJDveA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-session": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-session/-/dsh-client-ui-session-0.2.0-rc.2.tgz", + "integrity": "sha512-QbavrwYkWqdmR4Be7Bv2tNqf+Gh1LV6+rlDkdukMWvdJFSeAmX9Fsctwn8yqgnPRGEHZUfZIjef8zKXIWexuYQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings/-/dsh-client-ui-settings-0.2.0-rc.2.tgz", + "integrity": "sha512-Kyho8FvRGYb7Ok1t7T429d4Dj/XF8+tE/+MX6T1s41RkXCe7v0sP89i4DUMo6OeUxyE+/uGoAVa5QZXY4O/y+g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-account": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-account/-/dsh-client-ui-settings-account-0.2.0-rc.2.tgz", + "integrity": "sha512-4Twq6woo7QJshkHu7hXzE0eyDnYCf01iuLfWZftWpLl6olaA6eQBxaRrMyW7YDubYpnTIu6m+1QRGtQ5MARYgw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-agent-loop": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-agent-loop/-/dsh-client-ui-settings-agent-loop-0.2.0-rc.2.tgz", + "integrity": "sha512-e3Vx0ZE8jfuNQjaGXggUA+cp8x71VqkYFldd3IeXuMW1w4MeBzo+wbKeCOOf4TCCyvqLTD+x3OD5wVr1lgkjiQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-general": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-general/-/dsh-client-ui-settings-general-0.2.0-rc.2.tgz", + "integrity": "sha512-LqM4OitgSKe7KDFiyBauVuJ8wvS2G5Vk/BNV1wmYz3oTNyCJXZxdJVP6qijFc4yf1zPXWfEGAufYBdtyYb35WA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-models": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-models/-/dsh-client-ui-settings-models-0.2.0-rc.2.tgz", + "integrity": "sha512-vZVCHW1PYaPOhlunGL771e2WfkN023CTvZ7ZeiTWX6vkiDloUPCAMCjCl0e/xkbtgSMGvVjquuqGluwxqqIShQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugin-inventory": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-plugin-inventory/-/dsh-client-ui-settings-plugin-inventory-0.2.0-rc.2.tgz", + "integrity": "sha512-oS2EwNGQeNQwSsbZYv7PzuR9byUu905KcVuf4nwaQ/JOJJRfMj7fzpP2wSh6nJ1l11Yjhvvc9TQ6nzmGDmL9jA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugins": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-plugins/-/dsh-client-ui-settings-plugins-0.2.0-rc.2.tgz", + "integrity": "sha512-mW/BaxHgKNyO2Q/ePhqFvFziQc0OVU7HUVu5RC0YG6YbT6ZIEsXs8UWrucwgExjcenPDnmW11j89+q1Vi/1YJQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-session-log": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-session-log/-/dsh-client-ui-settings-session-log-0.2.0-rc.2.tgz", + "integrity": "sha512-aacrU3GfHkCTB8FFM0yEF2XFHetX7DZz4TWPJeAbMafFpbXi90pLOxY2wg92wehURtTuhNebqa+IYWBldg8sOA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-shell": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-shell/-/dsh-client-ui-settings-shell-0.2.0-rc.2.tgz", + "integrity": "sha512-dTEdo5Pbh/M3bi+co7gvKbdTewHakkvwy9ESJVjzq0WD/7qtQT6szbhlBJ+WaDKvRDhxnlcnuXB2u5wyRsKVmg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-subagent": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-subagent/-/dsh-client-ui-settings-subagent-0.2.0-rc.2.tgz", + "integrity": "sha512-Fk61weXn1Udb0lHSnvmId2rqNtdwg51Gw/Hdk2Upf+D5hGKaeRCv+lsO97Xi83fJaJz+md7OvBnqu9htduZuxg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-web-search": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-web-search/-/dsh-client-ui-settings-web-search-0.2.0-rc.2.tgz", + "integrity": "sha512-vt2Rgf0Z4sx1EE10EJDKQvHjK7xsNEMxrUv2ZUoxA6E8cFtRMD+wGblW7f8s6OwV2pNyAE+hiYePPf1zK24dbg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-shortcuts": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-shortcuts/-/dsh-client-ui-shortcuts-0.2.0-rc.2.tgz", + "integrity": "sha512-MZtbV4PgYGx7MOUFlwfiWF75sBeLZcds9uHlYTQlHSjkJwJWLnqnT9OYwTVQdfWYs5MBv3Bj5PK1kS8zUO49hg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar/-/dsh-client-ui-sidebar-0.2.0-rc.2.tgz", + "integrity": "sha512-qAvv42Jt36dVVHNuuZFUbR5kMofhPmGeFafBcOU1mlmUJitZFf31MFFF34UER3JSnByxwAeHsMx9JMq4k7nA4w==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-browser": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-browser/-/dsh-client-ui-sidebar-browser-0.2.0-rc.2.tgz", + "integrity": "sha512-tp5007jcJlcJnnjslpix4XbnbKGpKQjXCzlRKyFdUqcbua7Oqn1ZcIrCM/+gvgd3cOC+ZlAxrmyJQtbulFg4oQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-documentpreview": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-documentpreview/-/dsh-client-ui-sidebar-documentpreview-0.2.0-rc.2.tgz", + "integrity": "sha512-0daQxoPZiJ7Jkq3xwVZguqYURtrM4Sa8ghxyVjw7/Kyp5xGZ8+agFAJ7ZovlVramp7LacBc3A6aNlB3aRLlBMA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-files": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-files/-/dsh-client-ui-sidebar-files-0.2.0-rc.2.tgz", + "integrity": "sha512-QapGZ5bpiGRFFOT4tw32nJxgkFdTkbEw7qO32vYLkcSdmbuWMETCutVBp77HLGsizB1RtYUtW/Y3IMT3uGb3Xw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-right": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-right/-/dsh-client-ui-sidebar-right-0.2.0-rc.2.tgz", + "integrity": "sha512-ocVUP6v3X7vShYeJ5I1Z3t1lDC02hJdZ49/kIRj29Xbe+BIfMY9HSDyUVUUDdijdd3jP8dpmhmbHbDJudwFUtQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-terminal": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-terminal/-/dsh-client-ui-sidebar-terminal-0.2.0-rc.2.tgz", + "integrity": "sha512-W49Incf9cPFQ8Ntpb0S0dUkbn7bdlffbEUASYACxIxPceZc1YVzz7Tp32kTYUEZNJPkyi7E4r3M81wAhSYimmA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-skill": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-skill/-/dsh-client-ui-skill-0.2.0-rc.2.tgz", + "integrity": "sha512-WJ991QnG+V5Lc9rkpexlgDShO8kCGva0K3mc+VI+6BRJ5tRE6ZFf0hutCax6iyUz/gtaFsxoYs615Uw2jas6sQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-slots": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-slots/-/dsh-client-ui-slots-0.2.0-rc.2.tgz", + "integrity": "sha512-zfILCyG3ijHT7S8+WDXFz4RMxBJtG9A3ngtDBnqcLbD5wzKz8H7E+HC657USa6RgG13C2RGSs73sfKcSs4WtWQ==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-subagent": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-subagent/-/dsh-client-ui-subagent-0.2.0-rc.2.tgz", + "integrity": "sha512-n/1dJBhJE/LgC9qFr+sTm70yu8mY/vULcKCZo7rFs1+/GGlycjqBW4NjOF1Rc66QQQRpaMFuWPEGo83RelwiSQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-theme": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-theme/-/dsh-client-ui-theme-0.2.0-rc.2.tgz", + "integrity": "sha512-1pdHD6QfRGalG3BchmvvuVZportaMcSGQ1lwjFlddB2oyZrHk4lsYMYN8l1icQDgB7VrA4cA1VIlYlUfl7qbLw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-tool": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-tool/-/dsh-client-ui-tool-0.2.0-rc.2.tgz", + "integrity": "sha512-Obs9FeOoIHWJUszQTY4MbdqAhlxX+lkzpwPpxk36t2pGCfkvaPWDdKwC0oUrTkRZxqYdx7inY8JK/+PZaWPnoA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-trajectory/-/dsh-client-ui-trajectory-0.2.0-rc.2.tgz", + "integrity": "sha512-CSN5GnTpg03QysgHL2XW+DKAUea15Sf7a8CKHyHvp/EhtbRMq3JLcvkfx2SV8/d6he9AcJ9wu8++r+S7Qfmm2g==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-user-questions": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-user-questions/-/dsh-client-ui-user-questions-0.2.0-rc.2.tgz", + "integrity": "sha512-N19AmrBM4BNl2FNOVwi8q48W3utd3IUSdnhRxeDSR6TZRzWcFPlYZx9irt+kFFehsjvKRCnPz3Dv2A/CgCppcQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workflow-run": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-workflow-run/-/dsh-client-ui-workflow-run-0.2.0-rc.2.tgz", + "integrity": "sha512-vwHA+gyGXc9faftXvd5qoxmEy+8C4bWXuTogSs4/bA51hXhpOfFolQxm/C0F9Pq5nTDe926mcwIm/8KK5nTR+w==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workspace": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-workspace/-/dsh-client-ui-workspace-0.2.0-rc.2.tgz", + "integrity": "sha512-dGKLOFJXBiGDKl+qWMQ0cYF0AT485JMzSk+AUM6/81tZPapJuirxP7Yf5ZFMfsmgQFv6m4jjYlnOc6KcIfUUZQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-cmdline": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-cmdline/-/dsh-cmdline-0.2.0-rc.2.tgz", + "integrity": "sha512-S4X5fqxjRykgZvfISnw4ta8Kr5YDFUHD73NwD0aUaFbfyhCNFgVSgdZUHVA/a3NmBptIv4Wh+dGM1sI/5DI0yA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" + } + }, + "node_modules/@deepseek-ai/dsh-command-compact": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-command-compact/-/dsh-command-compact-0.2.0-rc.2.tgz", + "integrity": "sha512-QrDjlw1aU0IV6JUdvD7ZGGBjMScRar1JIzpO7g/9LAKvbDLhuJC8RNU2cnZDGCvcAC4sD87KAzK/x+y5JhUeGQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-command-feedback": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-command-feedback/-/dsh-command-feedback-0.2.0-rc.2.tgz", + "integrity": "sha512-O6h7T503zXfKkqgdo5aNDW04oZ1V7owMxsMeU/OGbvlx8Y3RmhgSY2Gyt6UAC2o+6sD0AKWk7fCjm61Ic/FeJg==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-anonymous-user-id": "0.2.0-rc.2", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-command-goal": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-command-goal/-/dsh-command-goal-0.2.0-rc.2.tgz", + "integrity": "sha512-zAQTumQZorlPoDKt7EnrWkIgIVRpRII/8i+aC1bUasf6l1L5Nua5Sy6g2Mf/ILzMO8eiIt7p3/CPJWbL/tvrEw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-commands": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-commands/-/dsh-commands-0.2.0-rc.2.tgz", + "integrity": "sha512-pU5oUyOMPDN0yxEjE1wJRInNeC5hs5vJnbOG8MSSfkFov/7Q8hrfwETxZtcRnbrpzzeG19wsvtRz1twkEMKZBA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-crypto": "0.2.0-rc.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-compaction": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction/-/dsh-compaction-0.2.0-rc.2.tgz", + "integrity": "sha512-aghHthiqhFZK5NlX/EJk54UgdBYJesmqHMxLQqwwzdq35kuFAx1ThxyNCEM/d244MG9IvvD0tSVk0Fj4UPx+Mw==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-compaction-basic": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction-basic/-/dsh-compaction-basic-0.2.0-rc.2.tgz", + "integrity": "sha512-5FUfmXUTM04gjnMhWxnpRk2iHY1eUgBBqSFNJFYTxRx5bVV5ZMJH8E5E+Bc1P8Xt0FORxW4y25MhpC+XA0uBow==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-token-meter": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-compaction-tool-result-pruner": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-compaction-image-offload": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction-image-offload/-/dsh-compaction-image-offload-0.2.0-rc.2.tgz", + "integrity": "sha512-aNX4glTxfengJnr26a8oxHaxjHgBEQxEKaoKXPINlASeBzbsJpCdPyQelTPpn5B/CgRFpw2p7oqlRLwGZjyYoA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-compaction-tool-result-pruner": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction-tool-result-pruner/-/dsh-compaction-tool-result-pruner-0.2.0-rc.2.tgz", + "integrity": "sha512-FK/nqlznWQm0HBJDQkXB7QjEm5ou01em2is+dbVo+LQJtIMo8V7tUDbjqRiIAOCK3MesxyF0HdG16TkY4M5F7Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-compaction": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-token-meter": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-config-editor": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-config-editor/-/dsh-config-editor-0.2.0-rc.2.tgz", + "integrity": "sha512-LG/4EyMMBEwcUAsewqn9+6m9+mFeXVGaze0gaz3YOO/bCnJRI/2f4iuejsk/n+yMI9CNczOaIfWT5b3s7zyhfA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2", + "js-yaml": "^4.1.0", + "yaml": "^2.8.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/dsh-hmr": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-hmr": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-cordis-client-runner": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-cordis-client-runner/-/dsh-cordis-client-runner-0.2.0-rc.2.tgz", + "integrity": "sha512-5VeQlKRUD2VitlGaDvksOI/bIGGOH4C8E1e+Y5kp+CeFxd1W3IABJkQEhEK90Vv3Gj+2S+ZbDh8n0ydsP7s9hg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-cordis-host-runner": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-cordis-host-runner/-/dsh-cordis-host-runner-0.2.0-rc.2.tgz", + "integrity": "sha512-XbCihVALcsNc/wZlOHTM5IRB1WyMbk753eUPlbtlAxjzRalzXVlnfjw5FFdxjoeavDGC+36k8aZFRtTnnCULBQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-credentials": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-credentials/-/dsh-credentials-0.2.0-rc.2.tgz", + "integrity": "sha512-TQlvP0jxXYGy1ZNzh4nVsiCzb8FR9iGarD6BfIZ3LwJC8lDtjSxQHWE8//NYjpn10TIMxmaR4s6niHuJ3JkTOw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-credentials-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-credentials-local/-/dsh-credentials-local-0.2.0-rc.2.tgz", + "integrity": "sha512-az83NVgu0COpjrPRAbXs0+evmSznQN1c8tFv/JKVvgcyPeFw5nLK5+0kA2QRBQ2g1p0+1x5H/4XBtr3Lwq/Piw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^4.0.3", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-deepseek-account": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deepseek-account/-/dsh-deepseek-account-0.2.0-rc.2.tgz", + "integrity": "sha512-hA1Etqs6oFvcRvkwCBP5Zp3lknSc629WyOgudMF/N7DkOsMBsYC+3Qj4hpkoF/G2pWGO7qsXmC3fRwFk17foHg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-deepseek-account-platform": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deepseek-account-platform/-/dsh-deepseek-account-platform-0.2.0-rc.2.tgz", + "integrity": "sha512-JX61prldKAfHmsBE7yyVfp7EShGp0PgWvIAmQnUqy3MxZvBB24k2XBZ/UmPk56WvRhHnirGM4pJyipaT/ljdlw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-authorization": "0.2.0-rc.2", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-account": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-deepseek-llm-api-extensions": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deepseek-llm-api-extensions/-/dsh-deepseek-llm-api-extensions-0.2.0-rc.2.tgz", + "integrity": "sha512-AAiHShG4cgAtDa2XOe0mI6fTTkxrAI70x29HilYN6ZNss8XzC5tFF/XWlEf6fUx+l98Ohudn5101nhhbENgqkQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-deque": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deque/-/dsh-deque-0.2.0-rc.2.tgz", + "integrity": "sha512-XwZvafZAxyDm2TRnQetEizuczZ1UG7RhO8vmmIUbAdjbRbMA15NOTlJ3d24uw+I8gcSKKkmWl/jwoKYKl/qo/A==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-agent-team": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-agent-team/-/dsh-experimental-agent-team-0.2.0-rc.2.tgz", + "integrity": "sha512-ds9BrnyJ+BAbxaH3J81c/+JJpk8jUtnpzUCyTXxrDW2nZOnFWqdPH/TZKAI1ttCuls218+RF4PPFPbhYaXNl6g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-agent-team-profile": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-agent-team-profile/-/dsh-experimental-agent-team-profile-0.2.0-rc.2.tgz", + "integrity": "sha512-XmOjwaAoHlmLkN3weOGd6phIdXtc3JaaT927Em32/yeduirVwdlQ9igDwIrpOcmNqi7jH6FldliHHvT3zrVkuQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-experimental-agent-team": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-client-ui-agent-team": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-tool-agent-team": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-api-speech-to-text": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-api-speech-to-text/-/dsh-experimental-api-speech-to-text-0.2.0-rc.2.tgz", + "integrity": "sha512-1RUi6flQ368MYEv3ukRFwyGqf9/5WaUfPgbi4/IAI0CaZeER/yBp7AlbaAzVwWo4EVqew0fXNcW95KoUgpHwZA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-auto-review": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-auto-review/-/dsh-experimental-auto-review-0.2.0-rc.2.tgz", + "integrity": "sha512-WMGHoNP/vX2TU8PmONeC4ji+DzRH/6LBjo0Sml66Nko9++m0n0+ksL4/DjIcJrBKGSH73gTGsDFNWt9YxO7wyA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-instructions": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-client-ui-agent-team": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-client-ui-agent-team/-/dsh-experimental-client-ui-agent-team-0.2.0-rc.2.tgz", + "integrity": "sha512-xrx4ThE3TbK0gbDcbW3oLLL0NzyP1poTygNeTBwoyY3gwPQZGx+4Q3W7CugGpEjNU2Ie4SZWqGYDN9jauiki3A==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-workspace": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-agent-team": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-client-ui-voice-input": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-client-ui-voice-input/-/dsh-experimental-client-ui-voice-input-0.2.0-rc.2.tgz", + "integrity": "sha512-oDJf2pSeaV+785Rk5le0HBteinB17Lw01EtexH27UWQQombNhOj1ZXs+PH5F/caTGyLaiIt/1Z4+o7e+TIcr0g==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-api-gateway": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-store": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-plugin-manager": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-schedule-bundle": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-schedule-bundle/-/dsh-experimental-schedule-bundle-0.2.0-rc.2.tgz", + "integrity": "sha512-6oGDFceBMAsrKeJfFxByyvXBPE+Obfd0oMCwNYdWesPmRBueuRwj5lwp8BY+v59mQAc3Jzdkx1hZh/E6xRcMng==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-client-ui-schedule": "0.2.0-rc.2", + "@deepseek-ai/dsh-schedule": "0.2.0-rc.2", + "@deepseek-ai/dsh-time-context": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-speech-to-text": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-speech-to-text/-/dsh-experimental-speech-to-text-0.2.0-rc.2.tgz", + "integrity": "sha512-p9j8bU00eRlKsVfKK/tYj4Y4tHtuyYV5WSg/zd08g28/07ejUNu0J9vMlw6RzTFHMHqOSGGnsx6ra9IxfvCc2w==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-settings": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-experimental-speech-to-text-sensevoice": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-speech-to-text-sensevoice/-/dsh-experimental-speech-to-text-sensevoice-0.2.0-rc.2.tgz", + "integrity": "sha512-Czz8Vp+p1wPXU0quJ2en7Okhrq5mp2wYxh/ZDjsiYq/Nm6GagNz4ZRYXSyxWZE/yFCv2UQ5gVcVOzp6OKNqxnw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "sherpa-onnx-node": "1.13.8", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-tool-agent-team": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-tool-agent-team/-/dsh-experimental-tool-agent-team-0.2.0-rc.2.tgz", + "integrity": "sha512-iwaUH4Ev4jz56iV9Zm1IkY/34c0NoUe3gFDKDzw8UQfy8S87uNoTOR5z4//ycdN0uuHQ01MfP7U0zKkdIuYjoA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-agent-team": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-voice-input-bundle": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-voice-input-bundle/-/dsh-experimental-voice-input-bundle-0.2.0-rc.2.tgz", + "integrity": "sha512-am08Ylak3AYyX2DYxnfN8zn5t80xl5a5Iys6BJ46Ji7ruF4vD6d4C3SaitEtjNgciPxn41R9B9iWTzYTD/cQhA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-client-ui-voice-input": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.2.0-rc.2", + "@deepseek-ai/dsh-experimental-speech-to-text-sensevoice": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-file-reference/-/dsh-file-reference-0.2.0-rc.2.tgz", + "integrity": "sha512-vIjixx03qmWeEoVAhIOFEXyQ7I3UTenWtql8tT0IEQLYp7WRRhMNr7vojpkRO7JPgSgW5tjUIiQvg8/h990GvA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-file-reference-local/-/dsh-file-reference-local-0.2.0-rc.2.tgz", + "integrity": "sha512-xrzsF7lrCExK4mdrFXuJM6XeYaZCQoaaqgv1Ab4YbN56N2UcCTHd5rKgFwwRRwauPkeytUAYMoFmXZmTIdhnVA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-file-reference": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-fs": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs/-/dsh-fs-0.2.0-rc.2.tgz", + "integrity": "sha512-PuVcI7drTwa19Key54DROoqnDFTTFkl8TPlyrTnS3BSnykm+jKbB13ES/PQEJoRunNdQkNZa12jtbUI4BP/EHw==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-fs-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs-local/-/dsh-fs-local-0.2.0-rc.2.tgz", + "integrity": "sha512-lDzh5VlQsXf3nI+E0+T0weYdH1VAoo+htj6Kwc62P7/Lx+xjnYSLQYTeGeaJR1d8H2iQv2FvlwaDKv60AorKdA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^4.0.3", + "koffi": "3.1.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-fs-observation-policy": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs-observation-policy/-/dsh-fs-observation-policy-0.2.0-rc.2.tgz", + "integrity": "sha512-YPqpJ+WPhYUHS6PtUN4abjUx/dK6bexUiQdFGeQ81F0CEWbIfxyT1QzadKPvU5PrjxpG5e+UtjoEmAQKSCrsiA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-fs-sandbox": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs-sandbox/-/dsh-fs-sandbox-0.2.0-rc.2.tgz", + "integrity": "sha512-y1RCQ64FOXzKXsLLHKVcExn8wKVN3klZY+OBeLYpiTEGZemADk6lf/5bNXQP9v6EwXK4bi4FRkTe8vURZMB/HQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-goal": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-goal/-/dsh-goal-0.2.0-rc.2.tgz", + "integrity": "sha512-dxjUpSl1WAmg6GqO+m9dYGKPAV+whMR+0xqQCoapb8C60FEmeHa2YdopGKKRLziUzB9H5JoDXjtv5HsfuRQRjA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-goal-round-driver": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-goal-round-driver/-/dsh-goal-round-driver-0.2.0-rc.2.tgz", + "integrity": "sha512-9J+uUo7+US98xqboK+JPXUF1TIGDwN3BB5AdhiDRDweLi1T3wBefpAHD4+ngM3C2e81MnUHk7FIFmK5IUY4B9A==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-headless": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-headless/-/dsh-headless-0.2.0-rc.2.tgz", + "integrity": "sha512-qe1X+9fV0bgStRFlegsaXvIV34Y6gP/7Cxlf2MmhRduXtUQhvHAX+OJC8oySCiy1xKGeaFjB3POG3Bh5Er2y4g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-cmdline": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-query": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-hmr": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hmr/-/dsh-hmr-0.2.0-rc.2.tgz", + "integrity": "sha512-DyMnylNJ3v8NgtUi13SdVm7Y2Aml4MN0K7gvN+7FDrSD9iCqr0BlPqODxD/XH2EM2AYULxK2ISis7Y5/8gqnfQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^4.0.3", + "picomatch": "^4.0.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/dsh-cmdline": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-home-paths": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.2.0-rc.2.tgz", + "integrity": "sha512-n4O5C9pNIVWbBklB5RzSTc3kr9hmUnDlZ6Leqj3TIk+CO593DTAmDGTt0rHMQe8H+1Ur+Jqj9Hqgsug/WRkkvQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-hook-protocol": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hook-protocol/-/dsh-hook-protocol-0.2.0-rc.2.tgz", + "integrity": "sha512-ew0biR00o9ilXExq71XGYYbC0uJl+sr6Ju/zjzNUf/vXSZEuOMs9I89xA0R82Od8KLPMobPtQIs8YMwTHjiJEQ==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-hooks-claude-code": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hooks-claude-code/-/dsh-hooks-claude-code-0.2.0-rc.2.tgz", + "integrity": "sha512-xMcX3KOeLOdiiA2Kzzo6TZbXmNMtr3xfJdbRu2Z4/MDvOHOxzPW1GUqDKUjpR16dZHZr8pB1Q2YhPlnWij/dXA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-hook-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-hooks-codex": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hooks-codex/-/dsh-hooks-codex-0.2.0-rc.2.tgz", + "integrity": "sha512-EtA1KUArcSwiyJqZCclbZ26Mo8+DLpP9JIFevicj40jD/wjBjX3DutFFiEdAxigUi3qgJs7VZKmNQd2yQuTbgQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-hook-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker/-/dsh-host-directory-picker-0.2.0-rc.2.tgz", + "integrity": "sha512-qrgr2mgIaLCQJbJnMiVCuDnrGyQUgamjOnC9/K3oUL4YRc6ymNy7SJ5y+6YHtziA1dF81pSmFAA2QPZd2zQDVA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-auto": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker-auto/-/dsh-host-directory-picker-auto-0.2.0-rc.2.tgz", + "integrity": "sha512-loiTeinKMrqstd+4GdGV2Odz1rhdCZ4hHtS+oVeK/C/r+EhWK++GiZMWKf2fn06+32QOS4Gi079AlMT0/cuPOg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-directory-picker-browse": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-directory-picker-native": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-browse": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker-browse/-/dsh-host-directory-picker-browse-0.2.0-rc.2.tgz", + "integrity": "sha512-1mWqpuxBRxm4O+fUKpiAYne35MQMDTeerClJhW3pclnO90T5fs/gaaa+np1nDhLdsUMXeZKBvDf0X0KuvdMDEA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-native": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker-native/-/dsh-host-directory-picker-native-0.2.0-rc.2.tgz", + "integrity": "sha512-p+KJRDaCyiZzCozcdW+M2wtw3uvZ+EBbquaMFy0Z2PL2EacgDWY329nihql2NsziyJ3/EfwP4nya55N6Jn+jfg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "0.2.0-rc.2", + "@deepseek-ai/dsh-native-command": "0.2.0-rc.2", + "koffi": "3.1.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-frontend-static": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-frontend-static/-/dsh-host-frontend-static-0.2.0-rc.2.tgz", + "integrity": "sha512-8wLpf1rw7gGINGISrHloNaPJDIGUuekqGAlq1bn14BjE2SNd01woy/+xOJgWgu365poefA/xlQ/6hEv3rnsLug==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-client-connection": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-host-open-in-app": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-open-in-app/-/dsh-host-open-in-app-0.2.0-rc.2.tgz", + "integrity": "sha512-d/DDm/8s+VjLVx19FyXdn+TDDn+JUqmucU6ZHo7QqQClBndzyL4qvWKjHpRuYLmJDSwlcmsrKIppjdYIm9L9Fw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-native-command": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-plugin-inventory": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-plugin-inventory/-/dsh-host-plugin-inventory-0.2.0-rc.2.tgz", + "integrity": "sha512-l/ESrOGxkk0aemM4t2b8yV3AvMZQ9oxSmgo4b1FSK3CYeaDoPJHC6iKW41DhmnJ0igdLpVIw+rg7R3KN0DREdg==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-preset-registry": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-host-product-telemetry-otel": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-product-telemetry-otel/-/dsh-host-product-telemetry-otel-0.2.0-rc.2.tgz", + "integrity": "sha512-qwAG4OA9IIILLr8NQwVJ+vBb25WLCSzj0lWM56nCKEir71rRST83DsSfaycR+xghWbJGf8nnJl5Nq9iFYDc0dQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "@opentelemetry/api-logs": "^0.220.0", + "@opentelemetry/otlp-exporter-base": "^0.220.0", + "@opentelemetry/sdk-logs": "^0.220.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-otel": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-host-webserver": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-webserver/-/dsh-host-webserver-0.2.0-rc.2.tgz", + "integrity": "sha512-0zvI44emJMRr928Tfl//cPJlx/hiTGWfD1zaDlXu35eGIgOATFJlTPkJLApJvJOPVPPAlSOSdhI2L+j1TnzStw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "compression": "^1.8.1", + "negotiator": "^1.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-http-proxy": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-http-proxy/-/dsh-http-proxy-0.2.0-rc.2.tgz", + "integrity": "sha512-zIGscCHeW6MUIKrksxhW03McWtKKpaDVVMf877bt51ZPP8p4UG8KmBUqJmX2l3eVoHeuuEyqM5zJSCj5NtSBGg==", + "license": "MIT", + "dependencies": { + "undici": "^8.10.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-invariants": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.2.0-rc.2.tgz", + "integrity": "sha512-QOVc0HpRsS8ekvprb45FlxieDvgR/cAMaxW289HASjMoV/U/B54FpbkHuPBw4EnTw07/sPkjx2B/23+YqE0cbg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-jobs": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-jobs/-/dsh-jobs-0.2.0-rc.2.tgz", + "integrity": "sha512-SuCCfXZDabBxsKbHoulXEeQrRSYuOYLSfhvnflQf+CYeb68wggKraejkLyO60LrCGnBJsgCqKIdIKLCUvIeN+g==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-workspace": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-jobs-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-jobs-local/-/dsh-jobs-local-0.2.0-rc.2.tgz", + "integrity": "sha512-sNyolYfcNVodxGyoWUM3G0f+numJexMrqwR0HC4x9kvzzZNR1WZV7ca4lCAzlaRSEvY8UPYxKC6Fi4T+MnBkSQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-launch-environment": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-launch-environment/-/dsh-launch-environment-0.2.0-rc.2.tgz", + "integrity": "sha512-IyhZjJJQ7RVLcKlc4pPPjojOKrr2XCYm7VRpslFq7bvGj3DGt8WMTSCCZUWxCThY2jg6kFF1ujiTGunELfRO6Q==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-lazy-require": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-lazy-require/-/dsh-lazy-require-0.2.0-rc.2.tgz", + "integrity": "sha512-t6m+13fe+4veaepjGwNu0BLTtqdrSPq+A/zmOzC+7DXgWCBHJ3IxfW2vUlLviKfviwMI4BqQMPv4wHeuJgYFIw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-llm": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm/-/dsh-llm-0.2.0-rc.2.tgz", + "integrity": "sha512-6QFrQn/h0iNqCfPpgQidnHtLSpA99A7ZND/uYKaGSd/4BGP8KBhuRd0w63e9s4u+hfW8jc3j29WKcNLIOeUfcA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-crypto": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-deepseek/-/dsh-llm-deepseek-0.2.0-rc.2.tgz", + "integrity": "sha512-Vk0oz0qAXYLC/tKoGfhRioank4FNX0Xdx8oDYduKL1HDf2tO72X+Nrq7hZaJp9nwvXCcg5TnPRIvE8ETZ98C5g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "eventsource-parser": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-anonymous-user-id": "0.2.0-rc.2", + "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek-account": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-deepseek-account/-/dsh-llm-deepseek-account-0.2.0-rc.2.tgz", + "integrity": "sha512-02nSBVyVxfRgZhNa7IHvSb3OMWFWRBTu1jCKMPcOONZx5e4wv8+Adad2vMfPRftEIJg7hFV2RGh/yN/5y02sZQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-deepseek-account": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-deepseek": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + }, + "@deepseek-ai/dsh-deepseek-account": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek-api-key": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-deepseek-api-key/-/dsh-llm-deepseek-api-key-0.2.0-rc.2.tgz", + "integrity": "sha512-F022Y9VK7NE3Z24TqTADgd9Gg3XzuVt8eRPXMRvs6rRDJiZBUCthFcSFAuZ668oTH6If4dC7PNoLgaN7QQVLRA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-deepseek": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-llm-pi-ai": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-pi-ai/-/dsh-llm-pi-ai-0.2.0-rc.2.tgz", + "integrity": "sha512-8DxCwQNhfQwqNQ6khxyDSh6Pba9PjpnNQqvAz29SF/V86ClZNH5xZuqCdNfU8E426Ec6wti5oUtM+uKohMAe3A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@earendil-works/pi-ai": "^0.87.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-authorization": "0.2.0-rc.2", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-llm-retry": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-retry/-/dsh-llm-retry-0.2.0-rc.2.tgz", + "integrity": "sha512-k992Xuafcz0plUyUHyxABDrB+elh6JYvVtQDnEIjUJkSAc8bbsN7ZcF5fxHFx0zCEoMrxRA7ZqtqxkFTYUiNMA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-mcp-client": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-mcp-client/-/dsh-mcp-client-0.2.0-rc.2.tgz", + "integrity": "sha512-UqP2sY1r6qAhBPFeuclqrXiMBBxPaCNrXlXRqKxAON7uI1wmZZ0B3/1GmBviQ3/WjjTQlOOkj0su2v4e5DMkug==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@modelcontextprotocol/client": "2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-mcp-resources": { + "optional": true + }, + "@deepseek-ai/dsh-system-prompt": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-mcp-resources": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-mcp-resources/-/dsh-mcp-resources-0.2.0-rc.2.tgz", + "integrity": "sha512-ZP4B0DQPFlFpzUymv7GuZ2rwcyxTJ/xPAhn2r06yPUfUnwVFpcyt32ipOSAds8OnpHm9jEybRX4+lWzE8MK+JA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-system-prompt": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-message-feedback": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-message-feedback/-/dsh-message-feedback-0.2.0-rc.2.tgz", + "integrity": "sha512-c6gc3173YL1vIqyLXdj6vcTwXUhPZYOhSyMrOK4Zb5KkrSfGshNo5mG3+BVGd7ZW0vbsMScSGbNG2PXidmUTpw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-feedback": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-native-command": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-native-command/-/dsh-native-command-0.2.0-rc.2.tgz", + "integrity": "sha512-RgjkI2avXHxJFwI7tjb42WTHHd4xL6Ybbg5I12T8qbuW4ph6gzAGcl8UKv7tSFM59yD85i2rnULTiZOzKKSdqw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-office-to-pdf": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-office-to-pdf/-/dsh-office-to-pdf-0.2.0-rc.2.tgz", + "integrity": "sha512-Dl0TjqzrrzgQZCLATAvLuoXGOkmJ+deQLsLtL1HZUehN/aTyDI9j42obKPdOwSEHZeUnrdY2SEga+RiqY/J8ag==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/libreoffice-kit": "^0.1.1", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-otel": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-otel/-/dsh-otel-0.2.0-rc.2.tgz", + "integrity": "sha512-LR1fSfTS2/0D/TYSSinIOu1AXO/iKRbZAnJ5d4un/rlGQKL0caQiCflQ2lo5ryPOIa9pJnIIEGu949xsZY2gIg==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.9.1", + "@opentelemetry/api-logs": "^0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-exporter-base": "^0.220.0", + "@opentelemetry/otlp-transformer": "^0.220.0", + "@opentelemetry/resources": "^2.9.0", + "@opentelemetry/sdk-logs": "^0.220.0", + "got": "^14.6.6" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-output-retention": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-output-retention/-/dsh-output-retention-0.2.0-rc.2.tgz", + "integrity": "sha512-+yVL95Om473rZTHIyvjZ6JUyDl2orRpyjXeMSqOzJqh66/sERUfPgCtwMbnH9tzhxTF6nw6cC30I9dxgHEz13w==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-package-manifest": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-package-manifest/-/dsh-package-manifest-0.2.0-rc.2.tgz", + "integrity": "sha512-CFycoLxUT4g4w1IGjaHi/IjTzTRgnQ2PQVeHHSWoEppD+0NTZ1rHHW3ofkh74ZgQagoeo7n+91Yjl0rDGuWE3g==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-permission-presets": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-permission-presets/-/dsh-permission-presets-0.2.0-rc.2.tgz", + "integrity": "sha512-7jOAGdhEtRlhXZnJC92Sj+Z689jGcZdI8xMkA64o5GNyTxDcyzmTMwQLa24Jqm0NH5GKj1DHYoKm8LMEmicl0w==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-persona": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-persona/-/dsh-persona-0.2.0-rc.2.tgz", + "integrity": "sha512-GfOs+GRlYVN4KHmCmAYal7aONmNQ9Z8m5yLwZKVC2c9tG1TsF2+wU+sHUXU1KrStdF5UDOKoE5qMhz2lPkC6xA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-plan-mode": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-plan-mode/-/dsh-plan-mode-0.2.0-rc.2.tgz", + "integrity": "sha512-Lpjv2GSz7rHijH+RNUwLTLH6AIptf6jUw/VfjiD7jGG0w6kq9KfpNs9WEW+lHeBrIWKGcfUkx47P3nu8uUbVvw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-questions": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-commands": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-plugin-manager/-/dsh-plugin-manager-0.2.0-rc.2.tgz", + "integrity": "sha512-WnLDgkj3snW8YnOESlAhHTYerLSZBVEqYlup8XHJBXly2SnOTG6GG11phLvngocSDbhvMI6PB3L2oWkFNTYNFQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "execa": "^10.0.0", + "yaml": "^2.9.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-hmr": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-plugin-inventory": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-hmr": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-plugin-package-inventory-deepseek": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-plugin-package-inventory-deepseek/-/dsh-plugin-package-inventory-deepseek-0.2.0-rc.2.tgz", + "integrity": "sha512-aSSwU1KDIodDj0s28C6njtDE8Mz3pIrPh3i7aVu4SHbGkYxhURcrfCtdRREVGnCRBsp0QV6W8qx6ArC2i+DwUA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-preset-registry": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-ptc-runtime": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-ptc-runtime/-/dsh-ptc-runtime-0.2.0-rc.2.tgz", + "integrity": "sha512-HR/3h1VFRcNlAAjCtCAxZ4V3F5pViYicXcLBuYLGjzXWpOhr4zKzeFKh9+UMLjsc9XWIarJMoSvxl662nDV/xQ==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-ptc-runtime-node": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-ptc-runtime-node/-/dsh-ptc-runtime-node-0.2.0-rc.2.tgz", + "integrity": "sha512-MYGTCOBFYuD8568j0hm4ChOTX/cBOUk0H1s+xuioRy9NAjjpTz+ybNZUJTYP3+noN5nzinDZfeiRdHqVoFh6YQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-ptc-runtime": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-pwsh-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-pwsh-local/-/dsh-pwsh-local-0.2.0-rc.2.tgz", + "integrity": "sha512-WNKHUCDkNeT108RB5o/clJ696K3vp9dw38Ekr23wRlWX1EDyxYmTzRDt7WfWDZoeQ+sh5CguLrUbFoPsOy9uEg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-pwsh-sandbox": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-pwsh-sandbox/-/dsh-pwsh-sandbox-0.2.0-rc.2.tgz", + "integrity": "sha512-V59arHVNWPhPHWZaEtdsl3hQ+9E1dZuqW85aGp5N/Vh2IdvEW99BcKL18jB5o+uZ1eI4PmAQ6HHWDU95ephmyA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-pwsh-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-repeat-tool-reminder": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-repeat-tool-reminder/-/dsh-repeat-tool-reminder-0.2.0-rc.2.tgz", + "integrity": "sha512-UOtSkw6L8OTUrCofK2t+VDuJTlX6eR/Ppki8lnHyJY4kcqUwiIMQ58SwQlB0shDdrJbMcK6HlpvZBsIEB3wTxQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox/-/dsh-sandbox-0.2.0-rc.2.tgz", + "integrity": "sha512-luKF7ey6HRZkGhImqLCB5Npt4f4omDRk1r+x5qQNqqdNOuN9LXciKDMNPfnSbHfKCcqSZbH3sK+APOmKzRAhVA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox-local/-/dsh-sandbox-local-0.2.0-rc.2.tgz", + "integrity": "sha512-fM1QtkRxeQ498isBeotl0lW+oK/GS0G63cBNvwJJn6686Qzdl+gqwTDPS61L8pFzxRnqhqcXFxzu2tIV3o2zbg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-sandbox-windows-acl": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/node-addon-system": "~0.1.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-policy": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox-policy/-/dsh-sandbox-policy-0.2.0-rc.2.tgz", + "integrity": "sha512-0xXVqWw908/V6scohMyyU9SZSiQJYji+S1hMPulcUNLb3iew89d+WPWMIkWQBJRvcJzdQ2ghHwCESRkONXTJnQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-windows-acl": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox-windows-acl/-/dsh-sandbox-windows-acl-0.2.0-rc.2.tgz", + "integrity": "sha512-z8blR3g/lIfWd2zR/GjEitXdysNU8NOcPZdILuxoSodBDpkPmKQOHYaH7nzjB1a/S5TxMADgPE1UDXsmJ0zfTA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.2.0-rc.2", + "@deepseek-ai/dsh-win32-process": "0.2.0-rc.2", + "koffi": "3.1.1", + "yaml": "^2.4.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-schedule": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-schedule/-/dsh-schedule-0.2.0-rc.2.tgz", + "integrity": "sha512-1eqTxT3gTs0qDynu0r63ciHIAP+tUNgOE964Y7WsfpzOyuE+CyF5FvZhxEdErVp84bakXehePUdKZ6Z+2IVIkw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "@js-temporal/polyfill": "0.5.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-scope": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-scope/-/dsh-scope-0.2.0-rc.2.tgz", + "integrity": "sha512-066p7Wv74GNWt4xA5Cyvl+7c/i9KrNEDALYh2/hu0VsJPLb4T9He+TY7y1bld9OgungmqyTy1n/cB2ZrVskvxA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-app": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-app/-/dsh-sdk-app-0.2.0-rc.2.tgz", + "integrity": "sha512-RX2ugii2C1AwJk/n1ajqypelNubOxdMfTNsG+vwTBEtonmjiJ4ACoKLFV/P6+RtyEeKEcveIEO1EmI6yXEjeMw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-cmdline": "0.2.0-rc.2", + "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill-office": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-workspace-dependencies": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-jsonrpc-server": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-jsonrpc-server/-/dsh-sdk-jsonrpc-server-0.2.0-rc.2.tgz", + "integrity": "sha512-lNg524lActTvh27Z+FDQOD3n43hzVXe/rN9+q3gGBuUeUkMv+7Hw5TFiDqE6H4VzqAUvuQp8B/0LkChtY2Fi4A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-deepseek-api-key": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-sdk-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-minimal": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-minimal/-/dsh-sdk-minimal-0.2.0-rc.2.tgz", + "integrity": "sha512-yGb64ou0LUM9mH0dz4UaX8d+bKp9FAybIIS4IRJVxrWc/K3eCETrFNoSVE3LKmVY/QgUzx15XpVVp6GzdGRx/g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-loop": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-deepseek-api-key": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-retry": "0.2.0-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.2.0-rc.2", + "@deepseek-ai/dsh-plugin-package-inventory-deepseek": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-sdk-app": "0.2.0-rc.2", + "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-log-deepseek": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence-jsonl": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal-bash": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-bash-persistent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-pwsh-persistent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-protocol": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-protocol/-/dsh-sdk-protocol-0.2.0-rc.2.tgz", + "integrity": "sha512-hs4Kl2x17wAuhSMUWuNpeHvv1mOm+F+A2EQnYu1QmxVux50PR3xHthee7IX/PylpgZybcfBn1JAigKvOFs5GPA==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session/-/dsh-session-0.2.0-rc.2.tgz", + "integrity": "sha512-wj+6MeqCYbDcbEvKH3puHyEGdjyu51JwBoN6Ua2tz6griLufDgLM5HpSU40L5xgpbOfrYVhXZs4vRgOrMlFY2g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-checkpoint-policy": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-checkpoint-policy/-/dsh-session-checkpoint-policy-0.2.0-rc.2.tgz", + "integrity": "sha512-aymiGTfsQcEmlkeq8X4ybYUjKlJagjwhY7qwj7+85i/EOlU8qSzBF7clYkjJBdtN9CAKBAcAPElbgLtwzqfT4w==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-format": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format/-/dsh-session-format-0.2.0-rc.2.tgz", + "integrity": "sha512-qdWtsJt1cLJbUAMCgzRBZ2LyW+XRJpetnle4N/0X/pkmJ9eOM6Y+QqwRQdcEcI4pWuEbPwuq7/HrnqoanVaiwg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-catalog": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-catalog/-/dsh-session-format-catalog-0.2.0-rc.2.tgz", + "integrity": "sha512-wBGYOqel01uyjVyhKjttJeWH99MyuKaaZRrrlvNa5iLDBTysqKrc5AE5MNx3UvvBFmF6Gi/N8FoycZYWOPL6Ww==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-compaction-image-offload": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v0-to-v1": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v1-to-v2": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v2-to-v3": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v3-to-v4": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v0-to-v1": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v0-to-v1/-/dsh-session-format-v0-to-v1-0.2.0-rc.2.tgz", + "integrity": "sha512-PPcfT7txn82/sZnFNxsuxEEUSSdEfBTkNTuOCaiu5ANDMmxUaxOOW6gXt+zBKndGJZRgCR/u9SoAdKv659FSZQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-session-format": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v1-to-v2": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v1-to-v2/-/dsh-session-format-v1-to-v2-0.2.0-rc.2.tgz", + "integrity": "sha512-PBIsz4OBE0wNnapaD87lz6255em24Kn53BKV4K1AqiNH9OWf1+m29TLXs/ICtZ2xigk6TK5H9q6oOVBBmbZyVw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v0-to-v1": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v2-to-v3": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v2-to-v3/-/dsh-session-format-v2-to-v3-0.2.0-rc.2.tgz", + "integrity": "sha512-vrQQ1l3JgPIv/19mhm50FVD40hjro+tAkP3L1PNtGHrbBoYriNWXpR4QDOCQsHdPhg3vpnp9MmARMr8vZzl0Nw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-session-format": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v0-to-v1": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v1-to-v2": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v3-to-v4": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v3-to-v4/-/dsh-session-format-v3-to-v4-0.2.0-rc.2.tgz", + "integrity": "sha512-UkiNDdGS8cwJKqjvHs52BKi+3NuKhoziz/l0IrDoDYpSdgDfK8HrrXkvIxOi+QaBUgIxNTQzA6tsI+TAIMDsGQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-session-format": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v2-to-v3": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-log-deepseek": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-log-deepseek/-/dsh-session-log-deepseek-0.2.0-rc.2.tgz", + "integrity": "sha512-sfQSvHI+19z1fzw6Fz8kGNHIBnuJ3Fp2HOOF1uSRAypCQaiiIvhcP+1TmDrbix7Dwh1uEcF0A3lqKX92G55ZkQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-log-export": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-log-export/-/dsh-session-log-export-0.2.0-rc.2.tgz", + "integrity": "sha512-e8Hwf6Cpnv4mWYiN7xFeSwI5qfPhyGhkDF0ln/k+gANwyQltk0hHu1D1aWQ2OTMvMhpJ9i+MlRJH06DA99n26Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "fflate": "^0.8.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-persistence": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.2.0-rc.2.tgz", + "integrity": "sha512-2OoRHZYWi5Vy0+1bPU37Y/NTh6uQiZ3VdpvDmW1oCgsapQr2JS/Lbody1gXOMJ1KXglCSLmePgTMC00uKw/UIg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-persistence-jsonl": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-persistence-jsonl/-/dsh-session-persistence-jsonl-0.2.0-rc.2.tgz", + "integrity": "sha512-iAzXWC8jmiLYjK+wuN/fAKXLniAfClWm0CmEIwSxZnJGVy8c0iy7j5v8UfOqUbwuGfqo5HUWfyLGgxbWH7SG3g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-catalog": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-format-v3-to-v4": "0.2.0-rc.2", + "@deepseek-ai/node-addon-system": "~0.1.2", + "@deepseek-ai/schemastery": "~3.18.4", + "koffi": "3.1.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-projection": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-projection/-/dsh-session-projection-0.2.0-rc.2.tgz", + "integrity": "sha512-caJ+XGjmR8ouws0LrvuXrabrzi21akB2l8CniUHdx4IpT6GkLapFYlWLbjZlDYqEWB3ktR+q32nxW2s+f27GSA==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-projection-cache": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-projection-cache/-/dsh-session-projection-cache-0.2.0-rc.2.tgz", + "integrity": "sha512-w6V+7Xl6drXgTjsfUAY76/dmt+B6WRnNin3Vyf+2Bo+Y2eMjyymlzc3j0+Tz0bH5oaCLD4k5zYKV9sOZEk24Yw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-query": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-query/-/dsh-session-query-0.2.0-rc.2.tgz", + "integrity": "sha512-seZkaK6E+L2KVUYbzQ5O3S9kKkINul/1WujXNsE7/9vE4NSg97hJjZxCwqYs81qlEO0Ei3f27+W61EtXOYYoGw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-session-format-catalog": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-query-sqlite": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-query-sqlite/-/dsh-session-query-sqlite-0.2.0-rc.2.tgz", + "integrity": "sha512-LyR/1M40kFBJF8TtidCJLLHNQN07ANWtW8+IISBmH0/XqrfqPGXQGBlxorNEYC+JyJ+QHF8+8ltdThMpdEqdkg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-query": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-reference": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-reference/-/dsh-session-reference-0.2.0-rc.2.tgz", + "integrity": "sha512-RWiFw97/ydhe9dwiLJwCVTJ78pvEQXZKVu72ZcbIcBZvoD5MUjVy+5dMjwhzVUwqOlaeRYhQZ+XaLZYt0FsEdg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-output-retention": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-query": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-spill": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-spill": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-stats": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-stats/-/dsh-session-stats-0.2.0-rc.2.tgz", + "integrity": "sha512-kA5Yv/FhIbrsFuNuahOPZP28KXbbCnEO6qHAULDvKZ5iO0/MpnriLKeSXRLS657c6DETC25d0I97HBujeNRQgg==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-telemetry/-/dsh-session-telemetry-0.2.0-rc.2.tgz", + "integrity": "sha512-L0ST+ZmVYdk2YMzgOZLPZNmhB2htF1HqNahuBJpID2d+XyiWYNy3vXhm/lHPs79FxHKN0XVJUR5mUv//MZK4LQ==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry-otel": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-telemetry-otel/-/dsh-session-telemetry-otel-0.2.0-rc.2.tgz", + "integrity": "sha512-MIxi5PWmJIkhkPro8DSycrF5TFWgCA+5y0UVHtiHqUN+tXTltAd0OWtG/wAveyaWhbJdsY/jikx0U7YSibcyrg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "@opentelemetry/api-logs": "^0.220.0", + "@opentelemetry/otlp-exporter-base": "^0.220.0", + "@opentelemetry/sdk-logs": "^0.220.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-anonymous-user-id": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-feedback": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-message-feedback": "0.2.0-rc.2", + "@deepseek-ai/dsh-otel": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-telemetry": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-title": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-title/-/dsh-session-title-0.2.0-rc.2.tgz", + "integrity": "sha512-602qEtmftsQfRzUu4u0sispiHXDGnRGwtS3+isaPmcEDlxETwMjWusatAaGvRIlrl6GGc27mr1IbqxjHWwI5zA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-first-prompt-llm": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-title-first-prompt-llm/-/dsh-session-title-first-prompt-llm-0.2.0-rc.2.tgz", + "integrity": "sha512-72eo8zMep5+okUgUcBCIFhrTVb/5EuR/Ts9W2fbVzSh3+hFC8WKkjKTFrtUMoZeIX9yv2se/R6QC/GH6q0Yjdw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title-llm": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-llm": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-title-llm/-/dsh-session-title-llm-0.2.0-rc.2.tgz", + "integrity": "sha512-S3WNORrtkrDI6F9NADF2cKdGO8FxS7tvSsf+cxmOu6qJktidRP0/n2O9ePmOX3azZ93Ta/mGNMbPueSs7Dta+Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-turn-outline": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-turn-outline/-/dsh-session-turn-outline-0.2.0-rc.2.tgz", + "integrity": "sha512-MMh5n7FpikqC/JkH0M4v+2zO8ezrxonq0XSQ81F7A9lD+eEXGngpspdj/Fatf7l+x9OQpy+BcNqFwlst2i31DA==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-settings": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-settings/-/dsh-settings-0.2.0-rc.2.tgz", + "integrity": "sha512-Py4ZbCyady6st+h8wlsPJxrAOg9VrT1+tltymnJUiAmdnZjMADZKWec9JrB2KwUuo27R+IbibxzaYQOvnZdUkg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/cosmokit": "~1.8.5", + "@deepseek-ai/dsh-config-editor": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "yaml": "^2.8.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + } + }, + "node_modules/@deepseek-ai/dsh-shell": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-shell/-/dsh-shell-0.2.0-rc.2.tgz", + "integrity": "sha512-+3uBpxhXSzukUZx7XjdnUVfItj/w4maPQAcDXnVxF8vVt/dHa2NDJBXyYC9fzIA4PnXqVHFURdrhMfFgeD7GJA==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-shell-env": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-shell-env/-/dsh-shell-env-0.2.0-rc.2.tgz", + "integrity": "sha512-Cl4i32DPSLPra4mt8wBPNVDbV4+mG6UBLGF1EXsmjpj51Xg8slVqPMcs7ThkgesHBG+Fvpbvu4Y0aGhOckcXYw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-skill": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill/-/dsh-skill-0.2.0-rc.2.tgz", + "integrity": "sha512-3QfzZ6qWfESq1TRoVjEfoBRCTONRLU9aLopKpA7hJg/LZ2GqCgMoSvOwJJL+q2Djbs3oiUyC9qJHRnnN6EacIA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-skill-badge": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill-badge/-/dsh-skill-badge-0.2.0-rc.2.tgz", + "integrity": "sha512-LbxiwrQIt1DJNdWDpbJxdOqW2rDAjBlMY5RaNxmQv+PPuS2cbpwlO2oFxNP0qmcodu3YPww+t1S5JK7Jsb3dhA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill-filesystem/-/dsh-skill-filesystem-0.2.0-rc.2.tgz", + "integrity": "sha512-V/88b4uEFwhCAewQhI/VE7/IvgBkDQb//3/zQjK7xieZ+D9wVpOc5AY8GCcQThZu5aGBnI1gX5ITHPlUHjKUtQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^5.0.0", + "yaml": "^2.4.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-skill-office": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill-office/-/dsh-skill-office-0.2.0-rc.2.tgz", + "integrity": "sha512-VCo/orDfkq0tvngJZ9TGfcmnZ1Xud1wrmQdXRiof6DzIu89pEV3q6lfnrnptNynBojKu4dQ1zIChl3jtofamjw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/libreoffice-kit": "^0.1.1", + "@deepseek-ai/schemastery": "~3.18.4", + "yaml": "^2.4.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-spill": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-spill/-/dsh-spill-0.2.0-rc.2.tgz", + "integrity": "sha512-DWcSeURbNzlxMPOtRCzjmM6QTtEzlt7hD26fypE+9guvKPFJ9HUeCg/GQJRfpLbRQqukm4SJroHTSoZitd/t5g==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-spill-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-spill-local/-/dsh-spill-local-0.2.0-rc.2.tgz", + "integrity": "sha512-S6OVSa76ngIAk7lT7NymB2tXg/t0GXFodkwTuU/LGu166DmzvLTNlPqvTbxpJw3N1U1M86w5YV7q/DvSOdWCpw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-spill": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-spill-policy": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-spill-policy/-/dsh-spill-policy-0.2.0-rc.2.tgz", + "integrity": "sha512-xuxH8VGxqJHIYlWUcDWvz4HBYswYtm+sfy1Qs31s8YG2E7ATQ58syI78UbSiaTnJqG1TAOZn+YWZyXv1G9KvHQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-output-retention": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-spill": "0.2.0-rc.2", + "@deepseek-ai/dsh-token-meter": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-storage": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-storage/-/dsh-storage-0.2.0-rc.2.tgz", + "integrity": "sha512-tItvFJ1IAurwmZfBdrr8w+GuyLADZXZ01bos06Ma0QmD3+0NNyvo0E9qmYb54TfJ2h5yvRcFosHO1048gzuPPw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-storage-domain": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-storage-domain/-/dsh-storage-domain-0.2.0-rc.2.tgz", + "integrity": "sha512-GHHphcdLUNnFBPY1QOfE3dg6yKenIxB5wpgSNghZ7iG+Ifunwj4tyRUZ6YLKvni3HO9Kog1eIdXlUa9yEux39A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-storage-json": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-storage-json/-/dsh-storage-json-0.2.0-rc.2.tgz", + "integrity": "sha512-h7pD397LA8JUD3QMz1IUV5kAg4WD6iVSZnMFrrCnN0wBF5B0PS0BDHT+x7zojLtq3MFfyx3JwpmX7uF12S0glg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-storage": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subagent": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent/-/dsh-subagent-0.2.0-rc.2.tgz", + "integrity": "sha512-33izf4xhq03RzolYUjv223tKmeOBl8fMnvnRN15zZB3GWfNRcBTVUUxuu99rCN8TSRRt5A5ABTwYbObb1Isjqw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-chunked-list": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-query": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-time": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-preset-registry": { + "optional": true + }, + "@deepseek-ai/dsh-jobs": { + "optional": true + }, + "@deepseek-ai/dsh-permission-presets": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox-policy": { + "optional": true + }, + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-query": { + "optional": true + }, + "@deepseek-ai/dsh-settings": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + }, + "@deepseek-ai/dsh-workspace": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-subagent-fork-in-process": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent-fork-in-process/-/dsh-subagent-fork-in-process-0.2.0-rc.2.tgz", + "integrity": "sha512-nFsdyD8EIIkRmsEkmZbIhE5GUXa9/tPStTyTK0FM/WbJTFSyacD6Os9YkoYxgahCfcdlZ3cr/jY4eXVfr+0g2g==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent-in-process-driver": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-in-process-driver": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent-in-process-driver/-/dsh-subagent-in-process-driver-0.2.0-rc.2.tgz", + "integrity": "sha512-6ZYAipEyviSo4WlAesVM1DWBkLYQVZw/A8lFWOSVJjl5qOb3q4buZcW/Xy7XKw/forwNSkqaPPvJ/s0kdu1iCw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-spawn-in-process": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent-spawn-in-process/-/dsh-subagent-spawn-in-process-0.2.0-rc.2.tgz", + "integrity": "sha512-7qOuPyeMwaZ2/bFqYnMA6oNLYP+divyV+FlD2PeScDiAcKBI6ZXEhs3wUcT7C04o4zmSXEoalHvlJGAVYUA0jw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent-in-process-driver": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subprocess": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subprocess/-/dsh-subprocess-0.2.0-rc.2.tgz", + "integrity": "sha512-81ULZG0xg2ZKgrs+R+JY8okUwLp8jjsboR+QsMUMf5WFaJ2PueJ+krbhODB2enLx3MUyMX/wR6msnzi14ZNSAA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-http-proxy": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subprocess-local": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subprocess-local/-/dsh-subprocess-local-0.2.0-rc.2.tgz", + "integrity": "sha512-RKEhReGv6bAOHNeMd9kBwY1mQSuhm0OEiK+wnXkOD8CvesYaYXNUmtoIf9VJdrRhG5DF35gVNQAN79Si9d/BHw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.2.0-rc.2", + "@deepseek-ai/dsh-win32-process": "0.2.0-rc.2", + "koffi": "3.1.1", + "node-pty": "1.2.0-beta.15" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-system-prompt": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-system-prompt/-/dsh-system-prompt-0.2.0-rc.2.tgz", + "integrity": "sha512-ZZNk2gkXFV8CIT0IOZXS+pFaxNVJaRknYyH2vc4ZgZAiHKT+RqUYNr8e1F5Kp0AaN0DNlcTkjOGP5MCxeXfDjg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-terminal": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-terminal/-/dsh-terminal-0.2.0-rc.2.tgz", + "integrity": "sha512-AwyXx3wIsn9sVPNQsxsMQnnXk6WRGeNR3WrzWmg3Arpatbh/w9YTQZbvRKeGsETFDe62lHZ3BT8HJ+echqHurw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-terminal-bash": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-terminal-bash/-/dsh-terminal-bash-0.2.0-rc.2.tgz", + "integrity": "sha512-lUavM/UyNaJOcqW6lZlKk3Yro8FO7pA7tSPmP5VTws53jx/zMgX/oKQCraQUBGjStyYPzrcYJEGjEaYx3kYxFQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.2.0-rc.2", + "@deepseek-ai/dsh-pwsh-local": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@xterm/headless": "^6.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-time-context": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-time-context/-/dsh-time-context-0.2.0-rc.2.tgz", + "integrity": "sha512-BI9WBy77/NaHdfGz1UIfWQw9AqPXQYF25CCF9jWwiemdFOfERKJbrQooBtI319dQC+kjvItRHMEgWe0EuhMJ/A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-timeout": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-timeout/-/dsh-timeout-0.2.0-rc.2.tgz", + "integrity": "sha512-NDob8b8DJDB/sDPz3P7xhrkxOh1O9FbN1EZRKsxP4fuTfp4hrQU7aekYS5qZENFKoR8dBJMTh/zcEBw4m31glQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-tmux-context": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tmux-context/-/dsh-tmux-context-0.2.0-rc.2.tgz", + "integrity": "sha512-UbHEhxenMyd89imH9rJi02Mw5xPMgWEz2r1lOmicAIDRcYg7OTzsZWkIG9DPIbeJIglriTEKl76Gw85PhTBL4A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-token-meter": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-token-meter/-/dsh-token-meter-0.2.0-rc.2.tgz", + "integrity": "sha512-ivkxlbk/bl8t8jxPt62a60U4lE7AxlADelxq91u1dd01oSt3+Y5XBDWDKEVjfhISKyfO4qYHo3MvY6zkU7f3gw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-compaction": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-image-offload": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm-retry": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ask-user": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-ask-user/-/dsh-tool-ask-user-0.2.0-rc.2.tgz", + "integrity": "sha512-fRvU7SClHhUKfHnXP7SJitZFgEO4af4Y9kVLBoG+9RpATGINl+PSGChCM6zyz2EI4v0yS0bHsYILwQk82xjsMA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-questions": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-bash": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-bash/-/dsh-tool-bash-0.2.0-rc.2.tgz", + "integrity": "sha512-0yjnxm5C7yqX/XWJYFXZVBWXrM6E/6FnjOjt7sN8Itsb5eSHXCz9e5XpKXpLSAPbzq8Kh49yFOw2ZUJRBkOHyw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell-env": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-bash-persistent": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-bash-persistent/-/dsh-tool-bash-persistent-0.2.0-rc.2.tgz", + "integrity": "sha512-R7QzTQsYoTbS/rioRjoiXqJblhq7Noo8sWoI4Y53yYq9/1uF21mdBQzZGMTqB3v/lAYwawSfkEzfxIjzahgMHg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-output-retention": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-call-timeout-policy": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-call-timeout-policy/-/dsh-tool-call-timeout-policy-0.2.0-rc.2.tgz", + "integrity": "sha512-rZae/XGLoK5kzJ4LYwA4SQOEp0wmxgJKIzhcYDWEfL1y4JiqHJS+GKvjbXZWyOpMeeTga+hKeHjcI5rRB99xUA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-cordis": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-cordis/-/dsh-tool-cordis-0.2.0-rc.2.tgz", + "integrity": "sha512-KVUah6qgv/mjIRcIXM33SOyy/My+3yDOt1Kb+5GlY77EG4TOIhGlH0MksQDaHXyiGbRU+y1RWDMHi0gHf3Umew==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/dsh-cordis-host-runner": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-fs": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-fs/-/dsh-tool-fs-0.2.0-rc.2.tgz", + "integrity": "sha512-QDtVmZoc84iDwrM4ftMDwzuttQd5dXu93NMeas5cSsUvptnW4CiPrMOkYswRXmSry5WRWn7Gk0lSRJ1bpynwiQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-code-language": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "diff": "^9.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-fs-search": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-fs-search/-/dsh-tool-fs-search-0.2.0-rc.2.tgz", + "integrity": "sha512-2og9HzR1w99kXJbZ4miuIVPdfE3lYXWmBETAQeTZzLmPlKU5G6H9CbGq9lPAQ/lvqHDElJdolH9EO+j+zoFfcQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "@vscode/ripgrep": "^1.18.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-output-retention": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-spill": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-goal": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-goal/-/dsh-tool-goal-0.2.0-rc.2.tgz", + "integrity": "sha512-UeMd6NocvpXMU+jT0ujY/jU6S9SVSYY7H7oMnspBmWSPNdlh7eYHkQbQN9af7SWEhaDKBq5rsYPIOsYiSs2bZQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-jobs": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-jobs/-/dsh-tool-jobs-0.2.0-rc.2.tgz", + "integrity": "sha512-6mqWCkYm+XExCfJbix+pcJ2qcQLNTUtNZQOmfV1IFmpT4j0pGju6b4GbiKaS26yDPegIz71ZW2/tXWzijIsjyg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-output-retention": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-present": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-present/-/dsh-tool-present-0.2.0-rc.2.tgz", + "integrity": "sha512-B2Qro2ji4NWqTIuBj8gsIB8rs+I84o5l/r1N7RetKN3yqaiH6sGOUOed/jBa8frvv4dx+jcXWOcfPpzEtOo2Cw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-pwsh": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-pwsh/-/dsh-tool-pwsh-0.2.0-rc.2.tgz", + "integrity": "sha512-kFL84s7zQSRd2IquZl2LK7g56x4MUWSilSWLoRVwGTTQoW3RMFGjAsMZ9ZmtGjdLGrLeCnBwiXucwswTeqYCmw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell": "0.2.0-rc.2", + "@deepseek-ai/dsh-shell-env": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-pwsh-persistent": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-pwsh-persistent/-/dsh-tool-pwsh-persistent-0.2.0-rc.2.tgz", + "integrity": "sha512-rfDTDgAWFH0SVPDMKtn0Cg1gTwsmNbPBw5K26S9cwtFaGxlSaGHPL+lTa2RmQwtTkZoDXdbNG4JmnvzIDxY1CQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-output-retention": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ralph": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-ralph/-/dsh-tool-ralph-0.2.0-rc.2.tgz", + "integrity": "sha512-071tBiqv9EosR2YORosCq4guAhhEV+kB0P/JBKtejeRX4VpH2kR8TY0Y8mmKbjzWdBEncUPsmIqxPtxHbcr1Og==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-workflow": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-skill": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-skill/-/dsh-tool-skill-0.2.0-rc.2.tgz", + "integrity": "sha512-gPD5isAk3AP8oerJ+KiEpZgZ/UAp5g/obSqDJmJrUYzWJ6TYzdY9xFZgb2k8TYDDX7nBM/K5kS7hfRxhH9aerQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-str-replace-editor": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-str-replace-editor/-/dsh-tool-str-replace-editor-0.2.0-rc.2.tgz", + "integrity": "sha512-NDvuS4kmHFTdYNb5j/h/KwEGl4/CIB/mgQsraYj2gMvAcLz7SKfzyLHiliWFdFP48TnSRAS1JhMmNcQ0TN+T1A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-output-retention": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-subagent/-/dsh-tool-subagent-0.2.0-rc.2.tgz", + "integrity": "sha512-SKfjMFctni9IRFrvLAsr8V/pEBaV1gLOERGAG73fqdqbn4KoizMFCWP3WiKir9/gyDWzzQ2RQg53O9snnEo1Aw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent-control": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-subagent-control/-/dsh-tool-subagent-control-0.2.0-rc.2.tgz", + "integrity": "sha512-qVSnUssL+16M/PW3Vre3UFNoqLq3C14DZ9QzqOQgw6s1FAW1WvF9rzJuIYO/8MFy0g+/+f2nXWzOHD/2Gwylnw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-todo": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-todo/-/dsh-tool-todo-0.2.0-rc.2.tgz", + "integrity": "sha512-B3Yu/1gyFvbzsaYCJdCXj022HEBqJZwKL7fO2Txw1xnDDLgBS79B+NVSYDwxgHGYL7LXbtCyD+8zOyvtc6iItA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-web": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-web/-/dsh-tool-web-0.2.0-rc.2.tgz", + "integrity": "sha512-NBH1e06QsDAPGPBpCjp8jr1rv+YX173vyXQ+ENT8IChHFN43S5uNZbzr/EoVTcJ4uAw3OamGXVtD7lU7uF46Jg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@joplin/turndown-plugin-gfm": "^1.0.67", + "turndown": "^7.2.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-web": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-workflow": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-workflow/-/dsh-tool-workflow-0.2.0-rc.2.tgz", + "integrity": "sha512-4p4XTet7bLRj2K5ccE2w/+WT15nRvRl9iFMCPv8X9wZB9ymhd/C4DFOp7wmpDMs5NqedsPrsCK7Wi4vXxO+xKQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-workflow": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-workspace-dependencies": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-workspace-dependencies/-/dsh-tool-workspace-dependencies-0.2.0-rc.2.tgz", + "integrity": "sha512-5YAtIlVwA3RM1/aGTmTzU4YxIPlzVlKzShvbKk/tmj3WPuZJTWFAr9mTkATMwSyP9IRZPYevWeAwVzkerIF0qQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tools": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tools/-/dsh-tools-0.2.0-rc.2.tgz", + "integrity": "sha512-vquUz8PjHWE4zaS3wH70IpYjL441p2UlUcG8TN2yJZN1RhDkuiHum4bWCsjEPyWLS/aB1QJvzdXC2EK/PRkbsQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-ptc-runtime": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2", + "@deepseek-ai/dsh-user-approval": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-typert-loader": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-typert-loader/-/dsh-typert-loader-0.2.0-rc.2.tgz", + "integrity": "sha512-A9jxiG4fuXcU54PG2yqtD9LZe5ikpW1RzWy3VrQDea4U84Lh9Eyp2Flsj2xz8l5V7UD88JqI/CfHnjAGVRsbGA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-typert-registry": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-typert-protocol": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-typert-protocol/-/dsh-typert-protocol-0.2.0-rc.2.tgz", + "integrity": "sha512-95RvIDcVac2BWdv1IxN6yKlRV+8eEvkofqSxV+d0r8x1kx2EIWEsbdxz6C+coYIm+8e03MiN+rwOt8J7sLfe7Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-typert-registry": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-typert-registry/-/dsh-typert-registry-0.2.0-rc.2.tgz", + "integrity": "sha512-Hjepcu0cDTH4rz/SB121SVozg9ix79NBB+HNr0jW0GSHG9O24kNDyufAJD2/S4B97KVN+1nM0T8k1Dx2JSOEWQ==", + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-user-approval": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-user-approval/-/dsh-user-approval-0.2.0-rc.2.tgz", + "integrity": "sha512-fZMfDp4IeWZMwAKEQkuAYCiGRrwoVWNObvAbpdmQNUavjfYCtwwduWqYQz+5lMQq8vENdczBj7cxnO/pOQ1oZQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-user-questions": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-user-questions/-/dsh-user-questions-0.2.0-rc.2.tgz", + "integrity": "sha512-NrfPt/DBCbkK/+sSSaHT3kG5lA71mnpBbxTDsL9/eS/hVntT+IdthVIZy9tPiuBxCnq1N6iPO874zHlAYa6qCQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-scope": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-util-code-language": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-code-language/-/dsh-util-code-language-0.2.0-rc.2.tgz", + "integrity": "sha512-MYp8KlKWKgwxRfwwMbji4zweDZxVJ1smaneMAKjJvexDc9v+C40o1pJL5Ch/atny8a7O4aiBM1uSvC4bo7/S3g==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-util-crypto": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-crypto/-/dsh-util-crypto-0.2.0-rc.2.tgz", + "integrity": "sha512-5OvvmepY69uXTagUMlnoHqg7euI4ZMifLgfdV8xZO20OslWGGiRCkJbZRyDtcJG9GsXWz9UimfWmUu52zKXJ5w==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-util-time": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-time/-/dsh-util-time-0.2.0-rc.2.tgz", + "integrity": "sha512-x+b6PJ7BQ5HnNs0wa+eojmwkveR5X77VzhfKJ8p7ndB0TAdFGBshji30nxNjn/8aNWMdE90gsIvbtazsrGZn+w==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-util-values": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-values/-/dsh-util-values-0.2.0-rc.2.tgz", + "integrity": "sha512-qgpsbgiZABuE9UvgNaVo9b2HiWwLeU93CTl9PFXqE0jN8ap1ALxzQsLGvr/q2MJuWDYqnFBg60XnqnY8ZxPWEg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-util-workspace-path": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-workspace-path/-/dsh-util-workspace-path-0.2.0-rc.2.tgz", + "integrity": "sha512-pjjpi+hN29dVf9HMitxo5gUAXKNdYcJ75vNVjKp2T6sdBy0wxcMKlfddu/bYx/xDL3teNBhh17EH7w1asYNNZQ==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-web": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web/-/dsh-web-0.2.0-rc.2.tgz", + "integrity": "sha512-d44eM9mMqGnQUGsjqUc6k1G9QrC0w+TWx6Cw6I1iXJkVw5LZ/hpVVzsuCqck8GGS8+GK20kqjGUJSyomfEgd1A==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-web-app": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-app/-/dsh-web-app-0.2.0-rc.2.tgz", + "integrity": "sha512-pCIMPLfTKVfY942dP4eJSDVw7iUw86pemzfOr/e5DWP7CdCKTfvA82kP0RJAKJcyKJd8s679hqtCue/p4P20Dg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-agent-instructions": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-preset": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-tool-presentation": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-account-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-job-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-settings-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-terminal-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-workspace-controller": "0.2.0-rc.2", + "@deepseek-ai/dsh-api-workspace-files": "0.2.0-rc.2", + "@deepseek-ai/dsh-app-boot": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-connection": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-file-upload": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-hmr": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-modules": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-product-analytics": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-resources": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-shortcuts": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-agent-preset": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-approval": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-attachment": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-brand-official": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-chat": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-commands": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-cordis": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-deliverables": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-input-trigger": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-layout": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-message-feedback": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-model-selection": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-open-in-app": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-permission-presets": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-plan": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-plugin-manager": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-reference": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-account": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-agent-loop": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-general": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-models": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-plugin-inventory": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-plugins": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-session-log": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-shell": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-settings-web-search": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-shortcuts": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-browser": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-documentpreview": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-files": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-right": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-terminal": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-theme": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-tool": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-trajectory": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-user-questions": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-workflow-run": "0.2.0-rc.2", + "@deepseek-ai/dsh-client-ui-workspace": "0.2.0-rc.2", + "@deepseek-ai/dsh-cmdline": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-compact": "0.2.0-rc.2", + "@deepseek-ai/dsh-command-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-basic": "0.2.0-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.2.0-rc.2", + "@deepseek-ai/dsh-cordis-client-runner": "0.2.0-rc.2", + "@deepseek-ai/dsh-cordis-host-runner": "0.2.0-rc.2", + "@deepseek-ai/dsh-file-reference": "0.2.0-rc.2", + "@deepseek-ai/dsh-file-reference-local": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-directory-picker-auto": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-directory-picker-browse": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-directory-picker-native": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-frontend-static": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-open-in-app": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-plugin-inventory": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-product-telemetry-otel": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-message-feedback": "0.2.0-rc.2", + "@deepseek-ai/dsh-office-to-pdf": "0.2.0-rc.2", + "@deepseek-ai/dsh-persona": "0.2.0-rc.2", + "@deepseek-ai/dsh-plan-mode": "0.2.0-rc.2", + "@deepseek-ai/dsh-plugin-manager": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-log-export": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-reference": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-stats": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-turn-outline": "0.2.0-rc.2", + "@deepseek-ai/dsh-skill-filesystem": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal": "0.2.0-rc.2", + "@deepseek-ai/dsh-terminal-bash": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-ask-user": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-bash-persistent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-cordis": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-fs-search": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-goal": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-jobs": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-present": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-pwsh-persistent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-ralph": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-subagent-control": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-web": "0.2.0-rc.2", + "@deepseek-ai/dsh-tool-workflow": "0.2.0-rc.2", + "@deepseek-ai/dsh-web-frontend": "0.2.0-rc.2", + "@deepseek-ai/dsh-workflow-ptc": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace-changes": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0", + "open": "^11.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-shell-env": "0.2.0-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-web-fetch-http": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-fetch-http/-/dsh-web-fetch-http-0.2.0-rc.2.tgz", + "integrity": "sha512-PJLMAXv0nGdi/wdbzjcEIoaADvUNiGEXnQuF3vaeUzyplal0W1fou4r4klMsHf6aXwMZSXOdkKBocTlIk1U4uw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "ipaddr.js": "^2.5.0", + "undici": "^8.10.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-http-proxy": "0.2.0-rc.2", + "@deepseek-ai/dsh-timeout": "0.2.0-rc.2", + "@deepseek-ai/dsh-web": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-web-frontend": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-frontend/-/dsh-web-frontend-0.2.0-rc.2.tgz", + "integrity": "sha512-FpxbRvWwWyawsoP3bnErQizR5P2aOwAOwDZcc3YQX+BrQVPkQd3d06w3nLv8Fyo+zeTA+pnlBd2JFTLwlaVVzQ==", + "license": "MIT" + }, + "node_modules/@deepseek-ai/dsh-web-search-deepseek": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-search-deepseek/-/dsh-web-search-deepseek-0.2.0-rc.2.tgz", + "integrity": "sha512-WZUPkdO80qbwPatgl5TfRvMRm02L2UELjRYhizNF8Z0RszO85UJdB04PSKXfKxOvjMKRwTPBsbG0JAdBbLpkqg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-deepseek-account": "0.2.0-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-web": "0.2.0-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-deepseek-account": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-webhook": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-webhook/-/dsh-webhook-0.2.0-rc.2.tgz", + "integrity": "sha512-sEmiIwKh8nXbdaIOWmXRuTiOUfRDVZENWKxJ+b7r35JKZz3h8k3KuskGm9OjvVbEIAhl0Ka+s1UpvH8JwJLZNg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.2.0-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-title": "0.2.0-rc.2", + "@deepseek-ai/dsh-workspace": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-webhook-github": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-webhook-github/-/dsh-webhook-github-0.2.0-rc.2.tgz", + "integrity": "sha512-QK1KTS4yfWTWKgccEoI7Ei5hIJUz4jUgPXXeGwXHq0gSoyeW0JEAuK2n5HIzHbMAaj9HW2C01oXl3QSLmb7v8w==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@octokit/webhooks": "^14.2.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-credentials": "0.2.0-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-webhook": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-win32-process": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-win32-process/-/dsh-win32-process-0.2.0-rc.2.tgz", + "integrity": "sha512-MzzPCWqGFnLe0eiTNrdsy5qGprXV9K2U31D6W8XuyQ/5RVG4dLyI1xiXRnc+cqq8SASgxh0D/hM4wy+I6qNkRQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.2.0-rc.2", + "koffi": "3.1.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-workflow": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workflow/-/dsh-workflow-0.2.0-rc.2.tgz", + "integrity": "sha512-kvRw3d+x+clns+HrknZ6EDy32OEhKTmngS2LBuL7vjQl3XjEbM8QhnxbDW3NaRbEvZ5w2/+2GZqlo0bU/w6Cxw==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-workflow-ptc": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workflow-ptc/-/dsh-workflow-ptc-0.2.0-rc.2.tgz", + "integrity": "sha512-p/oqiVTlUiNO+qh8XJaJ0/DL7iEA4RFRHfGM2w4XiLwZycmDux9Z7RyAy2QuB2a3euDTejJuEhzkCO+v/oveHQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "@deepseek-ai/dsh-util-values": "0.2.0-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-llm": "0.2.0-rc.2", + "@deepseek-ai/dsh-ptc-runtime": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subagent": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2", + "@deepseek-ai/dsh-workflow": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-workspace": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workspace/-/dsh-workspace-0.2.0-rc.2.tgz", + "integrity": "sha512-Dvu+lzziMr5vpz9+G+qMabg9rJxqViFdNlz8ch56/zDp4tmwY3hnk2JZ4OuuiLHYUuUeM34ic1H5758IL3YKnA==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.2.0-rc.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage": "0.2.0-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-workspace-changes": { + "version": "0.2.0-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workspace-changes/-/dsh-workspace-changes-0.2.0-rc.2.tgz", + "integrity": "sha512-f1ukSyQSDJPt90daOSHz9S+cZ6L1Boq14ePTX0rUBbTGCMllRcyKHH74ODGzxPm7XEw1joWzQGeWOzSMEP+w0Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "diff": "^9.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.2.0-rc.2", + "@deepseek-ai/dsh-session": "0.2.0-rc.2", + "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2", + "@deepseek-ai/dsh-tools": "0.2.0-rc.2" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit/-/libreoffice-kit-0.1.5.tgz", + "integrity": "sha512-H12xtUsAyl70zFeQ5pk5GGRc3N1+6zn+DVAcqwlguI6EvqopBGP3xkUmePU7g5f6ydYlDZLWedHT9lTSL7zLxA==", + "license": "MPL-2.0", + "dependencies": { + "fflate": "0.8.2", + "fontkit": "2.0.4", + "koffi": "3.1.1", + "saxes": "6.0.0" + }, + "bin": { + "dsoffice": "lib/cli.js" + }, + "engines": { + "node": ">=22.19.0" + }, + "optionalDependencies": { + "@deepseek-ai/libreoffice-kit-darwin-arm64": "0.1.5", + "@deepseek-ai/libreoffice-kit-darwin-x64": "0.1.5", + "@deepseek-ai/libreoffice-kit-wasm": "0.1.5", + "@deepseek-ai/libreoffice-kit-win32-arm64": "0.1.5", + "@deepseek-ai/libreoffice-kit-win32-x64": "0.1.5" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-darwin-arm64": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-darwin-arm64/-/libreoffice-kit-darwin-arm64-0.1.5.tgz", + "integrity": "sha512-SjeXmyaTevEq2TxK7reb1rhCrQZ4QOXmXt/qEwfQD5Fx3odU0ILx2uiXN+nphSCQ95LFCzrElHGgv2c7a824yg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-darwin-x64": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-darwin-x64/-/libreoffice-kit-darwin-x64-0.1.5.tgz", + "integrity": "sha512-vuz2tTpH1Edk75+DISwg/TXdQ3BNSNSHoVnWVqxqbGMgrrK9trLOw2+0X7mjT1naGO00Zc1qkyQ4if3kx5XjqQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-wasm": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-wasm/-/libreoffice-kit-wasm-0.1.5.tgz", + "integrity": "sha512-V+pu5xJsKhVD4AU1xbFlMWY91svK9ZIC2JsNOph9kWp/arF/KQcuytt76bcbozJqPbE8o0n04lyh0m3QW5RYSA==", + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-win32-arm64": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-win32-arm64/-/libreoffice-kit-win32-arm64-0.1.5.tgz", + "integrity": "sha512-Av3aFfNLaVxfffu0JXP5mqfmsCU3gQtlUH9UD+zdXl8ON06ukVAmu7LqNyuKAz/68WoOMTQ+YBlVQukgDRKd/A==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-win32-x64": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-win32-x64/-/libreoffice-kit-win32-x64-0.1.5.tgz", + "integrity": "sha512-uKuDGZdofxuW4iRmUh8b3+XWU28JeOCYMTAONzo7tEHIq00DV2cARcgUYiTP7gUH49tH4A/RyPMOVEBzK7qjjw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit/node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/@deepseek-ai/node-addon-system": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system/-/node-addon-system-0.1.2.tgz", + "integrity": "sha512-EFn8K+mXIXiw6s3rxX+cgp2hZTEAQdVIsURhrXnBxycSXvtQ1EQpsSVzoNKtKAQI0I0VqkEcVEjHzS/PeaGsvw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@deepseek-ai/node-addon-system-darwin-arm64": "0.1.2", + "@deepseek-ai/node-addon-system-darwin-x64": "0.1.2", + "@deepseek-ai/node-addon-system-linux-arm64": "0.1.2", + "@deepseek-ai/node-addon-system-linux-x64": "0.1.2" + } + }, + "node_modules/@deepseek-ai/node-addon-system-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-darwin-arm64/-/node-addon-system-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-IR0cx8um19mLCZaJ+H5PLblKr6Eg3PWvVo8eTQBr/SwH2nh5tM9CD9/5fHweNS9Pjt15UdFlGqnvLSd/w+O6Rw==", + "cpu": [ + "arm64" + ], + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-system-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-darwin-x64/-/node-addon-system-darwin-x64-0.1.2.tgz", + "integrity": "sha512-XDbmquNapk9aT28y4EKn9lbONVr9YNs1NM/GKH1Gi5gUhjOT9wgRaTv72FJdNaVIInbPAYbPoyn7/y+MzQMNNg==", + "cpu": [ + "x64" + ], + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-system-linux-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-linux-arm64/-/node-addon-system-linux-arm64-0.1.2.tgz", + "integrity": "sha512-Z/DQtqgEYzjBzb2ocHGjMzx51W7xDILkJKKj89nyErr8gZMNiLs+JNL1uKzJqc3VLZB+vYCPaHGyQ3oX6EzEmA==", + "cpu": [ + "arm64" + ], + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-system-linux-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-linux-x64/-/node-addon-system-linux-x64-0.1.2.tgz", + "integrity": "sha512-S2aPVHvYCpNCppCFyNlooMYuTB7ucK5lvD9oXQQ42v5Z2s5AoaiCdjz9r2l+ED2rI5oS1x0cUZmKjJH2dxV0pg==", + "cpu": [ + "x64" + ], + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/schemastery": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@deepseek-ai/schemastery/-/schemastery-3.18.4.tgz", + "integrity": "sha512-SSXO6tYuyrIqKVbmOnIq0s+riUywYzouFMcnBluHF9n4KMo2G8HvEzhCYj6pj2617/glOjbJuVInJ9hfONsjkg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "@standard-schema/spec": "^1.1.0" + } + }, + "node_modules/@earendil-works/pi-ai": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.87.1.tgz", + "integrity": "sha512-X/3PfQBnnoeVdO9Cv8zHghUMglzlgNZYGNzoPnbRoGnHl3Rw3TlA2UKSUB7BRHUOxMryHXYa8dnjWZlbRheDZA==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.124.0", + "@aws-sdk/client-bedrock-runtime": "3.1127.0", + "@earendil-works/pi-telemetry": "^0.87.1", + "@google/genai": "2.21.0", + "@smithy/node-http-handler": "4.12.1", + "http-proxy-agent": "9.1.0", + "https-proxy-agent": "9.1.0", + "openai": "6.40.0", + "partial-json": "0.1.7", + "typebox": "1.3.27" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-telemetry": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.87.1.tgz", + "integrity": "sha512-MC6TRQH5lgMXpcN+Vku2WMI2T8BsiUPzMQHGo81uqFZD3/9O79WWJAysEDGuzduP6R4tvtgwMLwmqIxynM10JQ==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@google/genai": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-2.21.0.tgz", + "integrity": "sha512-+PDtco2/Z0ONdzCGekCoCT+O1VJS9xJQNN4XzQpXG/t3El/SWWMkCWlFRO1KmivOHPa4Q0VjUYu1HBKCZ/v33Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@joplin/turndown-plugin-gfm": { + "version": "1.0.68", + "resolved": "https://registry.npmjs.org/@joplin/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.68.tgz", + "integrity": "sha512-m8DfAQNC/V7g0j5H6Jv60WhekBBjodD+zTPGrU+g2m+ux/z8ZX07KQIl6kaAmbKwfvsQhC04op52g63I78sVgg==", + "license": "MIT" + }, + "node_modules/@js-temporal/polyfill": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@js-temporal/polyfill/-/polyfill-0.5.1.tgz", + "integrity": "sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ==", + "license": "ISC", + "dependencies": { + "jsbi": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "license": "MIT" + }, + "node_modules/@koromix/koffi-darwin-arm64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.1.tgz", + "integrity": "sha512-+Dl0zQDh1Wb55AWOn9hp7K30qgkODvrvN+ZNkFOh81Q0oFX/rpJQtocgjAuYk2zFAcajSeVDumkcHMPwnKSXzA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-darwin-x64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-darwin-x64/-/koffi-darwin-x64-3.1.1.tgz", + "integrity": "sha512-cDFAKn1qdZBFLrp7dAc9QUDw3l4xAhTJbOdPWWb0LxssVicUdHcRCLZGrDsmPW2tpH6LGNNeLgqRpAoD2Mo8iA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-arm64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-freebsd-arm64/-/koffi-freebsd-arm64-3.1.1.tgz", + "integrity": "sha512-zaP7FJISI/scQW9Wa5QicY3a09WmtKBWSbmC+5nfCqPzwWe7Hx2so74Er7mPsDfCiMMR0Ya+evKbJQDkfyXicg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-ia32": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-freebsd-ia32/-/koffi-freebsd-ia32-3.1.1.tgz", + "integrity": "sha512-7GejVb688TLM8rbjfc0oezJrATxZc0dn801xWEDJekN2DgmRXu7HquGqWQ6z3NeSq7ZxEggz4T3xtlbCysQapA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-x64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-freebsd-x64/-/koffi-freebsd-x64-3.1.1.tgz", + "integrity": "sha512-XLiCFP9OFCyOoGTjAimtDKLhzhfo34WcP1ShVWxRzNCWDGjfz8BYjwd69cp/cDSUXZbxamqs4+/6vmkePq9wxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-arm64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-arm64/-/koffi-linux-arm64-3.1.1.tgz", + "integrity": "sha512-HA9xINK7G4dRAkpfnBWD9VfuyIBgW1SuK+KPHjksUwRMOnhgqP8J/JqgrAzdzcDiefGBkqEacIP776OUwz7knQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-ia32": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-ia32/-/koffi-linux-ia32-3.1.1.tgz", + "integrity": "sha512-jG7IFytmP8K5Qtbx0ro0ZeuX3JjSsLxmYhq+nmXDdrtOAlxIsWGynuiDLS6Jk3vOchVii2m6Y2f/L3GLG2fG5A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-loong64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-loong64/-/koffi-linux-loong64-3.1.1.tgz", + "integrity": "sha512-CIsT1cNnih8FuU52Me/IVlJBpH28SQfoDeYPctJswgJzaARktusF7m4MUbtR1PBDjuquCVM4/vFyNdOzfPonvA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-riscv64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-riscv64/-/koffi-linux-riscv64-3.1.1.tgz", + "integrity": "sha512-9D6RmqeKsSvs3U6jILJU9PcAjMwKKyn7yLxNBb5k6z9PCoUoGJ3/BrhXAX0qjrLLwEiIpP/hS/40RuXvH8Lc3Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-x64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-linux-x64/-/koffi-linux-x64-3.1.1.tgz", + "integrity": "sha512-pyTcX5fePeYbt7TZAwRby69wdlRx3PT+g15ra5IYdat/Pgh3qAKEYeZ+uu7WpPGOy43p/oSRqqZoa2kORzozlA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-ia32": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-openbsd-ia32/-/koffi-openbsd-ia32-3.1.1.tgz", + "integrity": "sha512-iPnPzvG2HOfdzaiG1drdkt86sAqmTPDv9mAf+5gL7mRzkeeQC88EVGboRy7eXwdXn7R+v0ntA3iQxdHrBn6yXw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-x64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-openbsd-x64/-/koffi-openbsd-x64-3.1.1.tgz", + "integrity": "sha512-/Xqc3R0SVoMCYjMPZnJ9bULtRo364+dKmnQhfDrI83tSpxUHRw7HRNf12vBeL+hPgKxSBjtMpWfQ/ZIyVyLFag==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-arm64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-win32-arm64/-/koffi-win32-arm64-3.1.1.tgz", + "integrity": "sha512-JhqHauEwQvdcWUERxrV5HH/DT9W7hY1A1eU6/o8tB+yck+D3kt5elpRDBt9KjpW6h+vHPy3V0sjDvO0CXyabTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-ia32": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-win32-ia32/-/koffi-win32-ia32-3.1.1.tgz", + "integrity": "sha512-ZRuyYmlGS/rCc966qqs0qREXDW4FRdul7rDF1VgSWHbVmdc196PUgUT+blq/GjZgTwqzeEXtMRgM+cU8krHjvA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-x64": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@koromix/koffi-win32-x64/-/koffi-win32-x64-3.1.1.tgz", + "integrity": "sha512-KqHPmvj6QILhNyI/To8QSihHsijeVGIYYPBOUnXEpcnH2LuLbargY4Hd6dDeTN3Z90uUUxN+1FWz1UnhVzFOiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "license": "BSD-2-Clause" + }, + "node_modules/@modelcontextprotocol/client": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0.tgz", + "integrity": "sha512-8f1OghQ2rjzIOfqgUCP+8GiUWqRs89njoWLNqAe8kWmDePv3s1fZXseej+QXemssEuuOvLLmLO/kqM3IQHtISw==", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/core": "2.0.0", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "jose": "^6.1.3", + "pkce-challenge": "^5.0.0", + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@modelcontextprotocol/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0.tgz", + "integrity": "sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==", + "license": "MIT", + "dependencies": { + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", + "license": "MIT" + }, + "node_modules/@octokit/openapi-webhooks-types": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-12.1.0.tgz", + "integrity": "sha512-WiuzhOsiOvb7W3Pvmhf8d2C6qaLHXrWiLBP4nJ/4kydu+wpagV5Fkz9RfQwV2afYzv3PB+3xYgp4mAdNGjDprA==", + "license": "MIT" + }, + "node_modules/@octokit/request-error": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.2.tgz", + "integrity": "sha512-XZRuT3xZ84D3gYErI1DZvhJ33dCWVV6uzBtWkaBB4TvA/L6eOeTZodxLFVB44bBEEo3vEx7y00UfX1tBLrtLRg==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^18.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^29.0.1" + } + }, + "node_modules/@octokit/webhooks": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-14.2.0.tgz", + "integrity": "sha512-da6KbdNCV5sr1/txD896V+6W0iamFWrvVl8cHkBSPT+YlvmT3DwXa4jxZnQc+gnuTEqSWbBeoSZYTayXH9wXcw==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-webhooks-types": "12.1.0", + "@octokit/request-error": "^7.0.0", + "@octokit/webhooks-methods": "^6.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/webhooks-methods": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-6.0.0.tgz", + "integrity": "sha512-MFlzzoDJVw/GcbfzVC1RLR36QqkTLUf79vLVO3D+xn7r0QgxnFoLZgtrzxiQErAjFUOdH6fas2KeQJ1yr/qaXQ==", + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", + "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.9.0.tgz", + "integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.220.0.tgz", + "integrity": "sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-transformer": "0.220.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.220.0.tgz", + "integrity": "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/sdk-logs": "0.220.0", + "@opentelemetry/sdk-metrics": "2.9.0", + "@opentelemetry/sdk-trace": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.12.0.tgz", + "integrity": "sha512-+rSRoOdln6NhXTVcBdHSlZxJDNzwxadeweK2ltZO3tVtfp6aklABc06xclDk6ovRR+EiGgIcSbh/6NgjFhnb3A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.12.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.12.0.tgz", + "integrity": "sha512-1HsSAuvT4/my0QrXWsyXFdWjKaPeCHsismKZgEEIb8NK13LP6DrMRlsUbvD/0F9mDWK3xDom9AMv3IscxgOnOQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.220.0.tgz", + "integrity": "sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.9.0.tgz", + "integrity": "sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.9.0.tgz", + "integrity": "sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "license": "BSD-3-Clause" + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@smithy/core": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.36.0.tgz", + "integrity": "sha512-3hJiwG1F5t1SoXqp/yOCmYXziyx7ZVqF63S5W6YU201e/qwVaHPex+E/3vvyY9a3ORq/b+BydeNZpP2saQ9X2g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.8.0.tgz", + "integrity": "sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.18.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.1.tgz", + "integrity": "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.18.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.4.tgz", + "integrity": "sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.19.0.tgz", + "integrity": "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", + "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@vscode/ripgrep": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep/-/ripgrep-1.18.0.tgz", + "integrity": "sha512-ns5lWe44tSfbTMbVUsyB+I1819PVSw4AdpgK0RNkzfWfwy6+3IUNSxwSrfTno1/oWaS/hERNz+XLWVyga2aJBQ==", + "license": "MIT", + "optionalDependencies": { + "@vscode/ripgrep-darwin-arm64": "1.18.0", + "@vscode/ripgrep-darwin-x64": "1.18.0", + "@vscode/ripgrep-linux-arm": "1.18.0", + "@vscode/ripgrep-linux-arm64": "1.18.0", + "@vscode/ripgrep-linux-ia32": "1.18.0", + "@vscode/ripgrep-linux-ppc64": "1.18.0", + "@vscode/ripgrep-linux-riscv64": "1.18.0", + "@vscode/ripgrep-linux-s390x": "1.18.0", + "@vscode/ripgrep-linux-x64": "1.18.0", + "@vscode/ripgrep-win32-arm64": "1.18.0", + "@vscode/ripgrep-win32-ia32": "1.18.0", + "@vscode/ripgrep-win32-x64": "1.18.0" + } + }, + "node_modules/@vscode/ripgrep-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-darwin-arm64/-/ripgrep-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-r3ktHSvbFycQNF6sl7sNDPocpsI7J+mEzh1IaZFkY0spm3k2Z9t8hPAeOK7+p0l6p6/swkQC14XWX01low+94Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/ripgrep-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-darwin-x64/-/ripgrep-darwin-x64-1.18.0.tgz", + "integrity": "sha512-25b4gWbL138dGuQU244ebCKKc0q05ULBMoFSz9oAEUHNeqK/lOJViDS7DRvbDazzAzSEdan391Znks/R5mkaTQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-arm/-/ripgrep-linux-arm-1.18.0.tgz", + "integrity": "sha512-GDAvufNDHu8zqLEmXstalQF0Wh6wQvdsBi/Vg3Yi3CK4a8XoFXqqXVEHEZ9xQz3t0NfoSEc9JbvK9DDS6FxyxQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-arm64/-/ripgrep-linux-arm64-1.18.0.tgz", + "integrity": "sha512-lQ/5zTG++U0E3IhVgS4EPTTn/U4okncaRMM5GOFfOYZywS4nuD31GhkHbNYlDk5CuDC68+hYJ0/eQeyCKJDA+g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-ia32/-/ripgrep-linux-ia32-1.18.0.tgz", + "integrity": "sha512-YWLkSUtFd4Jh5EepIhA9RJSfv3uMAVMo+2rBIGHPBnvgLrZciIs2cDKei1/p6Wc/aCzUoHyMAg2R6tw4ZCBKGg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ppc64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-ppc64/-/ripgrep-linux-ppc64-1.18.0.tgz", + "integrity": "sha512-quXVY8fwQ8O/lvU1yrSqSl3jlUzysRSb+AfUfCL/tRtphxsKlFvPAejryZ6vg4Bgvn8XL74xb4qMCDmWgYrT5w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-riscv64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-riscv64/-/ripgrep-linux-riscv64-1.18.0.tgz", + "integrity": "sha512-f5kBQBrWfQt8Q7OhSORuNDei5dkYagBj3y4jImSUXGMy8B/Ke7SltSRcUtjPv166FAFfHCAmWuZp3+cWnX2/Vw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-s390x": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-s390x/-/ripgrep-linux-s390x-1.18.0.tgz", + "integrity": "sha512-rTOcJFGGcl2c07RUOWUo4U1ndnemKhY6A9hnMB18uk7jSgJc0d/QLBGWMWpumdtoJtpizn/wIv5mXIisJukusQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-linux-x64/-/ripgrep-linux-x64-1.18.0.tgz", + "integrity": "sha512-mQ3bVrUpnD2vs7QT0vX90Lt0cnUq467uFtEktIdsJJmW296RoSULRGqWgzG1AKxyBpNDD6l4ZO4qKf6SgyC23Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-win32-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-win32-arm64/-/ripgrep-win32-arm64-1.18.0.tgz", + "integrity": "sha512-vfTIjq1OHnzUjxZcHVQAMbnggp8dpGf+0QKFOZHwWPqFwXxQC8eCWM+5NUdoJ6yrElCeMzoUTXoK/LdZaniB+Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-win32-ia32/-/ripgrep-win32-ia32-1.18.0.tgz", + "integrity": "sha512-//rfAE+BOw5AC2EMmepmiE36jUuevtQYNQqqlw1s3m9FlRxjxEut97RkRPHAu9BG4mSojatZx+kXZXNdyI9caQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@vscode/ripgrep-win32-x64/-/ripgrep-win32-x64-1.18.0.tgz", + "integrity": "sha512-KNPvtElldqILHdnAetujPaowkNbpqJy3ssIGGN6F6Kve9Qi+nNLI2DN01O83JjCEVQbCzl8Ov3QZ9Eov3BR8Dg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@xterm/addon-serialize": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0.tgz", + "integrity": "sha512-uteyTU1EkrQa2Ux6P/uFl2fzmXI46jy5uoQMKEOM0fKTyiW7cSn0WrFenHm5vO5uEXX/GpwW/FgILvv3r0WbkA==", + "license": "MIT" + }, + "node_modules/@xterm/headless": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-6.0.0.tgz", + "integrity": "sha512-5Yj1QINYCyzrZtf8OFIHi47iQtI+0qYFPHmouEfG8dHNxbZ9Tb9YGSuLcsEwj9Z+OL75GJqPyJbyoFer80a2Hw==", + "license": "MIT", + "workspaces": [ + "addons/*" + ] + }, + "node_modules/agent-base": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.1.tgz", + "integrity": "sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/byte-counter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/byte-counter/-/byte-counter-0.1.0.tgz", + "integrity": "sha512-jheRLVMeUKrDBjVw2O5+k4EvR4t9wtxHL+bo/LxfkxsVeuGMy3a5SEGgXdAFA4FSzTrU8rQXQIrsZ3oBq5a0pQ==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "13.0.19", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-13.0.19.tgz", + "integrity": "sha512-SVXGH037+Mo1aIMO5B2UcleR43FGjFdN+M8JObSyEoQ2Mn4CODRWx28gN5jiTF0n5ItsgtIZfyargMNs8GX4kg==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.2.0", + "get-stream": "^9.0.1", + "http-cache-semantics": "^4.2.0", + "keyv": "^5.6.0", + "mimic-response": "^4.0.0", + "normalize-url": "^8.1.1", + "responselike": "^4.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz", + "integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "destroy": "1.2.0", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-10.0.0.tgz", + "integrity": "sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==", + "license": "MIT", + "dependencies": { + "mimic-response": "^4.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "license": "MIT" + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-10.1.1.tgz", + "integrity": "sha512-yJAC9ulsE6fU0K6wzJBIH+wI+KAtMeu6Ck8rs23OVzvEhqXjGADdI6K+YNIDAjcQQ6AwXTD96cKExJo6xFJXyg==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "figures": "^6.1.0", + "get-stream": "^9.0.1", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.3.1", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "which-command": "^0.1.0", + "yoctocolors": "^2.2.0" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT" + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fontkit": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", + "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.12", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "dfa": "^1.2.0", + "fast-deep-equal": "^3.1.3", + "restructure": "^3.0.0", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.4.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/form-data-encoder": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.1.0.tgz", + "integrity": "sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/gaxios": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.3.1.tgz", + "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gaxios/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/gaxios/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-auth-library": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.9.1.tgz", + "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/got": { + "version": "14.6.6", + "resolved": "https://registry.npmjs.org/got/-/got-14.6.6.tgz", + "integrity": "sha512-QLV1qeYSo5l13mQzWgP/y0LbMr5Plr5fJilgAIwgnwseproEbtNym8xpLsDzeZ6MWXgNE6kdWGBjdh3zT/Qerg==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^7.0.1", + "byte-counter": "^0.1.0", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^13.0.12", + "decompress-response": "^10.0.0", + "form-data-encoder": "^4.0.2", + "http2-wrapper": "^2.2.1", + "keyv": "^5.5.3", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^4.0.1", + "responselike": "^4.0.2", + "type-fest": "^4.26.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz", + "integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==", + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", + "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", + "license": "MIT", + "dependencies": { + "agent-base": "9.0.0", + "debug": "^4.3.4", + "proxy-agent-negotiate": "1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", + "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.12", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", + "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbi": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.2.tgz", + "integrity": "sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==", + "license": "Apache-2.0" + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/koffi": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-3.1.1.tgz", + "integrity": "sha512-mRX6AMeeKCxSOeOopqAcLAl5jcNvge7NAG8l7rF/8gGJATI0tdHFYjteIdE0mGOtWdsrJOij+PjnP8Q9c1gwgA==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "url": "https://liberapay.com/Koromix" + }, + "optionalDependencies": { + "@koromix/koffi-darwin-arm64": "3.1.1", + "@koromix/koffi-darwin-x64": "3.1.1", + "@koromix/koffi-freebsd-arm64": "3.1.1", + "@koromix/koffi-freebsd-ia32": "3.1.1", + "@koromix/koffi-freebsd-x64": "3.1.1", + "@koromix/koffi-linux-arm64": "3.1.1", + "@koromix/koffi-linux-ia32": "3.1.1", + "@koromix/koffi-linux-loong64": "3.1.1", + "@koromix/koffi-linux-riscv64": "3.1.1", + "@koromix/koffi-linux-x64": "3.1.1", + "@koromix/koffi-openbsd-ia32": "3.1.1", + "@koromix/koffi-openbsd-x64": "3.1.1", + "@koromix/koffi-win32-arm64": "3.1.1", + "@koromix/koffi-win32-ia32": "3.1.1", + "@koromix/koffi-win32-x64": "3.1.1" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/node-addon-native-custom-loader": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-native-custom-loader/-/node-addon-native-custom-loader-0.1.9.tgz", + "integrity": "sha512-Zh87aubSc1UF8CzZsRws1KtSwXiPDH0tbcg8V/2OA8Tcq9yGJRESFcEOC5NGLFama5IGfC3aJhubZbrj9Un2qA==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin/-/node-addon-require-builtin-0.1.9.tgz", + "integrity": "sha512-BCxXCMZDs/VLLh64SwKNw/me7Qx1I7Be4qxWwYVRRm8tJoOB8fL7qg6CmXhSXeUqsKt72t8RaKCX4EN+5nocVg==", + "license": "MIT", + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "node-addon-require-builtin-darwin-arm64": "0.1.9", + "node-addon-require-builtin-darwin-x64": "0.1.9", + "node-addon-require-builtin-linux-arm64-gnu": "0.1.9", + "node-addon-require-builtin-linux-arm64-musl": "0.1.9", + "node-addon-require-builtin-linux-x64-gnu": "0.1.9", + "node-addon-require-builtin-linux-x64-musl": "0.1.9", + "node-addon-require-builtin-win32-arm64-msvc": "0.1.9", + "node-addon-require-builtin-win32-ia32-msvc": "0.1.9", + "node-addon-require-builtin-win32-x64-msvc": "0.1.9" + } + }, + "node_modules/node-addon-require-builtin-darwin-arm64": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-darwin-arm64/-/node-addon-require-builtin-darwin-arm64-0.1.9.tgz", + "integrity": "sha512-n45xEILQVOLZ2hVhzRXesTMYS4odHquyI/B/IkPMPUCONa8PjNfBag6lYBH4wDrhgpLNNBwMsUD8d8O/13QPPA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-darwin-x64": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-darwin-x64/-/node-addon-require-builtin-darwin-x64-0.1.9.tgz", + "integrity": "sha512-Sm4Liqh1uo9zgJB2F/pACPPZdHu+fj9Qniyr1Q99dDQB0v71VgZgkAgv3K0/E1iPQBlZq9rakFkY7MGUIfWc0A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-arm64-gnu": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-linux-arm64-gnu/-/node-addon-require-builtin-linux-arm64-gnu-0.1.9.tgz", + "integrity": "sha512-ToU4wGtOD/069i2y4fJ3cjDJiiWtcjSQTZMf0YKlotb5BmTM7FjhR3X1aub8J/YjlOwl6665J/XAYuvCaDO5sA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-arm64-musl": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-linux-arm64-musl/-/node-addon-require-builtin-linux-arm64-musl-0.1.9.tgz", + "integrity": "sha512-85Z5Avp++wfa9iiTIH8LC/r6qvlC/CiwpifiwIz0gYQ9PzajTSkz06gX7YDqf1oUqWYxU9uwNEOmo7mktHOOfA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-x64-gnu": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-linux-x64-gnu/-/node-addon-require-builtin-linux-x64-gnu-0.1.9.tgz", + "integrity": "sha512-fh3K3/JvBfSYwU8vEOpp4Wdp4N/jX0EnZYq5GsaftlQin1FVqgve/yDNoh+asxBMOQyHOG8F4dXlV1WCierrfg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-x64-musl": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-linux-x64-musl/-/node-addon-require-builtin-linux-x64-musl-0.1.9.tgz", + "integrity": "sha512-B6fu/5xmbRxnifM7nWz0IESkYnUl8dwFZmRDMsxdhzv2nb+EtBRFAXg4lf73qhX3yoZD4SnWJILBQMlIAwBCzw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-arm64-msvc": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-win32-arm64-msvc/-/node-addon-require-builtin-win32-arm64-msvc-0.1.9.tgz", + "integrity": "sha512-FOQuzNe8B1BANu886rJgdbQuRxPGUQmewkykw87wSr32U0ibQ3AWGuUM/Gh7LG4RekjFaifj7gEI/tq2+6GU6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-ia32-msvc": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-win32-ia32-msvc/-/node-addon-require-builtin-win32-ia32-msvc-0.1.9.tgz", + "integrity": "sha512-N29P0kmIBT6hnkNNFYzxn+o9ydT6OYZe9RFAi8dSxV1rNSul1FlxtuKWYe8w2sQpbQGYuGDEtpOwdeFtq2iFTg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20 <23" + } + }, + "node_modules/node-addon-require-builtin-win32-x64-msvc": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-win32-x64-msvc/-/node-addon-require-builtin-win32-x64-msvc-0.1.9.tgz", + "integrity": "sha512-+i6N4A7m7txjbw8pDYESdWXiKO9EEVq0SzTzwPS0WZuV4F1MzQnaDJwJJnO7T6zAc0BvqHXBOkpharCrUjFhbQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.9" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-pty": { + "version": "1.2.0-beta.15", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.2.0-beta.15.tgz", + "integrity": "sha512-vORSzHXi4Ofl7HemVWpuudLqCPdaQb4LfpRCUpE5HPxhp4JYscl8zZwxh11p26v2wvW24WMwnMfLjhRLixrfxA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^7.1.0" + } + }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/open": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", + "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.5.1", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "6.40.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.40.0.tgz", + "integrity": "sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA==", + "license": "Apache-2.0", + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/p-cancelable": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", + "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/powershell-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.1.tgz", + "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", + "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/protobufjs": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", + "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-agent-negotiate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", + "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "kerberos": "^2.0.0" + }, + "peerDependenciesMeta": { + "kerberos": { + "optional": true + } + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve.exports": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.4.tgz", + "integrity": "sha512-zepuGL0ulf+nt+XaFrlKeaiTJeyPFPLLY62+ncq1/VTHBdt3HsfXOH60priZ6tnXQozdGcDeIF5JVTanvIcYWQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/responselike": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-4.0.2.tgz", + "integrity": "sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restructure": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", + "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==", + "license": "MIT" + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sherpa-onnx-darwin-arm64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-darwin-arm64/-/sherpa-onnx-darwin-arm64-1.13.8.tgz", + "integrity": "sha512-FPNgJMgnWVl/KhRTIhG3KL3A4Om63Rn4YKXc9/uHY7SzLcvqLJLc/h7UBWJwduXvv7K18t5NpxHR6XgXn4sjWw==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/sherpa-onnx-darwin-x64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-darwin-x64/-/sherpa-onnx-darwin-x64-1.13.8.tgz", + "integrity": "sha512-7BLRpjM6w4f9W46/nmkmq8lEKUayhebvcpslCVQ+6QN2uReYlZEMDZlSpXMjme+hUFrPfRz8P3UNq8ep/4d19g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/sherpa-onnx-linux-arm64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-linux-arm64/-/sherpa-onnx-linux-arm64-1.13.8.tgz", + "integrity": "sha512-Tlg7a70b/Wge3OF8IgTHF9jhSVCsLyKQKhwc4BsJ5A+dL/SrFtGBjzuHp4XeLhiiOT7afCxX5PdSn/D4c8Lnuw==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/sherpa-onnx-linux-x64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-linux-x64/-/sherpa-onnx-linux-x64-1.13.8.tgz", + "integrity": "sha512-6plnhjagsSeTntCgnlag86hWbs/uZE9Crms1LgOb68/1nKsIQjMd+WG519m+aPwT6TrsBOiEMzrx41t8sL5L5g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/sherpa-onnx-node": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-node/-/sherpa-onnx-node-1.13.8.tgz", + "integrity": "sha512-MsDMBdhLFTZ1GwvcGSSQhnS7g/EA8OMH6IYysCVUOM7j8Icty9KRc0E6YT1A5fWBsZwRfKOeh88QC95aRvS8ag==", + "license": "Apache-2.0", + "optionalDependencies": { + "sherpa-onnx-darwin-arm64": "^1.13.8", + "sherpa-onnx-darwin-x64": "^1.13.8", + "sherpa-onnx-linux-arm64": "^1.13.8", + "sherpa-onnx-linux-x64": "^1.13.8", + "sherpa-onnx-win-ia32": "^1.13.8", + "sherpa-onnx-win-x64": "^1.13.8" + } + }, + "node_modules/sherpa-onnx-win-ia32": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-win-ia32/-/sherpa-onnx-win-ia32-1.13.8.tgz", + "integrity": "sha512-H0Ojln9hfvM+pxWqW0cnjB/XK8/JPq4/k0IWu2JpY5Z458M3zv+XC3Hu+wmot3AoH/K1Bgt23n/tTKtPV9x8qg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/sherpa-onnx-win-x64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-win-x64/-/sherpa-onnx-win-x64-1.13.8.tgz", + "integrity": "sha512-oZF1c9VPOKtMwn83Bboc5XSWL+76BRoyB3eUuVnCknBKxwSULZU2Foia9VHWzU+n4I12rPsP6z6H9Rp1hD9o8g==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/standardwebhooks": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.1.1.tgz", + "integrity": "sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/turndown": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.4.tgz", + "integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==", + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + }, + "engines": { + "node": ">=18", + "npm": ">=9" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typebox": { + "version": "1.3.27", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.27.tgz", + "integrity": "sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "license": "MIT" + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-command": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/which-command/-/which-command-0.1.0.tgz", + "integrity": "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA==", + "license": "MIT", + "bin": { + "which-command": "cli.js" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/which-command?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz", + "integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.1.tgz", + "integrity": "sha512-c16PKLIRxBYpR3jSWsdS7SFp0COm5SOQdiFjY818dYFHJbMGuLBszpF07LBWmOS1uzrHa9VGdynsEgoeKy0oOQ==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yoctocolors": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/go/harness/byo/dsh/package.json b/go/harness/byo/dsh/package.json new file mode 100644 index 0000000000..0766086107 --- /dev/null +++ b/go/harness/byo/dsh/package.json @@ -0,0 +1,9 @@ +{ + "name": "kagent-dsh-byo-runtime", + "private": true, + "version": "0.1.0", + "description": "Pinned DSH installation for the BYO reference image", + "dependencies": { + "@deepseek-ai/dsh": "0.2.0-rc.2" + } +} From 0923e4019a7a2a852f21b16d456f40c02ca4ae2a Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 15:36:55 +0800 Subject: [PATCH 02/12] fix: make DSH ACP writes cancellable Close the ACP input stream when a blocked write is canceled and bound cancellation messages by a deadline. Cover blocked prompt, setup and permission writes, plus real DSH tool errors, permission decisions and resumed MCP calls. AI-assisted development with Codex; human review is required before upstream submission. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 9 +- .../bridge/real_tools_integration_test.go | 180 ++++++++++++++++++ go/harness/byo/dsh/internal/bridge/rpc.go | 32 +++- .../byo/dsh/internal/bridge/rpc_test.go | 54 +++++- go/harness/byo/dsh/internal/bridge/runner.go | 19 +- 5 files changed, 277 insertions(+), 17 deletions(-) create mode 100644 go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index fccdf76864..992a711a97 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -45,6 +45,10 @@ DSH session. A pending permission request retains that process until the decision arrives. Completion closes the session and stdin so DSH can flush its state; cancellation is followed by bounded process-group cleanup. +Cancellation interrupts blocked ACP writes by closing stdin. Forced process-group +cleanup does not yet prove that DSH tools in separate process groups have exited; +this remains a lifecycle acceptance gap before release. + `/data/adapter/state.json` binds the Actor to one native session. DSH session logs and storage live under `/data/dsh`, and the workspace is `/data/workspace`. The CLI profile and compiled overlay use a disposable home outside `/data`. @@ -66,7 +70,10 @@ docker push YOUR_REGISTRY/kagent-dsh-byo:dev Record the pushed image's manifest digest. The example requires the full `YOUR_REGISTRY/kagent-dsh-byo@sha256:...` reference, not its tag. -Use a clean kagent 1.x alpha installation with a configured `kagent-default` +Use a clean kagent installation whose Agent CRD supports `spec.template.inline`. +This example targets the API at source commit `b42a6c53`; `1.0.0-alpha9` uses +the earlier `templateRef` shape and rejects this Agent manifest. Cluster acceptance +against a compatible release is still required. Configure a `kagent-default` WorkerPool, snapshot storage, and Substrate credential gateway. In namespace `kagent`, create the Secret `deepseek-api-key` with an `OPENAI_API_KEY` entry using your normal secret-management workflow. Grant the Substrate atespace diff --git a/go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go b/go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go new file mode 100644 index 0000000000..e0dbb13176 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go @@ -0,0 +1,180 @@ +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +func TestRealDSHBuiltinToolsAndPermissions(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("DSH_TEST_BIN required") + } + for _, scenario := range []string{"bash", "approval-allow", "approval-reject", "approval-cancel", "malformed-arguments"} { + t.Run(scenario, func(t *testing.T) { + var requests atomic.Int32 + model := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var body struct { + Tools []struct { + Function struct { + Name string `json:"name"` + } `json:"function"` + } `json:"tools"` + Messages json.RawMessage `json:"messages"` + } + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, "bad request", 400) + return + } + if requests.Add(1) == 1 { + name := "" + for _, tool := range body.Tools { + if tool.Function.Name == "bash" { + name = tool.Function.Name + } + } + if name == "" { + http.Error(w, "no bash tool", 500) + return + } + args := `{"command":"printf audit-ok","description":"Print a harmless acceptance test marker"}` + if strings.HasPrefix(scenario, "approval-") { + args = `{"command":"printf audit-ok","description":"Print a harmless acceptance test marker","sandbox_permissions":"danger-full-access","justification":"Exercise approval with a harmless marker."}` + } + if scenario == "malformed-arguments" { + args = `{"command":` + } + writeCompletion(w, map[string]any{"role": "assistant", "tool_calls": []any{map[string]any{"index": 0, "id": "audit-call", "type": "function", "function": map[string]string{"name": name, "arguments": args}}}}, "tool_calls") + } else { + writeCompletion(w, map[string]string{"role": "assistant", "content": "audit complete"}, "stop") + } + })) + defer model.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock","base_url":%q},"runtime":{"control_plane_url":"http://controller:8083"}}`, model.URL+"/v1"))) + require.NoError(t, err) + runner, err := New(cfg, executable, t.TempDir(), append(os.Environ(), "OPENAI_API_KEY=mock", "DSH_PERMISSION_MODE=workspace-write")) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 40*time.Second) + defer cancel() + segmentCtx, finishSegment := context.WithCancel(ctx) + defer finishSegment() + sink := &recordingSink{} + out, err := runner.Run(segmentCtx, runtime.Turn{Prompt: "Run the acceptance check."}, sink) + require.NoError(t, err) + finishSegment() + if strings.HasPrefix(scenario, "approval-") { + require.NotNil(t, out.Pending, "real DSH must produce an approval request") + if scenario == "approval-cancel" { + require.NoError(t, out.Pending.Cancel(ctx, sink)) + resumed := &recordingSink{} + out, err = runner.Run(ctx, runtime.Turn{Prompt: "Continue after permission cancellation.", ContinuationID: sink.id}, resumed) + require.NoError(t, err) + require.Nil(t, out.Failure) + require.Nil(t, out.Pending) + require.Equal(t, sink.id, resumed.id) + require.Equal(t, []string{"audit complete"}, resumed.texts) + require.Equal(t, int32(2), requests.Load()) + return + } + request := out.Pending.Request().(*runtime.ApprovalRequest) + out, err = out.Pending.Resume(ctx, &runtime.ApprovalDecision{ID: request.ID, Approved: scenario == "approval-allow"}, sink) + require.NoError(t, err) + } + require.Nil(t, out.Failure) + require.Nil(t, out.Pending) + require.Len(t, sink.results, 1) + require.Equal(t, scenario == "approval-reject" || scenario == "malformed-arguments", sink.results[0].IsError) + if scenario == "approval-reject" { + require.Equal(t, runtime.ToolDeclined, sink.results[0].Status) + } + if scenario == "bash" || scenario == "approval-allow" { + require.False(t, sink.results[0].IsError) + require.Contains(t, fmt.Sprint(sink.results[0].Result), "audit-ok") + } + require.Equal(t, int32(2), requests.Load(), "tool failure should be returned to the model for recovery") + }) + } +} + +func TestRealDSHMCPErrorAndResumedToolCall(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("DSH_TEST_BIN required") + } + var calls atomic.Int32 + remote := mcp.NewServer(&mcp.Implementation{Name: "audit", Version: "1"}, nil) + mcp.AddTool(remote, &mcp.Tool{Name: "audit_tool", Description: "Exercise tool errors and resumed calls."}, func(context.Context, *mcp.CallToolRequest, map[string]any) (*mcp.CallToolResult, map[string]any, error) { + n := calls.Add(1) + if n == 1 { + return &mcp.CallToolResult{IsError: true, Content: []mcp.Content{&mcp.TextContent{Text: "audit expected tool failure"}}}, nil, nil + } + return nil, map[string]any{"result": "resumed-tool-ok"}, nil + }) + remoteHTTP := httptest.NewServer(mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return remote }, &mcp.StreamableHTTPOptions{Stateless: true})) + defer remoteHTTP.Close() + var n atomic.Int32 + model := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var body struct { + Tools []struct { + Function struct { + Name string `json:"name"` + } `json:"function"` + } `json:"tools"` + Messages json.RawMessage `json:"messages"` + } + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, "bad request", 400) + return + } + index := n.Add(1) + if index == 1 || index == 3 { + name := "" + for _, tool := range body.Tools { + if strings.HasSuffix(tool.Function.Name, "audit_tool") { + name = tool.Function.Name + } + } + writeCompletion(w, map[string]any{"role": "assistant", "tool_calls": []any{map[string]any{"index": 0, "id": fmt.Sprintf("call-%d", index), "type": "function", "function": map[string]string{"name": name, "arguments": "{}"}}}}, "tool_calls") + } else { + if index == 2 { + assert.Contains(t, string(body.Messages), "audit expected tool failure") + } else { + assert.Contains(t, string(body.Messages), "resumed-tool-ok") + } + writeCompletion(w, map[string]string{"role": "assistant", "content": "settled"}, "stop") + } + })) + defer model.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock","base_url":%q},"runtime":{"control_plane_url":"http://controller:8083"},"http_tools":[{"params":{"url":%q}}]}`, model.URL+"/v1", remoteHTTP.URL))) + require.NoError(t, err) + runner, err := New(cfg, executable, t.TempDir(), append(os.Environ(), "OPENAI_API_KEY=mock")) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 40*time.Second) + defer cancel() + id := "" + for i := range 2 { + sink := &recordingSink{} + out, err := runner.Run(ctx, runtime.Turn{Prompt: "Call audit_tool.", ContinuationID: id}, sink) + require.NoError(t, err) + require.Nil(t, out.Failure) + id = sink.id + require.Len(t, sink.results, 1) + require.Equal(t, i == 0, sink.results[0].IsError) + } + require.Equal(t, int32(2), calls.Load()) +} diff --git a/go/harness/byo/dsh/internal/bridge/rpc.go b/go/harness/byo/dsh/internal/bridge/rpc.go index d2864cdeca..4398904895 100644 --- a/go/harness/byo/dsh/internal/bridge/rpc.go +++ b/go/harness/byo/dsh/internal/bridge/rpc.go @@ -29,14 +29,14 @@ type frame struct { } type wire struct { - writer io.Writer + writer io.WriteCloser mu sync.Mutex frames chan frame done chan struct{} readDone chan struct{} } -func newWire(writer io.Writer, reader io.Reader) *wire { +func newWire(writer io.WriteCloser, reader io.Reader) *wire { w := &wire{writer: writer, frames: make(chan frame, 16), done: make(chan struct{}), readDone: make(chan struct{})} go w.read(reader) return w @@ -72,7 +72,7 @@ func (w *wire) deliver(f frame) bool { } } -func (w *wire) send(m message, params any) error { +func (w *wire) send(ctx context.Context, m message, params any) error { if params != nil { data, err := json.Marshal(params) if err != nil { @@ -84,20 +84,38 @@ func (w *wire) send(m message, params any) error { if err != nil { return fmt.Errorf("failed to encode ACP message: %w", err) } + // Canceling a partially written frame invalidates the stream. Closing stdin + // also interrupts a blocked pipe write; the process owner then reaps DSH. + interrupted := make(chan struct{}) + stop := context.AfterFunc(ctx, func() { + _ = w.writer.Close() + close(interrupted) + }) + defer func() { + if !stop() { + <-interrupted + } + }() w.mu.Lock() defer w.mu.Unlock() + if err := ctx.Err(); err != nil { + return err + } if _, err := w.writer.Write(append(data, '\n')); err != nil { + if ctx.Err() != nil { + return ctx.Err() + } return fmt.Errorf("failed to write ACP message: %w", err) } - return nil + return ctx.Err() } -func (w *wire) respond(id json.RawMessage, result any) error { +func (w *wire) respond(ctx context.Context, id json.RawMessage, result any) error { data, err := json.Marshal(result) if err != nil { return fmt.Errorf("failed to encode ACP response: %w", err) } - return w.send(message{JSONRPC: "2.0", ID: id, Result: data}, nil) + return w.send(ctx, message{JSONRPC: "2.0", ID: id, Result: data}, nil) } func (w *wire) next(ctx context.Context) (message, error) { @@ -114,7 +132,7 @@ func (w *wire) next(ctx context.Context) (message, error) { // Setup calls have no active turn, so requests are rejected and updates ignored. func (w *wire) call(ctx context.Context, id string, method string, params any) (json.RawMessage, error) { - if err := w.send(message{JSONRPC: "2.0", ID: json.RawMessage(id), Method: method}, params); err != nil { + if err := w.send(ctx, message{JSONRPC: "2.0", ID: json.RawMessage(id), Method: method}, params); err != nil { return nil, err } for { diff --git a/go/harness/byo/dsh/internal/bridge/rpc_test.go b/go/harness/byo/dsh/internal/bridge/rpc_test.go index 090926936a..a256a12987 100644 --- a/go/harness/byo/dsh/internal/bridge/rpc_test.go +++ b/go/harness/byo/dsh/internal/bridge/rpc_test.go @@ -2,9 +2,11 @@ package bridge import ( "context" + "encoding/json" "io" "strings" "testing" + "time" "github.com/stretchr/testify/require" ) @@ -16,7 +18,7 @@ func TestWireRejectsMalformedAndOversizedFrames(t *testing.T) { {"oversized", strings.Repeat("x", maxFrameBytes+1) + "\n"}, } { t.Run(test.name, func(t *testing.T) { - w := newWire(io.Discard, strings.NewReader(test.data)) + w := newWire(discardACPInput{}, strings.NewReader(test.data)) _, err := w.next(context.Background()) require.Error(t, err) close(w.done) @@ -31,7 +33,7 @@ func TestWireChecksResponseIdentityAndHidesErrorContent(t *testing.T) { {"remote error", `{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"secret"}}`}, } { t.Run(test.name, func(t *testing.T) { - w := newWire(io.Discard, strings.NewReader(test.data+"\n")) + w := newWire(discardACPInput{}, strings.NewReader(test.data+"\n")) _, err := w.call(t.Context(), "1", "initialize", struct{}{}) require.Error(t, err) require.NotContains(t, err.Error(), "secret") @@ -40,3 +42,51 @@ func TestWireChecksResponseIdentityAndHidesErrorContent(t *testing.T) { }) } } + +type discardACPInput struct{} + +func (discardACPInput) Write(data []byte) (int, error) { return len(data), nil } +func (discardACPInput) Close() error { return nil } + +func TestWireCancelsBlockedWrites(t *testing.T) { + for _, method := range []string{"prompt", "setup", "permission", "cancel"} { + t.Run(method, func(t *testing.T) { + reader, writer := io.Pipe() + w := newWire(writer, strings.NewReader("")) + t.Cleanup(func() { + close(w.done) + <-w.readDone + require.NoError(t, reader.Close()) + require.NoError(t, writer.Close()) + }) + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + done := make(chan error, 1) + go func() { + payload := strings.Repeat("x", 1<<20) + var err error + switch method { + case "prompt": + err = w.send(ctx, message{JSONRPC: "2.0", ID: json.RawMessage(promptID), Method: "session/prompt"}, payload) + case "setup": + _, err = w.call(ctx, "2", "session/new", payload) + case "permission": + err = w.respond(ctx, json.RawMessage("99"), payload) + case "cancel": + err = w.send(ctx, message{JSONRPC: "2.0", Method: "session/cancel"}, payload) + } + done <- err + }() + // Reading only one byte leaves Write blocked on the rest of the frame. + _, err := io.ReadFull(reader, make([]byte, 1)) + require.NoError(t, err) + cancel() + select { + case err := <-done: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(time.Second): + t.Fatal("ACP write did not respond to cancellation") + } + }) + } +} diff --git a/go/harness/byo/dsh/internal/bridge/runner.go b/go/harness/byo/dsh/internal/bridge/runner.go index 8e7790614a..bf6810c4c2 100644 --- a/go/harness/byo/dsh/internal/bridge/runner.go +++ b/go/harness/byo/dsh/internal/bridge/runner.go @@ -188,7 +188,7 @@ func (r *Runner) Run(ctx context.Context, turn runtime.Turn, sink runtime.EventS if err := sink.SessionStarted(runtime.SessionStarted{ContinuationID: id}); err != nil { return out, err } - if err := p.wire.send(message{JSONRPC: "2.0", ID: json.RawMessage(promptID), Method: "session/prompt"}, struct { + if err := p.wire.send(ctx, message{JSONRPC: "2.0", ID: json.RawMessage(promptID), Method: "session/prompt"}, struct { SessionID string `json:"sessionId"` Prompt []content `json:"prompt"` }{SessionID: id, Prompt: []content{{Type: "text", Text: turn.Prompt}}}); err != nil { @@ -296,23 +296,25 @@ func (p *pending) Resume(ctx context.Context, response runtime.InputResponse, si tool.declined = true p.process.events.tools[p.request.CallID] = tool } - if err := p.process.wire.respond(p.id, permissionResponse{Outcome: permissionOutcome{Outcome: "selected", OptionID: option}}); err != nil { + if err := p.process.wire.respond(ctx, p.id, permissionResponse{Outcome: permissionOutcome{Outcome: "selected", OptionID: option}}); err != nil { return out, err } return p.process.collect(ctx, sink) } func (p *pending) Cancel(_ context.Context, _ runtime.ModelCallSink) error { - err := p.process.wire.respond(p.id, permissionResponse{Outcome: permissionOutcome{Outcome: "cancelled"}}) + ctx, cancel := context.WithTimeout(context.Background(), stopTimeout) + defer cancel() + err := p.process.wire.respond(ctx, p.id, permissionResponse{Outcome: permissionOutcome{Outcome: "cancelled"}}) return errors.Join(err, p.process.cancel(), p.process.stop()) } func (p *process) cancel() error { - if err := p.wire.send(message{JSONRPC: "2.0", Method: "session/cancel"}, sessionParams{SessionID: p.events.sessionID}); err != nil { - return err - } ctx, cancel := context.WithTimeout(context.Background(), stopTimeout) defer cancel() + if err := p.wire.send(ctx, message{JSONRPC: "2.0", Method: "session/cancel"}, sessionParams{SessionID: p.events.sessionID}); err != nil { + return err + } for { m, err := p.wire.next(ctx) if err != nil { @@ -325,7 +327,7 @@ func (p *process) cancel() error { if m.Method != "session/request_permission" { return fmt.Errorf("unsupported ACP request during cancellation") } - if err := p.wire.respond(m.ID, permissionResponse{Outcome: permissionOutcome{Outcome: "cancelled"}}); err != nil { + if err := p.wire.respond(ctx, m.ID, permissionResponse{Outcome: permissionOutcome{Outcome: "cancelled"}}); err != nil { return err } } @@ -336,6 +338,9 @@ func (p *process) cancel() error { func (p *process) stop() error { close(p.wire.done) err := p.stdin.Close() + if errors.Is(err, os.ErrClosed) || errors.Is(err, io.ErrClosedPipe) { + err = nil + } select { case <-p.done: case <-time.After(stopTimeout): From 7e737586f4b8efd599610d03256b82eeef69a39b Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 15:49:41 +0800 Subject: [PATCH 03/12] fix: clean up DSH after MCP discovery failures Handle invalid remote tool schemas as startup errors and reject repeated pagination cursors. Verify remote session and DSH process cleanup. AI assistance: implementation and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/internal/bridge/mcp.go | 10 +- .../dsh/internal/bridge/mcp_discovery_test.go | 96 +++++++++++++++ .../bridge/mcp_runner_cleanup_test.go | 113 ++++++++++++++++++ 3 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 go/harness/byo/dsh/internal/bridge/mcp_discovery_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go diff --git a/go/harness/byo/dsh/internal/bridge/mcp.go b/go/harness/byo/dsh/internal/bridge/mcp.go index a22f128485..f81c9b5431 100644 --- a/go/harness/byo/dsh/internal/bridge/mcp.go +++ b/go/harness/byo/dsh/internal/bridge/mcp.go @@ -30,6 +30,9 @@ func startMCP(ctx context.Context, cfg *config.Config, bindings []config.MCPServ root, cancel := context.WithCancel(context.WithoutCancel(ctx)) p := &mcpProxy{cancel: cancel} defer func() { + if recovered := recover(); recovered != nil { + returnErr = fmt.Errorf("failed to initialize MCP proxy: %v", recovered) + } if returnErr != nil { returnErr = errors.Join(returnErr, p.close()) } @@ -46,6 +49,9 @@ func startMCP(ctx context.Context, cfg *config.Config, bindings []config.MCPServ p.transports = append(p.transports, transport) httpClient := &http.Client{Timeout: timeout, Transport: headerTransport{base: transport, headers: binding.Headers, terminate: terminate}} connectCtx, connectCancel := context.WithTimeout(ctx, timeout) + // AddTool can panic on an invalid remote schema; release the discovery + // deadline even when the startup recovery above handles that panic. + defer connectCancel() session, err := mcp.NewClient(&mcp.Implementation{Name: "kagent-dsh-byo", Version: "1"}, nil).Connect(connectCtx, &mcp.StreamableClientTransport{Endpoint: binding.URL, HTTPClient: httpClient}, nil) if err != nil { connectCancel() @@ -54,6 +60,7 @@ func startMCP(ctx context.Context, cfg *config.Config, bindings []config.MCPServ p.sessions = append(p.sessions, session) server := mcp.NewServer(&mcp.Implementation{Name: binding.Name, Version: "1"}, nil) cursor := "" + seenCursors := make(map[string]struct{}) for { listed, err := session.ListTools(connectCtx, &mcp.ListToolsParams{Cursor: cursor}) if err != nil { @@ -71,11 +78,12 @@ func startMCP(ctx context.Context, cfg *config.Config, bindings []config.MCPServ if listed.NextCursor == "" { break } - if listed.NextCursor == cursor { + if _, exists := seenCursors[listed.NextCursor]; exists { connectCancel() return nil, fmt.Errorf("MCP binding %d repeated a discovery cursor", i) } cursor = listed.NextCursor + seenCursors[cursor] = struct{}{} } connectCancel() path := fmt.Sprintf("/mcp/%d", i) diff --git a/go/harness/byo/dsh/internal/bridge/mcp_discovery_test.go b/go/harness/byo/dsh/internal/bridge/mcp_discovery_test.go new file mode 100644 index 0000000000..38420a5da6 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/mcp_discovery_test.go @@ -0,0 +1,96 @@ +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" +) + +func TestMCPDiscoveryRejectsInvalidCatalogAndCursorCycle(t *testing.T) { + for _, mode := range []string{"invalid-schema", "list-error", "cursor-cycle"} { + t.Run(mode, func(t *testing.T) { + var deletes, pages atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodDelete { + deletes.Add(1) + w.WriteHeader(200) + return + } + if r.Method != http.MethodPost { + w.WriteHeader(405) + return + } + var request message + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + http.Error(w, "bad request", 400) + return + } + if len(request.ID) == 0 { + w.WriteHeader(202) + return + } + w.Header().Set("Content-Type", "application/json") + var result any + switch request.Method { + case "initialize": + w.Header().Set("Mcp-Session-Id", "audit-session") + result = json.RawMessage(`{"protocolVersion":"2025-11-25","capabilities":{"tools":{}},"serverInfo":{"name":"audit","version":"1"}}`) + case "tools/list": + n := pages.Add(1) + switch mode { + case "invalid-schema": + result = json.RawMessage(`{"tools":[{"name":"broken","inputSchema":{"type":"array"}}]}`) + case "list-error": + _ = json.NewEncoder(w).Encode(message{JSONRPC: "2.0", ID: request.ID, Error: &rpcError{Code: -32603, Message: "discovery unavailable"}}) + return + case "cursor-cycle": + cursor := "A" + if n%2 == 0 { + cursor = "B" + } + result = struct { + Tools []any `json:"tools"` + NextCursor string `json:"nextCursor"` + }{Tools: []any{}, NextCursor: cursor} + } + default: + http.Error(w, "unknown method", 400) + return + } + data, _ := json.Marshal(result) + _ = json.NewEncoder(w).Encode(message{JSONRPC: "2.0", ID: request.ID, Result: data}) + })) + defer server.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"},"http_tools":[{"params":{"url":%q,"timeout":0.5,"terminate_on_close":true}}]}`, server.URL))) + require.NoError(t, err) + bindings, err := cfg.Bindings(nil) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second) + defer cancel() + start := time.Now() + var connectErr error + require.NotPanics(t, func() { + proxy, err := startMCP(ctx, cfg, bindings) + connectErr = err + if proxy != nil { + require.NoError(t, proxy.close()) + } + }, "remote catalogs must fail as errors, without terminating the harness") + require.Error(t, connectErr) + t.Logf("mode=%s pages=%d deletes=%d duration=%s error=%v", mode, pages.Load(), deletes.Load(), time.Since(start), connectErr) + require.Equal(t, int32(1), deletes.Load(), "failed discovery must terminate the established remote session") + if mode == "cursor-cycle" { + require.LessOrEqual(t, pages.Load(), int32(3), "a repeated cursor must fail before the timeout") + } + }) + } +} diff --git a/go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go b/go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go new file mode 100644 index 0000000000..e2c18b6ec3 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go @@ -0,0 +1,113 @@ +//go:build unix + +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "syscall" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +type auditLaunch struct { + PID int `json:"pid"` + Home string `json:"home"` +} + +func TestRunnerCleansUpAfterInvalidMCPToolSchema(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(405) + return + } + var request message + _ = json.NewDecoder(r.Body).Decode(&request) + if len(request.ID) == 0 { + w.WriteHeader(202) + return + } + w.Header().Set("Content-Type", "application/json") + result := json.RawMessage(`{"protocolVersion":"2025-11-25","capabilities":{"tools":{}},"serverInfo":{"name":"audit","version":"1"}}`) + if request.Method == "tools/list" { + result = json.RawMessage(`{"tools":[{"name":"broken","inputSchema":{"type":"array"}}]}`) + } + _ = json.NewEncoder(w).Encode(message{JSONRPC: "2.0", ID: request.ID, Result: result}) + })) + defer server.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"},"http_tools":[{"params":{"url":%q}}]}`, server.URL))) + require.NoError(t, err) + executable, err := os.Executable() + require.NoError(t, err) + dir := t.TempDir() + pidFile := filepath.Join(dir, "launch.json") + script := filepath.Join(dir, "dsh") + require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nexec '"+strings.ReplaceAll(executable, "'", "'\\''")+"' -test.run=TestMCPRunnerCleanupHelperProcess -- \"$@\"\n"), 0700)) + runner, err := New(cfg, script, filepath.Join(dir, "data"), append(os.Environ(), "DSH_AUDIT_LAUNCH="+pidFile)) + require.NoError(t, err) + var launch auditLaunch + t.Cleanup(func() { + if launch.PID > 0 { + _ = syscall.Kill(-launch.PID, syscall.SIGTERM) + deadline := time.Now().Add(time.Second) + for syscall.Kill(launch.PID, 0) == nil && time.Now().Before(deadline) { + time.Sleep(10 * time.Millisecond) + } + } + if strings.HasPrefix(launch.Home, filepath.Join(os.TempDir(), "kagent-dsh-")) { + _ = os.RemoveAll(launch.Home) + } + }) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) + defer cancel() + var runErr error + require.NotPanics(t, func() { + _, runErr = runner.Run(ctx, runtime.Turn{Prompt: "work"}, &recordingSink{}) + }) + require.Error(t, runErr, "malformed remote MCP schemas must return a startup error") + deadline := time.Now().Add(time.Second) + for { + data, err := os.ReadFile(pidFile) + if err == nil { + require.NoError(t, json.Unmarshal(data, &launch)) + break + } + if time.Now().After(deadline) { + t.Fatal("DSH test process did not record its PID") + } + time.Sleep(10 * time.Millisecond) + } + live := syscall.Kill(launch.PID, 0) == nil + t.Logf("DSH process PID=%d still running after MCP schema failure: %t", launch.PID, live) + require.False(t, live, "invalid remote tool schema must not leak the DSH subprocess") +} +func TestMCPRunnerCleanupHelperProcess(t *testing.T) { + path := os.Getenv("DSH_AUDIT_LAUNCH") + if path == "" { + return + } + home := "" + for i, arg := range os.Args { + if arg == "--patch" && i+1 < len(os.Args) { + home = filepath.Dir(os.Args[i+1]) + } + } + data, _ := json.Marshal(auditLaunch{PID: os.Getpid(), Home: home}) + if os.WriteFile(path, data, 0600) != nil { + os.Exit(2) + } + _, _ = io.Copy(io.Discard, os.Stdin) + os.Exit(0) +} From 0db86b5818af37c06064ef6ca1d175ee1ee78fe4 Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 15:52:01 +0800 Subject: [PATCH 04/12] docs: record DSH non-object tool argument limitation AI assistance: audit and documentation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index 992a711a97..d41977d141 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -38,6 +38,11 @@ ADK-specific context settings are not translated. DSH keeps its own built-in tools and plugin composition; those are not equivalent to kagent Agent Plugins. The first version accepts text input and output only. +Known limitation: a tool call whose ACP `rawInput` is a JSON array or scalar +aborts the turn because the shared runtime currently requires an argument object. +The malformed-JSON recovery test does not cover this case; preserving these values +through the tool-error recovery flow remains an acceptance gap. + ## State and process lifetime Each turn starts a DSH ACP process and creates or resumes the Actor's private From 3828ba280298a6cf657c05a2902c99526d26169f Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:06:34 +0800 Subject: [PATCH 05/12] fix: supervise DSH descendants and preserve non-object tool input Use a per-turn Linux subreaper and a lifetime pipe to clean up detached and orphaned tools before returning. Preserve non-object ACP input in JSON-compatible tool events so DSH can return validation errors to the model. Validate forced and normal teardown, adapter death, unrelated process survival, non-object arguments, and the existing runtime suite under the race detector. Runtime execution now requires Linux. AI assistance: implementation, regression tests, and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 36 ++-- go/harness/byo/dsh/cmd/main.go | 4 + .../internal/bridge/a2a_integration_test.go | 2 + go/harness/byo/dsh/internal/bridge/events.go | 15 +- .../byo/dsh/internal/bridge/events_test.go | 62 ++++++ .../dsh/internal/bridge/integration_test.go | 2 + .../byo/dsh/internal/bridge/main_test.go | 15 ++ .../bridge/mcp_runner_cleanup_test.go | 2 +- .../internal/bridge/process_cleanup_test.go | 185 ++++++++++++++++++ .../bridge/real_tools_integration_test.go | 17 +- go/harness/byo/dsh/internal/bridge/runner.go | 59 ++++-- .../byo/dsh/internal/bridge/runner_test.go | 32 +-- .../byo/dsh/internal/supervisor/command.go | 42 ++++ .../byo/dsh/internal/supervisor/run_linux.go | 158 +++++++++++++++ .../byo/dsh/internal/supervisor/run_other.go | 13 ++ 15 files changed, 575 insertions(+), 69 deletions(-) create mode 100644 go/harness/byo/dsh/internal/bridge/events_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/main_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/process_cleanup_test.go create mode 100644 go/harness/byo/dsh/internal/supervisor/command.go create mode 100644 go/harness/byo/dsh/internal/supervisor/run_linux.go create mode 100644 go/harness/byo/dsh/internal/supervisor/run_other.go diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index d41977d141..41efeaaf05 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -38,21 +38,31 @@ ADK-specific context settings are not translated. DSH keeps its own built-in tools and plugin composition; those are not equivalent to kagent Agent Plugins. The first version accepts text input and output only. -Known limitation: a tool call whose ACP `rawInput` is a JSON array or scalar -aborts the turn because the shared runtime currently requires an argument object. -The malformed-JSON recovery test does not cover this case; preserving these values -through the tool-error recovery flow remains an acceptance gap. +Non-object tool input is retained under `args.rawInput` in tool-call events. +DSH validates the original input and returns tool errors to the model, allowing +recovery from arrays, scalars, null and malformed argument strings. ## State and process lifetime Each turn starts a DSH ACP process and creates or resumes the Actor's private DSH session. A pending permission request retains that process until the decision arrives. Completion closes the session and stdin so DSH can flush its -state; cancellation is followed by bounded process-group cleanup. - -Cancellation interrupts blocked ACP writes by closing stdin. Forced process-group -cleanup does not yet prove that DSH tools in separate process groups have exited; -this remains a lifecycle acceptance gap before release. +state. A dedicated Linux child subreaper owns each process tree, including +orphaned tools and tools that create a separate session or process group. + +Cancellation interrupts blocked ACP writes by closing stdin. After five seconds +of graceful shutdown, the adapter closes a private lifetime pipe to request forced +cleanup. Adapter death also closes that pipe. The supervisor kills DSH, terminates +adopted descendants and waits until the kernel reports no remaining children. +The Actor's turn is not released before that completes; uninterruptible kernel +I/O or cleanup failures can delay completion. The adapter never kills the +supervisor to impose a deadline that would leave tools behind. + +Process supervision requires Linux with readable procfs child lists and permission +to set `PR_SET_CHILD_SUBREAPER`. It runs as the image's unprivileged user without +additional Linux capabilities. Unsupported hosts fail validation; run runtime +tests in Linux rather than launching this adapter natively on macOS. This manages +process lifetime; sandbox and container isolation remain platform responsibilities. `/data/adapter/state.json` binds the Actor to one native session. DSH session logs and storage live under `/data/dsh`, and the workspace is `/data/workspace`. @@ -105,14 +115,16 @@ The server must use Streamable HTTP and the platform trust bundle. ## Verification -From `go/`: +From `go/` in a Linux development environment: ```sh go test -race ./harness/byo/dsh/... ./harness/runtime/... ``` -The subprocess tests exercise permission decisions, cancellation, identity -validation, malformed protocol handling and cleanup without a model API. +The Linux subprocess tests exercise permission decisions, cancellation, identity +validation, malformed protocol handling, detached and orphaned tool cleanup, +unrelated-process survival, and adapter death without a model API. Configuration, +event conversion and wire tests also run on non-Linux hosts. For the published runtime tests, install the locked npm dependencies and run: ```sh diff --git a/go/harness/byo/dsh/cmd/main.go b/go/harness/byo/dsh/cmd/main.go index 1296887143..b470c2efbf 100644 --- a/go/harness/byo/dsh/cmd/main.go +++ b/go/harness/byo/dsh/cmd/main.go @@ -15,6 +15,7 @@ import ( "github.com/kagent-dev/kagent/go/adk/pkg/app" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/bridge" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/supervisor" runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" "github.com/kagent-dev/kagent/go/harness/runtime/continuation" "github.com/kagent-dev/kagent/go/pkg/logging" @@ -22,6 +23,9 @@ import ( ) func main() { + if len(os.Args) > 1 && os.Args[1] == supervisor.Mode { + os.Exit(supervisor.Run(os.Args[2:])) + } executable := flag.String("dsh-bin", "dsh", "DSH executable (must match the pinned version)") dataDir := flag.String("data-dir", "/data", "absolute durable data directory") port := flag.String("port", "80", "private A2A gRPC port") diff --git a/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go index 8cd95faac2..554e774bf5 100644 --- a/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go +++ b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go @@ -1,3 +1,5 @@ +//go:build linux + package bridge import ( diff --git a/go/harness/byo/dsh/internal/bridge/events.go b/go/harness/byo/dsh/internal/bridge/events.go index 3c3f9c1cba..790980703d 100644 --- a/go/harness/byo/dsh/internal/bridge/events.go +++ b/go/harness/byo/dsh/internal/bridge/events.go @@ -76,9 +76,18 @@ func (e *events) apply(data json.RawMessage, sink runtime.EventSink) error { return fmt.Errorf("ACP tool call identity was reused") } args := make(map[string]any) - if len(u.RawInput) != 0 && string(u.RawInput) != "null" { - if err := json.Unmarshal(u.RawInput, &args); err != nil { - return fmt.Errorf("ACP tool arguments must be an object") + if len(u.RawInput) != 0 { + var input any + if err := json.Unmarshal(u.RawInput, &input); err != nil { + return fmt.Errorf("failed to decode ACP tool input: %w", err) + } + var object bool + args, object = input.(map[string]any) + if !object { + // This is an observation, not a request to execute a tool. DSH + // validates the original input and returns its error to the model. + // Use JSON-compatible values for A2A's protobuf conversion. + args = map[string]any{"rawInput": input} } } e.tools[u.ToolCallID] = tool{name: u.Title, args: args} diff --git a/go/harness/byo/dsh/internal/bridge/events_test.go b/go/harness/byo/dsh/internal/bridge/events_test.go new file mode 100644 index 0000000000..c9c79285ef --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/events_test.go @@ -0,0 +1,62 @@ +package bridge + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/structpb" + + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +type recordingSink struct { + id string + texts []string + calls []runtime.ToolCall + results []runtime.ToolResult + callReady chan struct{} +} + +func (s *recordingSink) SessionStarted(v runtime.SessionStarted) error { + s.id = v.ContinuationID + return nil +} +func (s *recordingSink) TextDelta(v runtime.TextDelta) error { + s.texts = append(s.texts, v.Text) + return nil +} +func (s *recordingSink) ToolCall(v runtime.ToolCall) error { + s.calls = append(s.calls, v) + if s.callReady != nil { + close(s.callReady) + s.callReady = nil + } + return nil +} +func (s *recordingSink) ToolResult(v runtime.ToolResult) error { + s.results = append(s.results, v) + return nil +} +func (s *recordingSink) ModelCall(runtime.ModelCall) {} + +func TestToolArgumentsPreserveNonObjectInput(t *testing.T) { + for _, raw := range []string{`[]`, `42`, `true`, `null`, `"invalid"`, `"{bad json"`} { + t.Run(raw, func(t *testing.T) { + e := events{sessionID: "session", tools: make(map[string]tool)} + sink := &recordingSink{} + input := json.RawMessage(`{"sessionId":"session","update":{"sessionUpdate":"tool_call","toolCallId":"call","title":"bash","rawInput":` + raw + `}}`) + require.NoError(t, e.apply(input, sink)) + encoded, err := json.Marshal(sink.calls[0].Arguments) + require.NoError(t, err) + require.JSONEq(t, `{"rawInput":`+raw+`}`, string(encoded)) + // A2A gRPC converts data parts with structpb; JSON marshaling alone + // would also accept Go values that the transport cannot represent. + _, err = structpb.NewStruct(sink.calls[0].Arguments) + require.NoError(t, err) + require.NoError(t, e.apply(json.RawMessage(`{"sessionId":"session","update":{"sessionUpdate":"tool_call_update","toolCallId":"call","status":"failed","content":[{"type":"content","content":{"type":"text","text":"invalid tool input"}}]}}`), sink)) + require.True(t, sink.results[0].IsError) + require.Equal(t, "invalid tool input", sink.results[0].Result) + }) + } +} diff --git a/go/harness/byo/dsh/internal/bridge/integration_test.go b/go/harness/byo/dsh/internal/bridge/integration_test.go index 20af5f4244..7f087d8468 100644 --- a/go/harness/byo/dsh/internal/bridge/integration_test.go +++ b/go/harness/byo/dsh/internal/bridge/integration_test.go @@ -1,3 +1,5 @@ +//go:build linux + package bridge import ( diff --git a/go/harness/byo/dsh/internal/bridge/main_test.go b/go/harness/byo/dsh/internal/bridge/main_test.go new file mode 100644 index 0000000000..f17260e63a --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/main_test.go @@ -0,0 +1,15 @@ +package bridge + +import ( + "os" + "testing" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/supervisor" +) + +func TestMain(m *testing.M) { + if len(os.Args) > 1 && os.Args[1] == supervisor.Mode { + os.Exit(supervisor.Run(os.Args[2:])) + } + os.Exit(m.Run()) +} diff --git a/go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go b/go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go index e2c18b6ec3..b5e06ecdb1 100644 --- a/go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go +++ b/go/harness/byo/dsh/internal/bridge/mcp_runner_cleanup_test.go @@ -1,4 +1,4 @@ -//go:build unix +//go:build linux package bridge diff --git a/go/harness/byo/dsh/internal/bridge/process_cleanup_test.go b/go/harness/byo/dsh/internal/bridge/process_cleanup_test.go new file mode 100644 index 0000000000..5c164cec68 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/process_cleanup_test.go @@ -0,0 +1,185 @@ +//go:build linux + +package bridge + +import ( + "bufio" + "context" + "encoding/json" + "fmt" + "os" + "os/exec" + "os/signal" + "strconv" + "strings" + "syscall" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +func TestStopReapsDetachedTool(t *testing.T) { + for _, mode := range []string{"forced", "normal", "orphan"} { + t.Run(mode, func(t *testing.T) { testDetachedCleanup(t, mode) }) + } +} + +func testDetachedCleanup(t *testing.T, mode string) { + t.Helper() + sentinel := exec.Command("/bin/sleep", "60") + require.NoError(t, sentinel.Start()) + t.Cleanup(func() { _ = sentinel.Process.Kill(); _ = sentinel.Wait() }) + executable, err := os.Executable() + require.NoError(t, err) + dir := t.TempDir() + script := dir + "/dsh" + pidFile := dir + "/tool.pid" + require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nexec '"+strings.ReplaceAll(executable, "'", "'\\''")+"' -test.run=TestDetachedDSHProcess\n"), 0700)) + cfg, err := config.Parse([]byte(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"}}`)) + require.NoError(t, err) + runner, err := New(cfg, script, t.TempDir(), append(os.Environ(), "DSH_AUDIT_DETACHED="+pidFile, "DSH_AUDIT_EXIT="+mode)) + require.NoError(t, err) + defer func() { + if data, err := os.ReadFile(pidFile); err == nil { + pid, _ := strconv.Atoi(string(data)) + _ = syscall.Kill(-pid, syscall.SIGKILL) + } + }() + ctx, cancel := context.WithTimeout(t.Context(), 20*time.Second) + defer cancel() + _, err = runner.Run(ctx, runtime.Turn{Prompt: "work"}, &recordingSink{}) + if mode == "forced" { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.NoError(t, syscall.Kill(sentinel.Process.Pid, 0), "cleanup must not affect unrelated processes") + data, err := os.ReadFile(pidFile) + require.NoError(t, err) + pid, err := strconv.Atoi(string(data)) + require.NoError(t, err) + live := syscall.Kill(pid, 0) == nil + t.Logf("separate process group tool PID=%d still alive after DSH cleanup: %t", pid, live) + require.False(t, live, "forced cleanup must not release the Actor with a running tool process") +} +func TestDetachedDSHProcess(t *testing.T) { + pidFile := os.Getenv("DSH_AUDIT_DETACHED") + if pidFile == "" { + return + } + if os.WriteFile(pidFile+".dsh", []byte(strconv.Itoa(os.Getpid())), 0600) != nil { + os.Exit(2) + } + signal.Ignore(syscall.SIGTERM) + if os.Getenv("DSH_AUDIT_EXIT") == "orphan" { + executable, err := os.Executable() + if err != nil { + os.Exit(2) + } + child := exec.Command(executable, "-test.run=TestDetachedOrphanProcess") + if child.Run() != nil { + os.Exit(2) + } + } else { + child := exec.Command("/bin/sleep", "60") + child.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := child.Start(); err != nil { + os.Exit(2) + } + if err := os.WriteFile(pidFile, []byte(strconv.Itoa(child.Process.Pid)), 0600); err != nil { + os.Exit(2) + } + } + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + var m message + if json.Unmarshal(scanner.Bytes(), &m) != nil { + os.Exit(2) + } + switch m.Method { + case "initialize": + fmt.Println(`{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":1,"agentCapabilities":{}}}`) + case "session/new": + fmt.Println(`{"jsonrpc":"2.0","id":2,"result":{"sessionId":"audit-detached"}}`) + case "session/prompt": + fmt.Println(`{"jsonrpc":"2.0","id":3,"result":{"stopReason":"end_turn"}}`) + case "session/close": + fmt.Println(`{"jsonrpc":"2.0","id":4,"result":{}}`) + } + } + if os.Getenv("DSH_AUDIT_EXIT") != "forced" { + os.Exit(0) + } + for { + time.Sleep(time.Second) + } +} + +func TestDetachedOrphanProcess(t *testing.T) { + path := os.Getenv("DSH_AUDIT_DETACHED") + if path == "" { + return + } + child := exec.Command("/bin/sleep", "60") + child.SysProcAttr = &syscall.SysProcAttr{Setsid: true} + if child.Start() != nil { + os.Exit(2) + } + if os.WriteFile(path, []byte(strconv.Itoa(child.Process.Pid)), 0600) != nil { + os.Exit(2) + } + os.Exit(0) +} + +func TestAdapterDeathReapsDetachedTools(t *testing.T) { + executable, err := os.Executable() + require.NoError(t, err) + pidFile := t.TempDir() + "/tool.pid" + owner := exec.Command(executable, "-test.run=TestDSHLifetimeOwner") + owner.Env = append(os.Environ(), "DSH_AUDIT_OWNER="+pidFile) + require.NoError(t, owner.Start()) + t.Cleanup(func() { _ = owner.Process.Kill(); _ = owner.Wait() }) + var toolPID, dshPID int + require.Eventually(t, func() bool { + toolData, err := os.ReadFile(pidFile) + if err != nil { + return false + } + dshData, err := os.ReadFile(pidFile + ".dsh") + if err != nil { + return false + } + toolPID, err = strconv.Atoi(string(toolData)) + if err != nil { + return false + } + dshPID, err = strconv.Atoi(string(dshData)) + return err == nil + }, 5*time.Second, 10*time.Millisecond) + require.NoError(t, owner.Process.Kill()) + require.Error(t, owner.Wait()) + require.Eventually(t, func() bool { + return syscall.Kill(toolPID, 0) == syscall.ESRCH && syscall.Kill(dshPID, 0) == syscall.ESRCH + }, 5*time.Second, 10*time.Millisecond, "supervisor must reap DSH and its detached tool after adapter death") +} + +func TestDSHLifetimeOwner(t *testing.T) { + pidFile := os.Getenv("DSH_AUDIT_OWNER") + if pidFile == "" { + return + } + executable, err := os.Executable() + require.NoError(t, err) + script := t.TempDir() + "/dsh" + require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nexec '"+strings.ReplaceAll(executable, "'", "'\\''")+"' -test.run=TestDetachedDSHProcess\n"), 0700)) + cfg, err := config.Parse([]byte(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"}}`)) + require.NoError(t, err) + runner, err := New(cfg, script, t.TempDir(), append(os.Environ(), "DSH_AUDIT_DETACHED="+pidFile, "DSH_AUDIT_EXIT=forced")) + require.NoError(t, err) + _, _ = runner.Run(t.Context(), runtime.Turn{Prompt: "work"}, &recordingSink{}) + os.Exit(3) +} diff --git a/go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go b/go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go index e0dbb13176..b32a049e69 100644 --- a/go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go +++ b/go/harness/byo/dsh/internal/bridge/real_tools_integration_test.go @@ -1,3 +1,5 @@ +//go:build linux + package bridge import ( @@ -25,7 +27,7 @@ func TestRealDSHBuiltinToolsAndPermissions(t *testing.T) { if executable == "" { t.Skip("DSH_TEST_BIN required") } - for _, scenario := range []string{"bash", "approval-allow", "approval-reject", "approval-cancel", "malformed-arguments"} { + for _, scenario := range []string{"bash", "approval-allow", "approval-reject", "approval-cancel", "malformed-arguments", "array-arguments", "scalar-arguments", "null-arguments", "string-arguments"} { t.Run(scenario, func(t *testing.T) { var requests atomic.Int32 model := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -56,8 +58,17 @@ func TestRealDSHBuiltinToolsAndPermissions(t *testing.T) { if strings.HasPrefix(scenario, "approval-") { args = `{"command":"printf audit-ok","description":"Print a harmless acceptance test marker","sandbox_permissions":"danger-full-access","justification":"Exercise approval with a harmless marker."}` } - if scenario == "malformed-arguments" { + switch scenario { + case "malformed-arguments": args = `{"command":` + case "array-arguments": + args = `[]` + case "scalar-arguments": + args = `42` + case "null-arguments": + args = `null` + case "string-arguments": + args = `"invalid"` } writeCompletion(w, map[string]any{"role": "assistant", "tool_calls": []any{map[string]any{"index": 0, "id": "audit-call", "type": "function", "function": map[string]string{"name": name, "arguments": args}}}}, "tool_calls") } else { @@ -98,7 +109,7 @@ func TestRealDSHBuiltinToolsAndPermissions(t *testing.T) { require.Nil(t, out.Failure) require.Nil(t, out.Pending) require.Len(t, sink.results, 1) - require.Equal(t, scenario == "approval-reject" || scenario == "malformed-arguments", sink.results[0].IsError) + require.Equal(t, scenario == "approval-reject" || strings.HasSuffix(scenario, "-arguments"), sink.results[0].IsError) if scenario == "approval-reject" { require.Equal(t, runtime.ToolDeclined, sink.results[0].Status) } diff --git a/go/harness/byo/dsh/internal/bridge/runner.go b/go/harness/byo/dsh/internal/bridge/runner.go index bf6810c4c2..02c3912d7f 100644 --- a/go/harness/byo/dsh/internal/bridge/runner.go +++ b/go/harness/byo/dsh/internal/bridge/runner.go @@ -2,18 +2,19 @@ package bridge import ( + "bytes" "context" "encoding/json" "errors" "fmt" "io" "os" - "os/exec" "path/filepath" "strings" "time" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/supervisor" "github.com/kagent-dev/kagent/go/harness/internal/utils" "github.com/kagent-dev/kagent/go/harness/runtime" runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" @@ -53,21 +54,38 @@ func New(cfg *config.Config, executable, dataDir string, environment []string) ( } func (r *Runner) Validate(ctx context.Context) error { - command := exec.CommandContext(ctx, r.executable, "--version") + command, err := supervisor.Command(r.executable, "--version") + if err != nil { + return err + } command.Env = r.environment - output, err := command.Output() + var output bytes.Buffer + command.Stdout = &output + control, err := supervisor.Start(command) + if err != nil { + return fmt.Errorf("failed to start DSH version check: %w", err) + } + defer control.Close() + done := make(chan error, 1) + go func() { done <- command.Wait() }() + select { + case err = <-done: + case <-ctx.Done(): + _ = control.Close() + err = errors.Join(ctx.Err(), <-done) + } if err != nil { return fmt.Errorf("failed to check DSH version: %w", err) } - if strings.TrimSpace(string(output)) != config.Version { + if strings.TrimSpace(output.String()) != config.Version { return fmt.Errorf("DSH BYO requires version %s", config.Version) } return nil } type process struct { - command *exec.Cmd stdin io.WriteCloser + control io.Closer wire *wire done chan struct{} waitErr error @@ -89,7 +107,10 @@ func (r *Runner) start(ctx context.Context) (*process, error) { if err := utils.ReplacePrivateFile(path, patch); err != nil { return nil, errors.Join(err, os.RemoveAll(home)) } - cmd := exec.Command(r.executable, "--profile", "acp", "--patch", path) + cmd, err := supervisor.Command(r.executable, "--profile", "acp", "--patch", path) + if err != nil { + return nil, errors.Join(err, os.RemoveAll(home)) + } cmd.Dir, cmd.Env, cmd.Stderr = r.workspace, config.Environment(r.environment, home), io.Discard utils.ConfigureProcessGroup(cmd) stdin, err := cmd.StdinPipe() @@ -100,10 +121,11 @@ func (r *Runner) start(ctx context.Context) (*process, error) { if err != nil { return nil, errors.Join(fmt.Errorf("failed to open DSH stdout: %w", err), stdin.Close(), os.RemoveAll(home)) } - if err := cmd.Start(); err != nil { + control, err := supervisor.Start(cmd) + if err != nil { return nil, errors.Join(fmt.Errorf("failed to start DSH: %w", err), stdin.Close(), stdout.Close(), os.RemoveAll(home)) } - p := &process{command: cmd, stdin: stdin, wire: newWire(stdin, stdout), done: make(chan struct{}), home: home, events: events{tools: make(map[string]tool)}} + p := &process{stdin: stdin, control: control, wire: newWire(stdin, stdout), done: make(chan struct{}), home: home, events: events{tools: make(map[string]tool)}} go func() { p.waitErr = cmd.Wait(); close(p.done) }() proxy, err := startMCP(ctx, r.config, r.servers) if err != nil { @@ -334,7 +356,8 @@ func (p *process) cancel() error { } } -// EOF lets DSH flush persistence; escalation is bounded and reaps the process group. +// EOF lets DSH flush persistence. After the grace period, the supervisor kills +// DSH and reaps all descendants, including tools in separate process groups. func (p *process) stop() error { close(p.wire.done) err := p.stdin.Close() @@ -344,17 +367,13 @@ func (p *process) stop() error { select { case <-p.done: case <-time.After(stopTimeout): - if signalErr := utils.TerminateProcessGroup(p.command.Process); signalErr != nil && !errors.Is(signalErr, os.ErrProcessDone) { - err = errors.Join(err, signalErr) - } - select { - case <-p.done: - case <-time.After(stopTimeout): - if signalErr := utils.KillProcessGroup(p.command.Process); signalErr != nil && !errors.Is(signalErr, os.ErrProcessDone) { - err = errors.Join(err, signalErr) - } - <-p.done - } + // Never kill the supervisor to impose a deadline: doing so would orphan + // the very descendants whose exit must precede releasing the Actor. + err = errors.Join(err, p.control.Close()) + <-p.done + } + if closeErr := p.control.Close(); closeErr != nil && !errors.Is(closeErr, os.ErrClosed) { + err = errors.Join(err, closeErr) } <-p.wire.readDone if p.mcp != nil { diff --git a/go/harness/byo/dsh/internal/bridge/runner_test.go b/go/harness/byo/dsh/internal/bridge/runner_test.go index 4a315d6139..4b5d84d8f0 100644 --- a/go/harness/byo/dsh/internal/bridge/runner_test.go +++ b/go/harness/byo/dsh/internal/bridge/runner_test.go @@ -1,3 +1,5 @@ +//go:build linux + package bridge import ( @@ -18,36 +20,6 @@ import ( "github.com/kagent-dev/kagent/go/harness/runtime" ) -type recordingSink struct { - id string - texts []string - calls []runtime.ToolCall - results []runtime.ToolResult - callReady chan struct{} -} - -func (s *recordingSink) SessionStarted(v runtime.SessionStarted) error { - s.id = v.ContinuationID - return nil -} -func (s *recordingSink) TextDelta(v runtime.TextDelta) error { - s.texts = append(s.texts, v.Text) - return nil -} -func (s *recordingSink) ToolCall(v runtime.ToolCall) error { - s.calls = append(s.calls, v) - if s.callReady != nil { - close(s.callReady) - s.callReady = nil - } - return nil -} -func (s *recordingSink) ToolResult(v runtime.ToolResult) error { - s.results = append(s.results, v) - return nil -} -func (s *recordingSink) ModelCall(runtime.ModelCall) {} - func testRunner(t *testing.T, mode string) *Runner { t.Helper() c, err := config.Parse([]byte(`{"model":{"type":"openai","model":"mock","base_url":"http://localhost:1234/v1"},"instruction":"system","runtime":{"control_plane_url":"http://controller:8083"}}`)) diff --git a/go/harness/byo/dsh/internal/supervisor/command.go b/go/harness/byo/dsh/internal/supervisor/command.go new file mode 100644 index 0000000000..22318aa09a --- /dev/null +++ b/go/harness/byo/dsh/internal/supervisor/command.go @@ -0,0 +1,42 @@ +// Package supervisor owns one DSH process tree, including detached tools. +package supervisor + +import ( + "fmt" + "io" + "os" + "os/exec" + "runtime" +) + +// Mode is a private re-exec entry point, handled before application startup. +const Mode = "--dsh-supervise" + +// Command re-executes this binary as a dedicated supervisor for one DSH turn. +func Command(executable string, args ...string) (*exec.Cmd, error) { + if runtime.GOOS != "linux" { + return nil, fmt.Errorf("DSH BYO process supervision requires Linux") + } + self, err := os.Executable() + if err != nil { + return nil, fmt.Errorf("failed to locate DSH supervisor executable: %w", err) + } + return exec.Command(self, append([]string{Mode, executable}, args...)...), nil +} + +// Start gives the supervisor a private lifetime pipe. Closing it requests forced +// cleanup; adapter death also closes it. DSH and its tools never inherit it. +func Start(cmd *exec.Cmd) (io.Closer, error) { + reader, writer, err := os.Pipe() + if err != nil { + return nil, fmt.Errorf("failed to create DSH lifetime pipe: %w", err) + } + cmd.ExtraFiles = []*os.File{reader} + err = cmd.Start() + _ = reader.Close() + if err != nil { + _ = writer.Close() + return nil, err + } + return writer, nil +} diff --git a/go/harness/byo/dsh/internal/supervisor/run_linux.go b/go/harness/byo/dsh/internal/supervisor/run_linux.go new file mode 100644 index 0000000000..b2afdcfa3a --- /dev/null +++ b/go/harness/byo/dsh/internal/supervisor/run_linux.go @@ -0,0 +1,158 @@ +//go:build linux + +package supervisor + +import ( + "errors" + "fmt" + "log/slog" + "os" + "os/exec" + "os/signal" + "path/filepath" + "strconv" + "strings" + "syscall" + "time" + + "golang.org/x/sys/unix" +) + +// Run must execute in a dedicated process: subreaper status and wait4 belong +// to that process, never to the long-lived A2A server. It returns only after +// the main child and all adopted descendants have been reaped. +func Run(args []string) int { + if err := run(args); err != nil { + fmt.Fprintln(os.Stderr, err) + return 1 + } + return 0 +} + +func run(args []string) error { + if len(args) == 0 { + return fmt.Errorf("DSH supervisor requires an executable") + } + control := os.NewFile(3, "dsh-lifetime") + if control == nil { + return fmt.Errorf("DSH supervisor requires a lifetime pipe") + } + defer control.Close() + info, err := control.Stat() + if err != nil || info.Mode()&os.ModeNamedPipe == 0 { + return fmt.Errorf("DSH supervisor requires a lifetime pipe") + } + unix.CloseOnExec(3) + if err := unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); err != nil { + return fmt.Errorf("failed to enable DSH child supervision: %w", err) + } + // Check procfs before starting any payload; there is no unsupervised fallback. + if _, err := childPIDs(); err != nil { + return err + } + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) + defer signal.Stop(signals) + parentGone := make(chan struct{}) + go func() { var b [1]byte; _, _ = control.Read(b[:]); close(parentGone) }() + cmd := exec.Command(args[0], args[1:]...) + cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to launch DSH payload: %w", err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + var waitErr error + select { + case waitErr = <-done: + case <-parentGone: + waitErr = killAndWait(cmd, done) + case <-signals: + waitErr = killAndWait(cmd, done) + } + // The main child is already reaped. No other goroutine may wait on children + // while cleanup enumerates and signals them, preventing PID-reuse races. + return errors.Join(waitErr, reapDescendants()) +} + +func killAndWait(cmd *exec.Cmd, done <-chan error) error { + err := cmd.Process.Kill() + if errors.Is(err, os.ErrProcessDone) { + err = nil + } + return errors.Join(err, <-done) +} + +func reapDescendants() error { + var firstErr error + for { + empty, err := reapPass() + if err != nil && firstErr == nil { + firstErr = err + slog.New(slog.NewJSONHandler(os.Stderr, nil)).Error("failed to clean up dsh descendants", "error", err) + } + if empty { + return firstErr + } + // Never release the Actor on a cleanup failure. Retry until wait4 proves + // there are no children; kernel-level uninterruptible tasks can delay this. + time.Sleep(10 * time.Millisecond) + } +} + +func reapPass() (bool, error) { + for { + var status syscall.WaitStatus + pid, err := syscall.Wait4(-1, &status, syscall.WNOHANG, nil) + if errors.Is(err, syscall.ECHILD) { + return true, nil + } + if errors.Is(err, syscall.EINTR) { + continue + } + if err != nil { + return false, fmt.Errorf("failed to reap DSH descendant: %w", err) + } + if pid > 0 { + continue + } + children, err := childPIDs() + if err != nil { + return false, err + } + for _, child := range children { + if err := syscall.Kill(child, syscall.SIGKILL); err != nil && !errors.Is(err, syscall.ESRCH) { + return false, fmt.Errorf("failed to stop DSH descendant: %w", err) + } + } + // Children can exit or reparent their children during enumeration. An empty + // procfs snapshot is never proof of completion: only wait4 ECHILD is. + return false, nil + } +} + +func childPIDs() ([]int, error) { + paths, err := filepath.Glob("/proc/self/task/*/children") + if err != nil || len(paths) == 0 { + return nil, fmt.Errorf("DSH supervision requires procfs child lists") + } + var children []int + for _, path := range paths { + data, err := os.ReadFile(path) + if os.IsNotExist(err) { + continue + } // A Go runtime thread may have exited. + if err != nil { + return nil, fmt.Errorf("failed to read DSH child list: %w", err) + } + for value := range strings.FieldsSeq(string(data)) { + pid, err := strconv.Atoi(value) + if err != nil || pid <= 0 { + return nil, fmt.Errorf("invalid PID in DSH child list") + } + children = append(children, pid) + } + } + return children, nil +} diff --git a/go/harness/byo/dsh/internal/supervisor/run_other.go b/go/harness/byo/dsh/internal/supervisor/run_other.go new file mode 100644 index 0000000000..80b3a40bd1 --- /dev/null +++ b/go/harness/byo/dsh/internal/supervisor/run_other.go @@ -0,0 +1,13 @@ +//go:build !linux + +package supervisor + +import ( + "fmt" + "os" +) + +func Run([]string) int { + fmt.Fprintln(os.Stderr, "DSH BYO process supervision requires Linux") + return 1 +} From dcd35e4adb0371a4dd85b2afc8bb24b4839244c2 Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:42:12 +0800 Subject: [PATCH 06/12] fix: contain MCP redirects and recover from DSH supervisor failure Pin MCP requests and binding headers to the configured origin. Preserve same-origin redirects with a bounded chain and reject cross-origin hops. Use nested Linux subreapers and private cleanup confirmation to recover when either supervisor dies during payload execution. Avoid inherited stderr copy hangs. Keep the task unsettled if cleanup cannot be confirmed. Verify redirect isolation, forced supervisor death, detached tool cleanup, unrelated process survival, and missing confirmation. Run host runtime race tests, the Linux DSH race suite, Go and Linux lint, and container checks. AI assistance: implementation, regression tests, and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 23 ++- go/harness/byo/dsh/internal/bridge/mcp.go | 42 ++++- .../dsh/internal/bridge/mcp_redirect_test.go | 123 +++++++++++++++ go/harness/byo/dsh/internal/bridge/runner.go | 12 +- .../bridge/supervisor_failure_test.go | 146 ++++++++++++++++++ .../byo/dsh/internal/supervisor/command.go | 67 +++++++- .../byo/dsh/internal/supervisor/run_linux.go | 63 ++++++-- 7 files changed, 446 insertions(+), 30 deletions(-) create mode 100644 go/harness/byo/dsh/internal/bridge/mcp_redirect_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/supervisor_failure_test.go diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index 41efeaaf05..f0df220003 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -47,16 +47,22 @@ recovery from arrays, scalars, null and malformed argument strings. Each turn starts a DSH ACP process and creates or resumes the Actor's private DSH session. A pending permission request retains that process until the decision arrives. Completion closes the session and stdin so DSH can flush its -state. A dedicated Linux child subreaper owns each process tree, including +state. Two nested Linux child subreapers own each process tree, including orphaned tools and tools that create a separate session or process group. Cancellation interrupts blocked ACP writes by closing stdin. After five seconds of graceful shutdown, the adapter closes a private lifetime pipe to request forced -cleanup. Adapter death also closes that pipe. The supervisor kills DSH, terminates -adopted descendants and waits until the kernel reports no remaining children. -The Actor's turn is not released before that completes; uninterruptible kernel -I/O or cleanup failures can delay completion. The adapter never kills the -supervisor to impose a deadline that would leave tools behind. +cleanup. Adapter death also closes that pipe. If the inner supervisor dies, the +outer guard adopts and reaps its descendants. If the guard dies, its lifetime +pipe closes and the inner supervisor kills DSH and reaps its descendants. +The adapter waits for an explicit cleanup confirmation before releasing the turn; +process exit or closed output pipes alone are insufficient. + +During payload execution, this tolerates the loss of either supervisor. If neither +can confirm cleanup, for example after losing both, replacing the Actor is +required: the adapter logs the failure and leaves the task unsettled. +Uninterruptible kernel I/O can also delay cleanup. This is +not a guarantee against simultaneous process kills or malicious same-UID tools. Process supervision requires Linux with readable procfs child lists and permission to set `PR_SET_CHILD_SUBREAPER`. It runs as the image's unprivileged user without @@ -64,6 +70,11 @@ additional Linux capabilities. Unsupported hosts fail validation; run runtime tests in Linux rather than launching this adapter natively on macOS. This manages process lifetime; sandbox and container isolation remain platform responsibilities. +MCP HTTP redirects must retain the configured scheme, hostname and effective +port. Same-origin path redirects are supported, with a ten-redirect limit per +request. Cross-origin redirects, including HTTPS-to-HTTP redirects, are rejected +before sending a request or injecting binding headers. + `/data/adapter/state.json` binds the Actor to one native session. DSH session logs and storage live under `/data/dsh`, and the workspace is `/data/workspace`. The CLI profile and compiled overlay use a disposable home outside `/data`. diff --git a/go/harness/byo/dsh/internal/bridge/mcp.go b/go/harness/byo/dsh/internal/bridge/mcp.go index f81c9b5431..909457ea5b 100644 --- a/go/harness/byo/dsh/internal/bridge/mcp.go +++ b/go/harness/byo/dsh/internal/bridge/mcp.go @@ -7,6 +7,7 @@ import ( "io" "net" "net/http" + "net/url" "strings" "time" @@ -39,6 +40,10 @@ func startMCP(ctx context.Context, cfg *config.Config, bindings []config.MCPServ }() mux := http.NewServeMux() for i, binding := range bindings { + origin, err := url.Parse(binding.URL) + if err != nil { + return nil, fmt.Errorf("failed to parse MCP binding %d: %w", i, err) + } params := cfg.Agent.HttpTools[i].Params timeout := 30 * time.Second if params.Timeout != nil { @@ -47,7 +52,19 @@ func startMCP(ctx context.Context, cfg *config.Config, bindings []config.MCPServ terminate := params.TerminateOnClose == nil || *params.TerminateOnClose transport := http.DefaultTransport.(*http.Transport).Clone() p.transports = append(p.transports, transport) - httpClient := &http.Client{Timeout: timeout, Transport: headerTransport{base: transport, headers: binding.Headers, terminate: terminate}} + httpClient := &http.Client{ + Timeout: timeout, + Transport: headerTransport{base: transport, headers: binding.Headers, terminate: terminate, origin: origin}, + CheckRedirect: func(request *http.Request, via []*http.Request) error { + if !sameOrigin(origin, request.URL) { + return fmt.Errorf("MCP redirects must stay within the binding origin") + } + if len(via) >= 10 { + return fmt.Errorf("MCP stopped after 10 redirects") + } + return nil + }, + } connectCtx, connectCancel := context.WithTimeout(ctx, timeout) // AddTool can panic on an invalid remote schema; release the discovery // deadline even when the startup recovery above handles that panic. @@ -126,6 +143,7 @@ func (p *mcpProxy) close() error { type headerTransport struct { base http.RoundTripper + origin *url.URL headers []config.Header terminate bool } @@ -133,6 +151,11 @@ type headerTransport struct { var _ http.RoundTripper = headerTransport{} func (t headerTransport) RoundTrip(request *http.Request) (*http.Response, error) { + // Guard injection as well as redirects: SDK-generated requests must use the + // configured origin before receiving any binding headers. + if !sameOrigin(t.origin, request.URL) { + return nil, fmt.Errorf("MCP request must stay within the binding origin") + } if request.Method == http.MethodDelete && !t.terminate { return &http.Response{StatusCode: http.StatusOK, Header: make(http.Header), Body: io.NopCloser(strings.NewReader("")), Request: request}, nil } @@ -142,3 +165,20 @@ func (t headerTransport) RoundTrip(request *http.Request) (*http.Response, error } return t.base.RoundTrip(request) } + +func sameOrigin(a, b *url.URL) bool { + if a == nil || b == nil || !strings.EqualFold(a.Scheme, b.Scheme) || !strings.EqualFold(a.Hostname(), b.Hostname()) { + return false + } + return originPort(a) == originPort(b) +} + +func originPort(u *url.URL) string { + if port := u.Port(); port != "" { + return port + } + if strings.EqualFold(u.Scheme, "https") { + return "443" + } + return "80" +} diff --git a/go/harness/byo/dsh/internal/bridge/mcp_redirect_test.go b/go/harness/byo/dsh/internal/bridge/mcp_redirect_test.go new file mode 100644 index 0000000000..22e689d52a --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/mcp_redirect_test.go @@ -0,0 +1,123 @@ +package bridge + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "sync/atomic" + "testing" + + "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" +) + +func TestMCPRejectsCrossOriginRedirect(t *testing.T) { + for _, host := range []string{"127.0.0.1", "localhost"} { + t.Run(host, func(t *testing.T) { + var calls atomic.Int32 + destination := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + calls.Add(1) + w.WriteHeader(http.StatusBadGateway) + })) + defer destination.Close() + target := strings.Replace(destination.URL, "127.0.0.1", host, 1) + source := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "Bearer test-marker" { + http.Error(w, "missing header", http.StatusUnauthorized) + return + } + http.Redirect(w, r, target, http.StatusTemporaryRedirect) + })) + defer source.Close() + cfg := redirectConfig(t, source.URL) + p, err := startMCP(t.Context(), cfg, cfg.MCP) + if p != nil { + _ = p.close() + } + require.ErrorContains(t, err, "binding origin") + require.Zero(t, calls.Load(), "cross-origin destination must receive no request, including binding credentials") + }) + } +} + +func TestMCPSameOriginRedirect(t *testing.T) { + var authenticated atomic.Int32 + remote := mcp.NewServer(&mcp.Implementation{Name: "redirect-target", Version: "1"}, nil) + mcp.AddTool(remote, &mcp.Tool{Name: "check"}, func(context.Context, *mcp.CallToolRequest, struct{}) (*mcp.CallToolResult, struct{}, error) { + return &mcp.CallToolResult{}, struct{}{}, nil + }) + handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return remote }, &mcp.StreamableHTTPOptions{Stateless: true}) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/redirect" { + http.Redirect(w, r, "/mcp", http.StatusTemporaryRedirect) + return + } + if r.Header.Get("Authorization") != "Bearer test-marker" { + http.Error(w, "missing header", http.StatusUnauthorized) + return + } + authenticated.Add(1) + handler.ServeHTTP(w, r) + })) + defer server.Close() + cfg := redirectConfig(t, server.URL+"/redirect") + p, err := startMCP(t.Context(), cfg, cfg.MCP) + require.NoError(t, err) + require.NoError(t, p.close()) + require.Positive(t, authenticated.Load()) +} + +func TestMCPRedirectLoopIsBounded(t *testing.T) { + var calls atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + calls.Add(1) + http.Redirect(w, r, "/loop", http.StatusTemporaryRedirect) + })) + defer server.Close() + cfg := redirectConfig(t, server.URL) + _, err := startMCP(t.Context(), cfg, cfg.MCP) + require.ErrorContains(t, err, "10 redirects") + // The SDK first tries capabilities negotiation, then legacy initialize. + // Each request must stop after ten redirects. + require.EqualValues(t, 20, calls.Load()) +} + +func TestMCPOriginComparison(t *testing.T) { + origin, err := url.Parse("https://example.com/mcp") + require.NoError(t, err) + for _, tt := range []struct { + target string + same bool + }{ + {"https://EXAMPLE.com:443/other", true}, + {"http://example.com/mcp", false}, + {"https://example.com:8443/mcp", false}, + {"https://other.example.com/mcp", false}, + } { + t.Run(tt.target, func(t *testing.T) { + target, err := url.Parse(tt.target) + require.NoError(t, err) + require.Equal(t, tt.same, sameOrigin(origin, target)) + if !tt.same { + request, err := http.NewRequestWithContext(t.Context(), http.MethodPost, tt.target, nil) + require.NoError(t, err) + // No base transport: a forbidden request must be rejected before dispatch. + _, err = (headerTransport{origin: origin, headers: []config.Header{{Name: "Authorization", Value: "Bearer test-marker"}}}).RoundTrip(request) + require.ErrorContains(t, err, "binding origin") + require.Empty(t, request.Header.Get("Authorization")) + } + }) + } +} + +func redirectConfig(t *testing.T, endpoint string) *config.Config { + t.Helper() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"},"http_tools":[{"params":{"url":%q,"timeout":3,"headers":{"Authorization":"Bearer test-marker"}}}]}`, endpoint))) + require.NoError(t, err) + return cfg +} diff --git a/go/harness/byo/dsh/internal/bridge/runner.go b/go/harness/byo/dsh/internal/bridge/runner.go index 02c3912d7f..74b125dac5 100644 --- a/go/harness/byo/dsh/internal/bridge/runner.go +++ b/go/harness/byo/dsh/internal/bridge/runner.go @@ -67,7 +67,7 @@ func (r *Runner) Validate(ctx context.Context) error { } defer control.Close() done := make(chan error, 1) - go func() { done <- command.Wait() }() + go func() { done <- control.Wait() }() select { case err = <-done: case <-ctx.Done(): @@ -111,7 +111,9 @@ func (r *Runner) start(ctx context.Context) (*process, error) { if err != nil { return nil, errors.Join(err, os.RemoveAll(home)) } - cmd.Dir, cmd.Env, cmd.Stderr = r.workspace, config.Environment(r.environment, home), io.Discard + // A nil stderr connects directly to the null device, without a copy + // goroutine that descendants could keep blocked after supervisor death. + cmd.Dir, cmd.Env = r.workspace, config.Environment(r.environment, home) utils.ConfigureProcessGroup(cmd) stdin, err := cmd.StdinPipe() if err != nil { @@ -126,7 +128,7 @@ func (r *Runner) start(ctx context.Context) (*process, error) { return nil, errors.Join(fmt.Errorf("failed to start DSH: %w", err), stdin.Close(), stdout.Close(), os.RemoveAll(home)) } p := &process{stdin: stdin, control: control, wire: newWire(stdin, stdout), done: make(chan struct{}), home: home, events: events{tools: make(map[string]tool)}} - go func() { p.waitErr = cmd.Wait(); close(p.done) }() + go func() { p.waitErr = control.Wait(); close(p.done) }() proxy, err := startMCP(ctx, r.config, r.servers) if err != nil { return nil, errors.Join(err, p.stop()) @@ -367,8 +369,8 @@ func (p *process) stop() error { select { case <-p.done: case <-time.After(stopTimeout): - // Never kill the supervisor to impose a deadline: doing so would orphan - // the very descendants whose exit must precede releasing the Actor. + // Request forced cleanup through the lifetime pipe, then keep waiting + // for confirmation rather than releasing the Actor on a deadline. err = errors.Join(err, p.control.Close()) <-p.done } diff --git a/go/harness/byo/dsh/internal/bridge/supervisor_failure_test.go b/go/harness/byo/dsh/internal/bridge/supervisor_failure_test.go new file mode 100644 index 0000000000..0c2d819e8b --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/supervisor_failure_test.go @@ -0,0 +1,146 @@ +//go:build linux + +package bridge + +import ( + "context" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "syscall" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/supervisor" + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +func TestSupervisorDeathReapsDetachedTools(t *testing.T) { + for _, stage := range []string{"payload", "guard"} { + t.Run(stage, func(t *testing.T) { testSupervisorDeath(t, stage) }) + } +} + +func testSupervisorDeath(t *testing.T, stage string) { + t.Helper() + sentinel := exec.Command("/bin/sleep", "60") + require.NoError(t, sentinel.Start()) + t.Cleanup(func() { _ = sentinel.Process.Kill(); _ = sentinel.Wait() }) + executable, err := os.Executable() + require.NoError(t, err) + dir := t.TempDir() + script, pidFile := filepath.Join(dir, "dsh"), filepath.Join(dir, "tool.pid") + require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nexec '"+strings.ReplaceAll(executable, "'", "'\\''")+"' -test.run=TestDetachedDSHProcess\n"), 0700)) + cfg, err := config.Parse([]byte(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"}}`)) + require.NoError(t, err) + runner, err := New(cfg, script, filepath.Join(dir, "data"), append(os.Environ(), "DSH_AUDIT_DETACHED="+pidFile, "DSH_AUDIT_EXIT=forced")) + require.NoError(t, err) + var dshPID, toolPID int + t.Cleanup(func() { + if dshPID > 0 { + _ = syscall.Kill(-dshPID, syscall.SIGKILL) + } + if toolPID > 0 { + _ = syscall.Kill(-toolPID, syscall.SIGKILL) + } + }) + ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) + defer cancel() + done := make(chan error, 1) + go func() { _, err := runner.Run(ctx, runtime.Turn{Prompt: "work"}, &recordingSink{}); done <- err }() + require.Eventually(t, func() bool { + data, err := os.ReadFile(pidFile) + if err != nil { + return false + } + toolPID, err = strconv.Atoi(string(data)) + if err != nil { + return false + } + data, err = os.ReadFile(pidFile + ".dsh") + if err != nil { + return false + } + dshPID, err = strconv.Atoi(string(data)) + return err == nil + }, 3*time.Second, 10*time.Millisecond) + supervisorPID := parentPID(t, dshPID) + if stage == "guard" { + supervisorPID = parentPID(t, supervisorPID) + } + require.Greater(t, supervisorPID, 1) + commandLine, err := os.ReadFile("/proc/" + strconv.Itoa(supervisorPID) + "/cmdline") + require.NoError(t, err) + require.Contains(t, string(commandLine), supervisor.Mode+"\x00"+stage+"\x00", "only kill the expected supervisor") + require.NoError(t, syscall.Kill(supervisorPID, syscall.SIGKILL)) + cancel() + returned := false + select { + case err := <-done: + returned = true + require.Error(t, err) + case <-time.After(12 * time.Second): + } + dshAlive, toolAlive := syscall.Kill(dshPID, 0) == nil, syscall.Kill(toolPID, 0) == nil + require.NoError(t, syscall.Kill(sentinel.Process.Pid, 0), "unrelated process must survive") + require.True(t, returned, "supervisor failure leaves Run blocked despite cancellation") + require.False(t, dshAlive || toolAlive, "failed supervisor must not release a turn while its payload is alive") +} + +func parentPID(t *testing.T, pid int) int { + t.Helper() + status, err := os.ReadFile("/proc/" + strconv.Itoa(pid) + "/status") + require.NoError(t, err) + for line := range strings.SplitSeq(string(status), "\n") { + if value, ok := strings.CutPrefix(line, "PPid:"); ok { + parent, err := strconv.Atoi(strings.TrimSpace(value)) + require.NoError(t, err) + return parent + } + } + t.Fatal("missing PPid") + return 0 +} + +func TestMissingCleanupConfirmationBlocksCompletion(t *testing.T) { + executable, err := os.Executable() + require.NoError(t, err) + logPath := filepath.Join(t.TempDir(), "supervisor.log") + logFile, err := os.Create(logPath) + require.NoError(t, err) + defer logFile.Close() + owner := exec.Command(executable, "-test.run=^TestMissingCleanupOwner$") + owner.Env = append(os.Environ(), "DSH_TEST_MISSING_CONFIRMATION=1") + owner.Stderr = logFile + require.NoError(t, owner.Start()) + done := make(chan error, 1) + go func() { done <- owner.Wait() }() + t.Cleanup(func() { _ = owner.Process.Kill(); <-done }) + require.Eventually(t, func() bool { + output, err := os.ReadFile(logPath) + return err == nil && strings.Contains(string(output), "actor replacement required") + }, 5*time.Second, 10*time.Millisecond) + select { + case err := <-done: + done <- err + t.Fatal("missing cleanup confirmation must not settle the turn", err) + case <-time.After(100 * time.Millisecond): + } +} + +func TestMissingCleanupOwner(t *testing.T) { + if os.Getenv("DSH_TEST_MISSING_CONFIRMATION") == "" { + return + } + // A process that exits without implementing the private confirmation protocol. + control, err := supervisor.Start(exec.Command("/bin/true")) + require.NoError(t, err) + defer control.Close() + _ = control.Wait() + os.Exit(3) +} diff --git a/go/harness/byo/dsh/internal/supervisor/command.go b/go/harness/byo/dsh/internal/supervisor/command.go index 22318aa09a..afd46a20d6 100644 --- a/go/harness/byo/dsh/internal/supervisor/command.go +++ b/go/harness/byo/dsh/internal/supervisor/command.go @@ -4,14 +4,22 @@ package supervisor import ( "fmt" "io" + "log/slog" "os" "os/exec" "runtime" + "time" ) // Mode is a private re-exec entry point, handled before application startup. const Mode = "--dsh-supervise" +const ( + guardStage = "guard" + payloadStage = "payload" + cleanupComplete = byte(1) +) + // Command re-executes this binary as a dedicated supervisor for one DSH turn. func Command(executable string, args ...string) (*exec.Cmd, error) { if runtime.GOOS != "linux" { @@ -21,17 +29,66 @@ func Command(executable string, args ...string) (*exec.Cmd, error) { if err != nil { return nil, fmt.Errorf("failed to locate DSH supervisor executable: %w", err) } - return exec.Command(self, append([]string{Mode, executable}, args...)...), nil + cmd := exec.Command(self, append([]string{Mode, guardStage, executable}, args...)...) + // Bound inherited output pipes after guard death. Cleanup is independently + // confirmed by Wait, so closing an output pipe cannot release a live tool. + cmd.WaitDelay = time.Second + return cmd, nil +} + +// Process owns the lifetime and cleanup-confirmation pipes for a supervised tree. +type Process struct { + cmd *exec.Cmd + lifetime *os.File + completion *os.File +} + +var _ io.Closer = (*Process)(nil) + +// Start gives both supervisors private pipes. Closing the lifetime requests +// forced cleanup; adapter death also closes it. Payloads inherit neither pipe. +func Start(cmd *exec.Cmd) (*Process, error) { + reader, writer, err := os.Pipe() + if err != nil { + return nil, fmt.Errorf("failed to create DSH cleanup pipe: %w", err) + } + lifetime, err := startSupervised(cmd, writer) + _ = writer.Close() + if err != nil { + _ = reader.Close() + return nil, err + } + return &Process{cmd: cmd, lifetime: lifetime, completion: reader}, nil +} + +func (p *Process) Close() error { return p.lifetime.Close() } + +// Wait must be called once. Process exit alone does not prove cleanup: a +// supervisor may have been killed while the surviving supervisor is reaping. +func (p *Process) Wait() error { + err := p.cmd.Wait() + var confirmation [1]byte + _, readErr := io.ReadFull(p.completion, confirmation[:]) + _ = p.completion.Close() + if readErr != nil || confirmation[0] != cleanupComplete { + // Both supervisors were lost, or the private protocol broke. Keep the + // task unsettled: only replacing the Actor can restore containment. + slog.New(slog.NewJSONHandler(os.Stderr, nil)).Error("dsh cleanup could not be confirmed; actor replacement required", "error", readErr) + // A bare select would let Go's deadlock detector terminate a check-only + // process with no server goroutines. Keep this failure closed there too. + for { + time.Sleep(time.Hour) + } + } + return err } -// Start gives the supervisor a private lifetime pipe. Closing it requests forced -// cleanup; adapter death also closes it. DSH and its tools never inherit it. -func Start(cmd *exec.Cmd) (io.Closer, error) { +func startSupervised(cmd *exec.Cmd, completion *os.File) (*os.File, error) { reader, writer, err := os.Pipe() if err != nil { return nil, fmt.Errorf("failed to create DSH lifetime pipe: %w", err) } - cmd.ExtraFiles = []*os.File{reader} + cmd.ExtraFiles = []*os.File{reader, completion} err = cmd.Start() _ = reader.Close() if err != nil { diff --git a/go/harness/byo/dsh/internal/supervisor/run_linux.go b/go/harness/byo/dsh/internal/supervisor/run_linux.go index b2afdcfa3a..341a084779 100644 --- a/go/harness/byo/dsh/internal/supervisor/run_linux.go +++ b/go/harness/byo/dsh/internal/supervisor/run_linux.go @@ -22,27 +22,32 @@ import ( // to that process, never to the long-lived A2A server. It returns only after // the main child and all adopted descendants have been reaped. func Run(args []string) int { - if err := run(args); err != nil { + completion, err := privatePipe(4, "dsh-cleanup") + if err != nil { + fmt.Fprintln(os.Stderr, err) + return 1 + } + defer completion.Close() + err = run(args, completion) + // run returns only before starting a child or after ECHILD. Either + // supervisor can confirm cleanup if the other was killed. + _, _ = completion.Write([]byte{cleanupComplete}) + if err != nil { fmt.Fprintln(os.Stderr, err) return 1 } return 0 } -func run(args []string) error { - if len(args) == 0 { +func run(args []string, completion *os.File) error { + if len(args) < 2 || (args[0] != guardStage && args[0] != payloadStage) { return fmt.Errorf("DSH supervisor requires an executable") } - control := os.NewFile(3, "dsh-lifetime") - if control == nil { - return fmt.Errorf("DSH supervisor requires a lifetime pipe") + control, err := privatePipe(3, "dsh-lifetime") + if err != nil { + return err } defer control.Close() - info, err := control.Stat() - if err != nil || info.Mode()&os.ModeNamedPipe == 0 { - return fmt.Errorf("DSH supervisor requires a lifetime pipe") - } - unix.CloseOnExec(3) if err := unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); err != nil { return fmt.Errorf("failed to enable DSH child supervision: %w", err) } @@ -55,10 +60,28 @@ func run(args []string) error { defer signal.Stop(signals) parentGone := make(chan struct{}) go func() { var b [1]byte; _, _ = control.Read(b[:]); close(parentGone) }() - cmd := exec.Command(args[0], args[1:]...) + cmd := exec.Command(args[1], args[2:]...) + if args[0] == guardStage { + self, err := os.Executable() + if err != nil { + return fmt.Errorf("failed to locate DSH supervisor executable: %w", err) + } + cmd = exec.Command(self, append([]string{Mode, payloadStage}, args[1:]...)...) + } cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - if err := cmd.Start(); err != nil { + if args[0] == guardStage { + // If this guard dies, EOF makes the inner supervisor clean up. If the + // inner supervisor dies, its descendants are adopted by this guard. + lifetime, startErr := startSupervised(cmd, completion) + err = startErr + if lifetime != nil { + defer lifetime.Close() + } + } else { + err = cmd.Start() + } + if err != nil { return fmt.Errorf("failed to launch DSH payload: %w", err) } done := make(chan error, 1) @@ -76,6 +99,20 @@ func run(args []string) error { return errors.Join(waitErr, reapDescendants()) } +func privatePipe(fd int, name string) (*os.File, error) { + file := os.NewFile(uintptr(fd), name) + if file == nil { + return nil, fmt.Errorf("DSH supervisor requires %s pipe", name) + } + info, err := file.Stat() + if err != nil || info.Mode()&os.ModeNamedPipe == 0 { + _ = file.Close() + return nil, fmt.Errorf("DSH supervisor requires %s pipe", name) + } + unix.CloseOnExec(fd) + return file, nil +} + func killAndWait(cmd *exec.Cmd, done <-chan error) error { err := cmd.Process.Kill() if errors.Is(err, os.ErrProcessDone) { From a519aa7f38dffbd9bf9714c93f53747d2bce5cad Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 18:17:18 +0800 Subject: [PATCH 07/12] test(dsh): verify settlement and durable workspace recovery Exercise the production TaskStore wrapper over gRPC, require native process cleanup before settlement, and verify file and conversation recovery with the pinned DSH runtime. Document the completed clean-cluster lifecycle acceptance and remaining coverage limits. AI assistance: implementation and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 40 +++- .../internal/bridge/a2a_integration_test.go | 50 +--- .../durable_workspace_integration_test.go | 127 ++++++++++ .../bridge/settlement_integration_test.go | 217 ++++++++++++++++++ 4 files changed, 381 insertions(+), 53 deletions(-) create mode 100644 go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go create mode 100644 go/harness/byo/dsh/internal/bridge/settlement_integration_test.go diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index f0df220003..3cab14aaaa 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -81,8 +81,9 @@ The CLI profile and compiled overlay use a disposable home outside `/data`. Do not delete the native session logs while retaining the continuation binding. Public tasks and history remain in kagent's controller-backed TaskStore. -The local tests verify recovery after a DSH process restart. Full Substrate -snapshot/restore remains a separate cluster acceptance check. +The local tests verify recovery after a DSH process restart. Cluster acceptance +also covers conversation and workspace continuity across automatic suspension +and explicit suspend/resume; Actor replacement and fork remain unverified. ## Build and deploy @@ -99,7 +100,8 @@ Record the pushed image's manifest digest. The example requires the full Use a clean kagent installation whose Agent CRD supports `spec.template.inline`. This example targets the API at source commit `b42a6c53`; `1.0.0-alpha9` uses the earlier `templateRef` shape and rejects this Agent manifest. Cluster acceptance -against a compatible release is still required. Configure a `kagent-default` +used a control plane built from this checkout and Substrate `0.5.0-alpha2`. +Configure a `kagent-default` WorkerPool, snapshot storage, and Substrate credential gateway. In namespace `kagent`, create the Secret `deepseek-api-key` with an `OPENAI_API_KEY` entry using your normal secret-management workflow. Grant the Substrate atespace @@ -145,11 +147,27 @@ DSH_TEST_BIN="$PWD/harness/byo/dsh/node_modules/.bin/dsh" \ ``` These tests use a real DSH process, a local model fixture, and a local MCP -server. They verify MCP execution and resumed turns through A2A gRPC without -provider credentials. The transport test substitutes an SDK-local TaskStore -for the controller, so it does not prove full cluster settlement or snapshots. - -Before release, run the same scenarios in Substrate: two turns, MCP success and -failure, cancellation followed by another turn, approval allow/reject/cancel, -and conversation continuity after explicit suspend/resume and Actor replacement. -Do not advertise snapshot, fork or model-usage guarantees until those checks pass. +server. A2A gRPC calls use the production TaskStore client and settlement wrapper +against a local controller RPC fixture. They check MCP execution, resumed turns, +runtime identity headers and versioned settlement without provider credentials. +Separate process tests require DSH and detached tools to exit before settlement +on normal completion, forced cleanup and cancellation. + +The durable-workspace test creates, reads and edits a file with DSH's built-in +tools across three fresh adapter instances. It verifies that the native session +identity, conversation history and workspace contents survive reconstruction +from the same durable directory. These checks do not exercise the real controller +database or Substrate snapshots and are not a substitute for cluster acceptance. + +Manual cluster acceptance on Linux arm64 with gVisor, Kubernetes `1.37.0` and +Substrate `0.5.0-alpha2` exercised the public A2A API and real PostgreSQL-backed +TaskStore. Three turns completed and automatically suspended; public `GetTask` +returned the completed task after each suspension. After explicit suspend/resume, +the model fixture received the earlier conversation history. Gateway credential +injection and workspace write/read/edit/read across suspensions also passed. +The model was a local Chat Completions fixture, not a live provider. + +Before release, complete the remaining cluster checks: MCP success and failure, +cancellation followed by another turn, approval allow/reject/cancel, and continuity +after Actor replacement and fork. The checks above do not establish guarantees +for untested lifecycle paths or model usage reporting. diff --git a/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go index 554e774bf5..64b0a2e336 100644 --- a/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go +++ b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go @@ -7,8 +7,6 @@ import ( "encoding/json" "fmt" "io" - "iter" - "net" "net/http" "net/http/httptest" "os" @@ -19,14 +17,9 @@ import ( "time" a2atype "github.com/a2aproject/a2a-go/v2/a2a" - a2agrpc "github.com/a2aproject/a2a-go/v2/a2agrpc/v1" - a2apb "github.com/a2aproject/a2a-go/v2/a2apb/v1" "github.com/a2aproject/a2a-go/v2/a2apb/v1/pbconv" - "github.com/a2aproject/a2a-go/v2/a2asrv" "github.com/modelcontextprotocol/go-sdk/mcp" "github.com/stretchr/testify/require" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" @@ -108,20 +101,10 @@ func TestRealDSHThroughA2AGRPCAndMCP(t *testing.T) { require.NoError(t, err) executor, err := runtimea2a.New(runner, store, tracing.RuntimeTelemetry{}) require.NoError(t, err) - listener, err := net.Listen("tcp", "127.0.0.1:0") - require.NoError(t, err) - server := grpc.NewServer() - a2agrpc.NewHandler(a2asrv.NewHandler(transportFixture{executor})).RegisterWith(server) - serveDone := make(chan error, 1) - go func() { serveDone <- server.Serve(listener) }() - t.Cleanup(func() { server.Stop(); require.NoError(t, <-serveDone) }) - connection, err := grpc.NewClient(listener.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) - require.NoError(t, err) - t.Cleanup(func() { require.NoError(t, connection.Close()) }) - client := a2apb.NewA2AServiceClient(connection) + client, api := newSettlementClient(t, executor, nil) ctx, cancel := context.WithTimeout(t.Context(), 90*time.Second) defer cancel() - contextID := "" + contextID := "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa" for i, prompt := range []string{"Calculate six times seven.", "Continue the calculation."} { message := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart(prompt)) message.ContextID = contextID @@ -154,6 +137,12 @@ func TestRealDSHThroughA2AGRPCAndMCP(t *testing.T) { } } require.True(t, completed) + select { + case task := <-api.settled: + require.Equal(t, contextID, task.ContextId) + case <-ctx.Done(): + t.Fatal("missing task settlement", ctx.Err()) + } want := "product=42" if i == 1 { want = "resumed product=42" @@ -168,29 +157,6 @@ func TestRealDSHThroughA2AGRPCAndMCP(t *testing.T) { require.Contains(t, string(requests[2]), "product=42") } -// The production App's controller-backed TaskStore publishes the initial task. -// This transport-only fixture substitutes an SDK-local task for that boundary. -type transportFixture struct{ a2asrv.AgentExecutor } - -func (f transportFixture) Execute(ctx context.Context, input *a2asrv.ExecutorContext) iter.Seq2[a2atype.Event, error] { - return func(yield func(a2atype.Event, error) bool) { - if input.TaskID == "" { - input.TaskID = a2atype.NewTaskID() - } - if input.ContextID == "" { - input.ContextID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa" - } - if !yield(a2atype.NewSubmittedTask(input, input.Message), nil) { - return - } - for event, err := range f.AgentExecutor.Execute(ctx, input) { - if !yield(event, err) { - return - } - } - } -} - func writeCompletion(w http.ResponseWriter, delta any, finish string) { w.Header().Set("Content-Type", "text/event-stream") for _, choice := range []any{map[string]any{"delta": delta, "index": 0, "finish_reason": nil}, map[string]any{"delta": map[string]any{}, "index": 0, "finish_reason": finish}} { diff --git a/go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go b/go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go new file mode 100644 index 0000000000..5f859bc860 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go @@ -0,0 +1,127 @@ +//go:build linux + +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "sync" + "testing" + "time" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + a2apb "github.com/a2aproject/a2a-go/v2/a2apb/v1" + "github.com/a2aproject/a2a-go/v2/a2apb/v1/pbconv" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" + "github.com/kagent-dev/kagent/go/harness/runtime/continuation" + "github.com/kagent-dev/kagent/go/pkg/tracing" +) + +func TestRealDSHRestartsWithDurableWorkspace(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("DSH_TEST_BIN required") + } + dataDir := t.TempDir() + file := filepath.Join(dataDir, "workspace", "continuity.txt") + var mu sync.Mutex + var requests []json.RawMessage + model := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var body json.RawMessage + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, "invalid request", 400) + return + } + mu.Lock() + requests = append(requests, body) + index := len(requests) + mu.Unlock() + step := map[int]int{2: 1, 5: 2, 7: 3}[index] + if step != 0 { + writeCompletion(w, map[string]string{"role": "assistant", "content": fmt.Sprintf("finished step %d", step)}, "stop") + return + } + args := map[string]string{"file_path": file} + name := "read" + switch index { + case 1: + name, args["content"] = "write", "first\n" + case 3, 6: + case 4: + name, args["old_string"], args["new_string"] = "edit", "first", "second" + default: + http.Error(w, "unexpected model call", 500) + return + } + encoded, _ := json.Marshal(args) + writeCompletion(w, map[string]any{"role": "assistant", "tool_calls": []any{map[string]any{"index": 0, "id": fmt.Sprintf("file-%d", index), "type": "function", "function": map[string]string{"name": name, "arguments": string(encoded)}}}}, "tool_calls") + })) + defer model.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock","base_url":%q},"runtime":{"control_plane_url":"http://controller:8083"}}`, model.URL+"/v1"))) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 60*time.Second) + defer cancel() + nativeID, contextID := "", uuid.NewString() + for i, prompt := range []string{"Create the continuity file.", "Replace first with second.", "Read the continuity file."} { + // Rebuild both adapter and continuation objects; only the durable directory + // carries conversation identity, history and files into the next turn. + runner, err := New(cfg, executable, dataDir, append(os.Environ(), "OPENAI_API_KEY=mock", "DSH_PERMISSION_MODE=workspace-write")) + require.NoError(t, err) + store, err := continuation.New(filepath.Join(dataDir, "adapter"), "dsh-byo", ValidateSessionID) + require.NoError(t, err) + executor, err := runtimea2a.New(runner, store, tracing.RuntimeTelemetry{}) + require.NoError(t, err) + client, api := newSettlementClient(t, executor, nil) + message := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart(prompt)) + message.ContextID = contextID + request, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: message}) + require.NoError(t, err) + _, err = client.SendMessage(ctx, request) + require.NoError(t, err) + select { + case task := <-api.settled: + require.Equal(t, a2apb.TaskState_TASK_STATE_COMPLETED, task.Status.State) + case <-ctx.Done(): + t.Fatal("file turn never settled", ctx.Err()) + } + id, bound, err := store.Load() + require.NoError(t, err) + require.True(t, bound) + if nativeID == "" { + nativeID = id + } + require.Equal(t, nativeID, id) + content, err := os.ReadFile(file) + require.NoError(t, err) + want := "second\n" + if i == 0 { + want = "first\n" + } + require.Equal(t, want, string(content)) + } + mu.Lock() + defer mu.Unlock() + require.Len(t, requests, 7) + require.Contains(t, string(requests[2]), "finished step 1") + require.Contains(t, string(requests[5]), "finished step 2") + var last struct { + Messages []struct { + Role string `json:"role"` + Content string `json:"content"` + } `json:"messages"` + } + require.NoError(t, json.Unmarshal(requests[6], &last)) + require.NotEmpty(t, last.Messages) + message := last.Messages[len(last.Messages)-1] + require.Equal(t, "tool", message.Role) + require.Contains(t, message.Content, "second") +} diff --git a/go/harness/byo/dsh/internal/bridge/settlement_integration_test.go b/go/harness/byo/dsh/internal/bridge/settlement_integration_test.go new file mode 100644 index 0000000000..eb87b935a2 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/settlement_integration_test.go @@ -0,0 +1,217 @@ +//go:build linux + +package bridge + +import ( + "context" + "fmt" + "net" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "syscall" + "testing" + "time" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + a2agrpc "github.com/a2aproject/a2a-go/v2/a2agrpc/v1" + a2apb "github.com/a2aproject/a2a-go/v2/a2apb/v1" + "github.com/a2aproject/a2a-go/v2/a2apb/v1/pbconv" + "github.com/a2aproject/a2a-go/v2/a2asrv" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + + adka2a "github.com/kagent-dev/kagent/go/adk/pkg/a2a" + "github.com/kagent-dev/kagent/go/adk/pkg/controllerclient" + "github.com/kagent-dev/kagent/go/adk/pkg/taskstore" + apia2a "github.com/kagent-dev/kagent/go/api/a2a" + apiv1alpha1 "github.com/kagent-dev/kagent/go/api/gen/kagent/api/v1alpha1" + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" + "github.com/kagent-dev/kagent/go/harness/runtime/continuation" + "github.com/kagent-dev/kagent/go/pkg/tracing" +) + +// The real runtime Store and settlement wrapper talk gRPC to this API fixture. +// It checks runtime ordering and version fences, not PostgreSQL or Substrate. +type taskStoreFixture struct { + apiv1alpha1.UnimplementedTaskStoreServiceServer + mu sync.Mutex + tasks map[string]*apiv1alpha1.StoredTask + settled chan *a2apb.Task + check func(*a2apb.Task) error +} + +func (s *taskStoreFixture) CreateTask(_ context.Context, r *apiv1alpha1.TaskStoreServiceCreateTaskRequest) (*apiv1alpha1.TaskStoreServiceCreateTaskResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + if r.Task == nil || r.Task.Id == "" || r.Task.ContextId == "" { + return nil, status.Error(codes.InvalidArgument, "missing task identity") + } + if s.tasks[r.Task.Id] != nil { + return nil, status.Error(codes.AlreadyExists, "task already exists") + } + s.tasks[r.Task.Id] = &apiv1alpha1.StoredTask{Task: proto.CloneOf(r.Task), Version: 1} + return &apiv1alpha1.TaskStoreServiceCreateTaskResponse{Version: 1}, nil +} + +func (s *taskStoreFixture) UpdateTask(_ context.Context, r *apiv1alpha1.TaskStoreServiceUpdateTaskRequest) (*apiv1alpha1.TaskStoreServiceUpdateTaskResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + stored := s.tasks[r.Task.GetId()] + if stored == nil || stored.Version != r.ExpectedVersion { + return nil, status.Error(codes.Aborted, "task version conflict") + } + stored.Task = proto.CloneOf(r.Task) + stored.Version++ + return &apiv1alpha1.TaskStoreServiceUpdateTaskResponse{Version: stored.Version}, nil +} + +func (s *taskStoreFixture) GetTask(_ context.Context, r *apiv1alpha1.TaskStoreServiceGetTaskRequest) (*apiv1alpha1.TaskStoreServiceGetTaskResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + stored := s.tasks[r.TaskId] + if stored == nil { + return nil, status.Error(codes.NotFound, "task not found") + } + return &apiv1alpha1.TaskStoreServiceGetTaskResponse{Stored: proto.CloneOf(stored)}, nil +} + +func (s *taskStoreFixture) SettleTask(_ context.Context, r *apiv1alpha1.TaskStoreServiceSettleTaskRequest) (*apiv1alpha1.TaskStoreServiceSettleTaskResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + stored := s.tasks[r.TaskId] + if stored == nil || stored.Version != r.Version { + return nil, status.Error(codes.Aborted, "settlement version conflict") + } + if s.check != nil { + if err := s.check(stored.Task); err != nil { + return nil, status.Error(codes.FailedPrecondition, err.Error()) + } + } + s.settled <- proto.CloneOf(stored.Task) + return &apiv1alpha1.TaskStoreServiceSettleTaskResponse{}, nil +} + +func newSettlementClient(t *testing.T, executor a2asrv.AgentExecutor, check func(*a2apb.Task) error) (a2apb.A2AServiceClient, *taskStoreFixture) { + t.Helper() + sessionID := uuid.NewString() + identityDir := t.TempDir() + for field, value := range map[string]string{"name": "session-" + sessionID, "atespace": "acceptance", "uid": "test-actor"} { + require.NoError(t, os.WriteFile(filepath.Join(identityDir, field), []byte(value), 0600)) + } + api := &taskStoreFixture{tasks: make(map[string]*apiv1alpha1.StoredTask), settled: make(chan *a2apb.Task, 16), check: check} + controlListener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + control := grpc.NewServer(grpc.UnaryInterceptor(func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { + md, _ := metadata.FromIncomingContext(ctx) + if strings.Join(md.Get(apia2a.InsecureRuntimeIdentityHeader), "") != "acceptance/session-"+sessionID+"/test-actor" || req.(interface{ GetSessionId() string }).GetSessionId() != sessionID { + return nil, status.Error(codes.PermissionDenied, "runtime identity mismatch") + } + return handler(ctx, req) + })) + apiv1alpha1.RegisterTaskStoreServiceServer(control, api) + controlDone := make(chan error, 1) + go func() { controlDone <- control.Serve(controlListener) }() + t.Cleanup(func() { control.Stop(); require.NoError(t, <-controlDone) }) + controller, err := controllerclient.New(controllerclient.Config{APIURL: "http://" + controlListener.Addr().String()}) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, controller.Close()) }) + tasks := taskstore.New(controller, filepath.Join(identityDir, "name")) + wrapped := tasks.WrapExecutor(executor, "", nil) + handler := a2asrv.NewHandler(wrapped, a2asrv.WithTaskStore(tasks), a2asrv.WithCallInterceptors(adka2a.HITLActivationInterceptor(), adka2a.UserIDCallInterceptor(), wrapped)) + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + server := grpc.NewServer() + a2agrpc.NewHandler(handler).RegisterWith(server) + serveDone := make(chan error, 1) + go func() { serveDone <- server.Serve(listener) }() + t.Cleanup(func() { server.Stop(); require.NoError(t, <-serveDone) }) + connection, err := grpc.NewClient(listener.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, connection.Close()) }) + return a2apb.NewA2AServiceClient(connection), api +} + +func TestSettlementWaitsForDetachedToolCleanup(t *testing.T) { + for _, mode := range []string{"normal", "forced", "cancel"} { + t.Run(mode, func(t *testing.T) { + executable, err := os.Executable() + require.NoError(t, err) + dir := t.TempDir() + script, pidFile := filepath.Join(dir, "dsh"), filepath.Join(dir, "tool.pid") + require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nexec '"+strings.ReplaceAll(executable, "'", "'\\''")+"' -test.run=TestDetachedDSHProcess\n"), 0700)) + cfg, err := config.Parse([]byte(`{"model":{"type":"openai","model":"mock"},"runtime":{"control_plane_url":"http://controller:8083"}}`)) + require.NoError(t, err) + exitMode := mode + if mode == "cancel" { + exitMode = "forced" + } + runner, err := New(cfg, script, filepath.Join(dir, "data"), append(os.Environ(), "DSH_AUDIT_DETACHED="+pidFile, "DSH_AUDIT_EXIT="+exitMode)) + require.NoError(t, err) + store, err := continuation.New(filepath.Join(dir, "data", "adapter"), "dsh-byo", ValidateSessionID) + require.NoError(t, err) + executor, err := runtimea2a.New(runner, store, tracing.RuntimeTelemetry{}) + require.NoError(t, err) + client, api := newSettlementClient(t, executor, func(*a2apb.Task) error { + for _, path := range []string{pidFile, pidFile + ".dsh"} { + data, err := os.ReadFile(path) + if err != nil { + return err + } + pid, err := strconv.Atoi(string(data)) + if err != nil { + return err + } + if syscall.Kill(pid, 0) != syscall.ESRCH { + return fmt.Errorf("settlement preceded process cleanup") + } + } + return nil + }) + ctx, cancel := context.WithTimeout(t.Context(), 20*time.Second) + defer cancel() + msg := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("work")) + msg.ContextID = uuid.NewString() + req, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: msg}) + require.NoError(t, err) + if mode == "cancel" { + stream, err := client.SendStreamingMessage(ctx, req) + require.NoError(t, err) + initial, err := stream.Recv() + require.NoError(t, err) + require.NotNil(t, initial.GetTask()) + require.Eventually(t, func() bool { _, err := os.Stat(pidFile); return err == nil }, 3*time.Second, 10*time.Millisecond) + cancelRequest, err := pbconv.ToProtoCancelTaskRequest(&a2atype.CancelTaskRequest{ID: a2atype.TaskID(initial.GetTask().Id)}) + require.NoError(t, err) + canceled, err := client.CancelTask(ctx, cancelRequest) + require.NoError(t, err) + require.Equal(t, a2apb.TaskState_TASK_STATE_CANCELED, canceled.Status.State) + } else { + _, err = client.SendMessage(ctx, req) + require.NoError(t, err) + } + select { + case task := <-api.settled: + want := a2apb.TaskState_TASK_STATE_COMPLETED + switch mode { + case "forced": + want = a2apb.TaskState_TASK_STATE_FAILED + case "cancel": + want = a2apb.TaskState_TASK_STATE_CANCELED + } + require.Equal(t, want, task.Status.State) + case <-ctx.Done(): + t.Fatal("task never settled", ctx.Err()) + } + }) + } +} From 98f70c34a20de2bcbbbf90d9a7338788db6000b7 Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 18:35:29 +0800 Subject: [PATCH 08/12] docs(dsh): track shared runtime migration requirements Document upstream dependencies and the guarantees needed to replace local process supervision, pending approvals and MCP origin checks. Clarify that replacing an Actor does not reconcile an orphaned controller task. AI assistance: implementation and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 13 +++++++++++-- go/harness/byo/dsh/internal/bridge/mcp.go | 5 +++++ go/harness/byo/dsh/internal/bridge/runner.go | 6 ++++++ go/harness/byo/dsh/internal/supervisor/command.go | 12 +++++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index 3cab14aaaa..9ca7a8f710 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -59,8 +59,11 @@ The adapter waits for an explicit cleanup confirmation before releasing the turn process exit or closed output pipes alone are insufficient. During payload execution, this tolerates the loss of either supervisor. If neither -can confirm cleanup, for example after losing both, replacing the Actor is -required: the adapter logs the failure and leaves the task unsettled. +can confirm cleanup, for example after losing both, the adapter logs the failure +and leaves the task unsettled. Replacing the Actor restores process containment; +it does not reconcile the controller's outstanding task. Recovery also needs +controller-owned fencing and task reconciliation, tracked in +[kagent #3010](https://github.com/kagent-dev/kagent/issues/3010). Uninterruptible kernel I/O can also delay cleanup. This is not a guarantee against simultaneous process kills or malicious same-UID tools. @@ -81,6 +84,12 @@ The CLI profile and compiled overlay use a disposable home outside `/data`. Do not delete the native session logs while retaining the continuation binding. Public tasks and history remain in kagent's controller-backed TaskStore. +Pending approvals also need the live ACP process. They cannot currently recover +from a DATA-only snapshot or process replacement. The shared durable-input work +in [kagent #3165](https://github.com/kagent-dev/kagent/pull/3165) is a migration +dependency, but DSH must also support resuming the exact pending call without +replaying a tool before this adapter can adopt that recovery path. + The local tests verify recovery after a DSH process restart. Cluster acceptance also covers conversation and workspace continuity across automatic suspension and explicit suspend/resume; Actor replacement and fork remain unverified. diff --git a/go/harness/byo/dsh/internal/bridge/mcp.go b/go/harness/byo/dsh/internal/bridge/mcp.go index 909457ea5b..5ac4c3037e 100644 --- a/go/harness/byo/dsh/internal/bridge/mcp.go +++ b/go/harness/byo/dsh/internal/bridge/mcp.go @@ -141,6 +141,11 @@ func (p *mcpProxy) close() error { return err } +// TODO: align with the shared origin/credential policy after +// https://github.com/kagent-dev/kagent/pull/3177 lands. Replace this local guard +// only when a shared client policy prevents binding headers from being sent to +// another origin on redirects and SDK-generated requests. Gateway destination +// grants alone do not provide that client-side guarantee. type headerTransport struct { base http.RoundTripper origin *url.URL diff --git a/go/harness/byo/dsh/internal/bridge/runner.go b/go/harness/byo/dsh/internal/bridge/runner.go index 74b125dac5..0b163d5f6c 100644 --- a/go/harness/byo/dsh/internal/bridge/runner.go +++ b/go/harness/byo/dsh/internal/bridge/runner.go @@ -291,6 +291,12 @@ type permissionOutcome struct { OptionID string `json:"optionId,omitempty"` } +// pending retains a live ACP request and requires memory-preserving suspension. +// TODO: adapt to the shared durable-input contract when +// https://github.com/kagent-dev/kagent/pull/3165 lands. Migration also requires a +// DSH-supported way to resume the exact pending call after process replacement, +// without replaying a possibly executed tool. A persisted session ID alone cannot +// replace this live request; do not enable DATA-only approval recovery by itself. type pending struct { process *process id json.RawMessage diff --git a/go/harness/byo/dsh/internal/supervisor/command.go b/go/harness/byo/dsh/internal/supervisor/command.go index afd46a20d6..181fcf1a10 100644 --- a/go/harness/byo/dsh/internal/supervisor/command.go +++ b/go/harness/byo/dsh/internal/supervisor/command.go @@ -1,4 +1,10 @@ // Package supervisor owns one DSH process tree, including detached tools. +// +// TODO: adopt shared turn-process ownership after +// https://github.com/kagent-dev/kagent/pull/3131 (built on PR #3006) lands and +// exposes an owner usable by native harnesses. Keep the local supervisor until +// that owner also reaps descendants that leave their process group and confirms +// cleanup after supervisor death; tracking process groups alone is insufficient. package supervisor import ( @@ -72,7 +78,11 @@ func (p *Process) Wait() error { _ = p.completion.Close() if readErr != nil || confirmation[0] != cleanupComplete { // Both supervisors were lost, or the private protocol broke. Keep the - // task unsettled: only replacing the Actor can restore containment. + // task unsettled: replacing the Actor restores process containment, but + // does not itself reconcile the controller's task state. + // TODO: use controller-owned fencing and task recovery once + // https://github.com/kagent-dev/kagent/issues/3010 is resolved with that + // contract. Never turn missing cleanup proof into local task completion. slog.New(slog.NewJSONHandler(os.Stderr, nil)).Error("dsh cleanup could not be confirmed; actor replacement required", "error", readErr) // A bare select would let Go's deadlock detector terminate a check-only // process with no server goroutines. Keep this failure closed there too. From e82738b1a30b57e7133e62e941b38029e8720a6a Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 18:50:29 +0800 Subject: [PATCH 09/12] fix(dsh): reject requests without a live execution owner Return an explicit cancellation error when the shared executor emits no result. Reject lost task continuations before SDK history writes can mutate or settle the waiting task. Keep unknown cleanup fail-closed and document that these DSH-only mitigations do not provide automatic task or approval recovery. AI assistance: implementation and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 10 ++ go/harness/byo/dsh/cmd/main.go | 5 +- .../internal/bridge/a2a_integration_test.go | 3 +- .../durable_workspace_integration_test.go | 3 +- .../byo/dsh/internal/bridge/executor.go | 75 ++++++++ .../bridge/recovery_integration_test.go | 165 ++++++++++++++++++ .../bridge/settlement_integration_test.go | 9 +- 7 files changed, 260 insertions(+), 10 deletions(-) create mode 100644 go/harness/byo/dsh/internal/bridge/executor.go create mode 100644 go/harness/byo/dsh/internal/bridge/recovery_integration_test.go diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index 9ca7a8f710..406ed70131 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -64,6 +64,10 @@ and leaves the task unsettled. Replacing the Actor restores process containment; it does not reconcile the controller's outstanding task. Recovery also needs controller-owned fencing and task reconciliation, tracked in [kagent #3010](https://github.com/kagent-dev/kagent/issues/3010). +As a temporary DSH-only mitigation, cancellation with no live execution owner +returns an explicit `TASK_NOT_CANCELABLE` error instead of waiting indefinitely. +It leaves the stored task unchanged; it does not certify cleanup or unblock the +session's lifecycle operations. Uninterruptible kernel I/O can also delay cleanup. This is not a guarantee against simultaneous process kills or malicious same-UID tools. @@ -89,6 +93,12 @@ from a DATA-only snapshot or process replacement. The shared durable-input work in [kagent #3165](https://github.com/kagent-dev/kagent/pull/3165) is a migration dependency, but DSH must also support resuming the exact pending call without replaying a tool before this adapter can adopt that recovery path. +Until then, the DSH adapter accepts a send referencing an existing task only +when that task owns the live pending approval. It rejects both approval decisions +and plain replies to a lost task before the SDK appends history or changes task +state. Continue completed work with a new A2A task in the same conversation. +These guards do not replay prompts or apply approvals after ownership is lost; +they provide explicit failure, not automatic approval recovery. The local tests verify recovery after a DSH process restart. Cluster acceptance also covers conversation and workspace continuity across automatic suspension diff --git a/go/harness/byo/dsh/cmd/main.go b/go/harness/byo/dsh/cmd/main.go index b470c2efbf..e434036b12 100644 --- a/go/harness/byo/dsh/cmd/main.go +++ b/go/harness/byo/dsh/cmd/main.go @@ -16,7 +16,6 @@ import ( "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/bridge" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/supervisor" - runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" "github.com/kagent-dev/kagent/go/harness/runtime/continuation" "github.com/kagent-dev/kagent/go/pkg/logging" "github.com/kagent-dev/kagent/go/pkg/telemetry" @@ -84,7 +83,7 @@ func run(ctx context.Context, executable, dataDir, port string, check bool, gete ctx = logging.IntoContext(ctx, logger) identity := runtimeConfig.Telemetry.WithEnvironment(environment) // Leave runtime identity unset: the telemetry catalog has no DSH value. - executor, err := runtimea2a.New(runner, store, identity) + executor, err := bridge.NewExecutor(runner, store, identity) if err != nil { return err } @@ -102,7 +101,7 @@ func run(ctx context.Context, executable, dataDir, port string, check bool, gete application, err := app.New(app.AppConfig{ AgentCard: card, Port: port, AppName: card.Name, ControlPlaneURL: runtimeConfig.ControlPlaneURL, MaxContentLength: runtimeConfig.MaxContentLength, Logger: logging.FromContext(ctx), Telemetry: identity, Flush: providers.ForceFlush, - HandlerOpts: []a2asrv.RequestHandlerOption{a2asrv.WithExecutorContextInterceptor(startMetrics(providers.StartMetrics))}, + HandlerOpts: []a2asrv.RequestHandlerOption{a2asrv.WithExecutorContextInterceptor(startMetrics(providers.StartMetrics)), a2asrv.WithCallInterceptors(executor)}, }, executor) if err != nil { return fmt.Errorf("failed to construct BYO A2A application: %w", err) diff --git a/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go index 64b0a2e336..0ce1efb60a 100644 --- a/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go +++ b/go/harness/byo/dsh/internal/bridge/a2a_integration_test.go @@ -22,7 +22,6 @@ import ( "github.com/stretchr/testify/require" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" - runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" "github.com/kagent-dev/kagent/go/harness/runtime/continuation" "github.com/kagent-dev/kagent/go/pkg/tracing" ) @@ -99,7 +98,7 @@ func TestRealDSHThroughA2AGRPCAndMCP(t *testing.T) { require.NoError(t, err) store, err := continuation.New(dataDir+"/adapter", "dsh-byo", ValidateSessionID) require.NoError(t, err) - executor, err := runtimea2a.New(runner, store, tracing.RuntimeTelemetry{}) + executor, err := NewExecutor(runner, store, tracing.RuntimeTelemetry{}) require.NoError(t, err) client, api := newSettlementClient(t, executor, nil) ctx, cancel := context.WithTimeout(t.Context(), 90*time.Second) diff --git a/go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go b/go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go index 5f859bc860..dee87ea303 100644 --- a/go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go +++ b/go/harness/byo/dsh/internal/bridge/durable_workspace_integration_test.go @@ -21,7 +21,6 @@ import ( "github.com/stretchr/testify/require" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" - runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" "github.com/kagent-dev/kagent/go/harness/runtime/continuation" "github.com/kagent-dev/kagent/go/pkg/tracing" ) @@ -78,7 +77,7 @@ func TestRealDSHRestartsWithDurableWorkspace(t *testing.T) { require.NoError(t, err) store, err := continuation.New(filepath.Join(dataDir, "adapter"), "dsh-byo", ValidateSessionID) require.NoError(t, err) - executor, err := runtimea2a.New(runner, store, tracing.RuntimeTelemetry{}) + executor, err := NewExecutor(runner, store, tracing.RuntimeTelemetry{}) require.NoError(t, err) client, api := newSettlementClient(t, executor, nil) message := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart(prompt)) diff --git a/go/harness/byo/dsh/internal/bridge/executor.go b/go/harness/byo/dsh/internal/bridge/executor.go new file mode 100644 index 0000000000..208667ce6a --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/executor.go @@ -0,0 +1,75 @@ +package bridge + +import ( + "context" + "iter" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + "github.com/a2aproject/a2a-go/v2/a2asrv" + + apia2a "github.com/kagent-dev/kagent/go/api/a2a" + runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" + "github.com/kagent-dev/kagent/go/pkg/tracing" +) + +// Executor adds DSH-specific failure handling to the shared executor. It cannot +// infer process cleanup from missing in-memory state or reconstruct ACP promises. +type Executor struct { + a2asrv.PassthroughCallInterceptor + *runtimea2a.Executor +} + +var _ a2asrv.AgentExecutor = (*Executor)(nil) +var _ a2asrv.CallInterceptor = (*Executor)(nil) + +// NewExecutor constructs the DSH executor. Register its call interceptor too, +// so lost continuations are rejected before the SDK persists their messages. +func NewExecutor(runner *Runner, store runtimea2a.ContinuationStore, telemetry tracing.RuntimeTelemetry) (*Executor, error) { + executor, err := runtimea2a.New(runner, store, telemetry) + if err != nil { + return nil, err + } + return &Executor{Executor: executor}, nil +} + +// Before admits task continuations only for the live parked turn. In this +// single-turn adapter, active work cannot accept another send and completed work +// continues as a new A2A task. Reject at the call boundary: even the SDK's history +// append can settle a stored input-required task before Executor.Execute runs. +// TODO: replace this rejection with exact pending-call recovery once +// https://github.com/kagent-dev/kagent/pull/3165 and DSH support that contract. +func (e *Executor) Before(ctx context.Context, _ *a2asrv.CallContext, request *a2asrv.Request) (context.Context, any, error) { + if send, ok := request.Payload.(*a2atype.SendMessageRequest); ok && send.Message != nil { + message := send.Message + payload, _ := message.Metadata[apia2a.HITLExtensionURI].(map[string]any) + approval := payload["type"] == apia2a.HITLTypeToolApprovalResponse + if (message.TaskID != "" || approval) && (message.TaskID == "" || e.ReservedTaskID() != message.TaskID) { + return ctx, nil, a2atype.NewError(a2atype.ErrUnsupportedOperation, "DSH task has no live continuation owner; the request was not applied and no tool was replayed") + } + } + return ctx, nil, nil +} + +// Cancel must return a protocol error when the shared executor has no owner. +// An empty sequence leaves the A2A caller waiting indefinitely. Do not fabricate +// CANCELED: an absent owner is not proof that its tools have stopped. +// TODO: adopt fenced task recovery from +// https://github.com/kagent-dev/kagent/issues/3010 when it becomes available. +func (e *Executor) Cancel(ctx context.Context, input *a2asrv.ExecutorContext) iter.Seq2[a2atype.Event, error] { + return func(yield func(a2atype.Event, error) bool) { + emitted := false + for event, err := range e.Executor.Cancel(ctx, input) { + emitted = true + if !yield(event, err) { + return + } + } + if !emitted { + if err := ctx.Err(); err != nil { + yield(nil, err) + return + } + yield(nil, a2atype.NewError(a2atype.ErrTaskNotCancelable, "DSH task has no live execution owner; cleanup must be confirmed before task recovery")) + } + } +} diff --git a/go/harness/byo/dsh/internal/bridge/recovery_integration_test.go b/go/harness/byo/dsh/internal/bridge/recovery_integration_test.go new file mode 100644 index 0000000000..42c38a6c4a --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/recovery_integration_test.go @@ -0,0 +1,165 @@ +//go:build linux + +package bridge + +import ( + "context" + "testing" + "time" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + a2apb "github.com/a2aproject/a2a-go/v2/a2apb/v1" + "github.com/a2aproject/a2a-go/v2/a2apb/v1/pbconv" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + + apia2a "github.com/kagent-dev/kagent/go/api/a2a" + apiv1alpha1 "github.com/kagent-dev/kagent/go/api/gen/kagent/api/v1alpha1" + "github.com/kagent-dev/kagent/go/harness/runtime/continuation" + "github.com/kagent-dev/kagent/go/pkg/tracing" +) + +func TestLostExecutionOwnerFailsWithoutChangingStoredTask(t *testing.T) { + for _, state := range []a2atype.TaskState{a2atype.TaskStateWorking, a2atype.TaskStateInputRequired} { + t.Run(string(state), func(t *testing.T) { + runner := testRunner(t, "") + store, err := continuation.New(t.TempDir(), "dsh-byo", ValidateSessionID) + require.NoError(t, err) + executor, err := NewExecutor(runner, store, tracing.RuntimeTelemetry{}) + require.NoError(t, err) + client, api := newSettlementClient(t, executor, nil) + task := &a2atype.Task{ID: a2atype.TaskID(uuid.NewString()), ContextID: uuid.NewString(), Status: a2atype.TaskStatus{State: state}} + if state == a2atype.TaskStateInputRequired { + task.Status.Message = a2atype.NewMessage(a2atype.MessageRoleAgent, a2atype.NewTextPart("Allow tool?")) + require.NoError(t, apia2a.AttachHITL(task.Status.Message, apia2a.ToolApprovalRequest{ + Type: apia2a.HITLTypeToolApprovalRequest, + Tools: []apia2a.HITLTool{{ID: "approval-1", CallID: "tool-1", Name: "write"}}, + })) + } + persisted, err := pbconv.ToProtoTask(task) + require.NoError(t, err) + // Simulate controller state surviving the loss of the runtime owner. + _, err = api.CreateTask(t.Context(), &apiv1alpha1.TaskStoreServiceCreateTaskRequest{Task: persisted}) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) + defer cancel() + for range 2 { + if state == a2atype.TaskStateWorking { + req, err := pbconv.ToProtoCancelTaskRequest(&a2atype.CancelTaskRequest{ID: task.ID}) + require.NoError(t, err) + _, err = client.CancelTask(ctx, req) + require.ErrorContains(t, err, "DSH task has no live execution owner") + } else { + decision := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("Approval decision")) + decision.TaskID, decision.ContextID = task.ID, task.ContextID + require.NoError(t, apia2a.AttachHITL(decision, apia2a.ToolApprovalResponse{ + Type: apia2a.HITLTypeToolApprovalResponse, + Approvals: []apia2a.ToolApproval{{ID: "approval-1", Approved: true}}, + })) + req, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: decision}) + require.NoError(t, err) + _, err = client.SendMessage(ctx, req) + require.ErrorContains(t, err, "DSH task has no live continuation owner") + } + require.NoError(t, ctx.Err(), "request must fail before its deadline") + } + get, err := pbconv.ToProtoGetTaskRequest(&a2atype.GetTaskRequest{ID: task.ID}) + require.NoError(t, err) + got, err := client.GetTask(ctx, get) + require.NoError(t, err) + require.True(t, proto.Equal(persisted, got), "do not append a decision or fabricate a task transition") + api.mu.Lock() + require.Equal(t, int64(1), api.tasks[string(task.ID)].Version) + require.Empty(t, api.settled, "unknown cleanup must never be settled") + api.mu.Unlock() + if state == a2atype.TaskStateInputRequired { + reply := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("continue")) + reply.TaskID, reply.ContextID = task.ID, task.ContextID + req, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: reply}) + require.NoError(t, err) + _, err = client.SendMessage(ctx, req) + require.ErrorContains(t, err, "DSH task has no live continuation owner") + got, err = client.GetTask(ctx, get) + require.NoError(t, err) + require.True(t, proto.Equal(persisted, got), "a plain reply must not change the waiting task") + api.mu.Lock() + defer api.mu.Unlock() + require.Equal(t, int64(1), api.tasks[string(task.ID)].Version, "reject plain replies before the SDK appends history") + require.Empty(t, api.settled) + } + }) + } +} + +func TestLiveApprovalThroughDSHExecutor(t *testing.T) { + for _, action := range []string{"allow", "reject", "cancel"} { + t.Run(action, func(t *testing.T) { + runner := testRunner(t, "approval") + store, err := continuation.New(t.TempDir(), "dsh-byo", ValidateSessionID) + require.NoError(t, err) + executor, err := NewExecutor(runner, store, tracing.RuntimeTelemetry{}) + require.NoError(t, err) + client, api := newSettlementClient(t, executor, nil) + ctx, cancel := context.WithTimeout(t.Context(), 30*time.Second) + defer cancel() + msg := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("work")) + request, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: msg}) + require.NoError(t, err) + first, err := client.SendMessage(ctx, request) + require.NoError(t, err) + task := first.GetTask() + require.NotNil(t, task) + require.Equal(t, a2apb.TaskState_TASK_STATE_INPUT_REQUIRED, task.Status.State) + t.Cleanup(func() { + cleanup, stop := context.WithTimeout(context.Background(), 15*time.Second) + defer stop() + req, err := pbconv.ToProtoCancelTaskRequest(&a2atype.CancelTaskRequest{ID: a2atype.TaskID(task.Id)}) + require.NoError(t, err) + // A completed task is already cleaned; only cancel a parked test turn. + if executor.ReservedTaskID() != "" { + _, err = client.CancelTask(cleanup, req) + require.NoError(t, err) + } + }) + select { + case <-api.settled: + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + req, err := pbconv.ToProtoCancelTaskRequest(&a2atype.CancelTaskRequest{ID: a2atype.TaskID(task.Id)}) + require.NoError(t, err) + if action == "cancel" { + canceled, err := client.CancelTask(ctx, req) + require.NoError(t, err) + require.Equal(t, a2apb.TaskState_TASK_STATE_CANCELED, canceled.Status.State) + } else { + nativeTask, err := pbconv.FromProtoTask(task) + require.NoError(t, err) + approval, err := apia2a.ParseToolApprovalRequest(nativeTask.Status.Message) + require.NoError(t, err) + require.NotNil(t, approval) + decision := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("Approval decision")) + decision.TaskID, decision.ContextID = nativeTask.ID, nativeTask.ContextID + require.NoError(t, apia2a.AttachHITL(decision, apia2a.ToolApprovalResponse{ + Type: apia2a.HITLTypeToolApprovalResponse, + Approvals: []apia2a.ToolApproval{{ID: approval.Tools[0].ID, Approved: action == "allow"}}, + })) + request, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: decision}) + require.NoError(t, err) + completed, err := client.SendMessage(ctx, request) + require.NoError(t, err) + require.Equal(t, a2apb.TaskState_TASK_STATE_COMPLETED, completed.GetTask().Status.State) + } + select { + case <-api.settled: + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + _, err = client.CancelTask(ctx, req) + require.NotEqual(t, codes.DeadlineExceeded, status.Code(err)) + }) + } +} diff --git a/go/harness/byo/dsh/internal/bridge/settlement_integration_test.go b/go/harness/byo/dsh/internal/bridge/settlement_integration_test.go index eb87b935a2..4a6f7a26ec 100644 --- a/go/harness/byo/dsh/internal/bridge/settlement_integration_test.go +++ b/go/harness/byo/dsh/internal/bridge/settlement_integration_test.go @@ -35,7 +35,6 @@ import ( apia2a "github.com/kagent-dev/kagent/go/api/a2a" apiv1alpha1 "github.com/kagent-dev/kagent/go/api/gen/kagent/api/v1alpha1" "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" - runtimea2a "github.com/kagent-dev/kagent/go/harness/runtime/a2a" "github.com/kagent-dev/kagent/go/harness/runtime/continuation" "github.com/kagent-dev/kagent/go/pkg/tracing" ) @@ -127,7 +126,11 @@ func newSettlementClient(t *testing.T, executor a2asrv.AgentExecutor, check func t.Cleanup(func() { require.NoError(t, controller.Close()) }) tasks := taskstore.New(controller, filepath.Join(identityDir, "name")) wrapped := tasks.WrapExecutor(executor, "", nil) - handler := a2asrv.NewHandler(wrapped, a2asrv.WithTaskStore(tasks), a2asrv.WithCallInterceptors(adka2a.HITLActivationInterceptor(), adka2a.UserIDCallInterceptor(), wrapped)) + opts := []a2asrv.RequestHandlerOption{a2asrv.WithTaskStore(tasks), a2asrv.WithCallInterceptors(adka2a.HITLActivationInterceptor(), adka2a.UserIDCallInterceptor(), wrapped)} + if interceptor, ok := executor.(a2asrv.CallInterceptor); ok { + opts = append(opts, a2asrv.WithCallInterceptors(interceptor)) + } + handler := a2asrv.NewHandler(wrapped, opts...) listener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) server := grpc.NewServer() @@ -159,7 +162,7 @@ func TestSettlementWaitsForDetachedToolCleanup(t *testing.T) { require.NoError(t, err) store, err := continuation.New(filepath.Join(dir, "data", "adapter"), "dsh-byo", ValidateSessionID) require.NoError(t, err) - executor, err := runtimea2a.New(runner, store, tracing.RuntimeTelemetry{}) + executor, err := NewExecutor(runner, store, tracing.RuntimeTelemetry{}) require.NoError(t, err) client, api := newSettlementClient(t, executor, func(*a2apb.Task) error { for _, path := range []string{pidFile, pidFile + ".dsh"} { From 9da08187cd70793d3b08280563105dce81831c5e Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 19:22:00 +0800 Subject: [PATCH 10/12] fix(dsh): explain failed approvals after process exit Report a specific failed outcome when process cleanup is already confirmed before an approval decision. Verify with real DSH SIGKILL fault injection that allow, reject and cancel settle the old task and a new task continues in the same session without replaying the pending tool. Document the surviving-adapter requirement. AI assistance: implementation and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 15 ++ .../bridge/fault_recovery_integration_test.go | 194 ++++++++++++++++++ go/harness/byo/dsh/internal/bridge/runner.go | 25 ++- .../byo/dsh/internal/bridge/runner_test.go | 20 ++ 4 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 go/harness/byo/dsh/internal/bridge/fault_recovery_integration_test.go diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index 406ed70131..c9b3412c2a 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -100,6 +100,15 @@ state. Continue completed work with a new A2A task in the same conversation. These guards do not replay prompts or apply approvals after ownership is lost; they provide explicit failure, not automatic approval recovery. +If only the DSH subprocess exits while awaiting approval, the surviving adapter +still owns the pending task and its cleanup confirmation. A later approval or +rejection ends that task as failed; cancellation ends it as canceled. Once the +terminal state is published, send a new message without the old task ID in the +same conversation. The adapter resumes the native session for the new task. +This does not apply the lost approval or replay the interrupted tool. It requires +a subsequent request; there is no background task-recovery worker. Losing the +adapter or the cleanup confirmation still requires the recovery work above. + The local tests verify recovery after a DSH process restart. Cluster acceptance also covers conversation and workspace continuity across automatic suspension and explicit suspend/resume; Actor replacement and fork remain unverified. @@ -172,6 +181,12 @@ runtime identity headers and versioned settlement without provider credentials. Separate process tests require DSH and detached tools to exit before settlement on normal completion, forced cleanup and cancellation. +A real-DSH fault test kills the process with SIGKILL while a tool awaits approval. +It checks that allow/reject/cancel can settle the old task after cleanup, a new +task completes in the same native session and A2A context, and the interrupted +tool's marker file is never created. The adapter remains alive throughout this +test; it does not establish recovery after Actor or adapter replacement. + The durable-workspace test creates, reads and edits a file with DSH's built-in tools across three fresh adapter instances. It verifies that the native session identity, conversation history and workspace contents survive reconstruction diff --git a/go/harness/byo/dsh/internal/bridge/fault_recovery_integration_test.go b/go/harness/byo/dsh/internal/bridge/fault_recovery_integration_test.go new file mode 100644 index 0000000000..d92cc320a4 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/fault_recovery_integration_test.go @@ -0,0 +1,194 @@ +//go:build linux + +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "syscall" + "testing" + "time" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + a2apb "github.com/a2aproject/a2a-go/v2/a2apb/v1" + "github.com/a2aproject/a2a-go/v2/a2apb/v1/pbconv" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + apia2a "github.com/kagent-dev/kagent/go/api/a2a" + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/runtime/continuation" + "github.com/kagent-dev/kagent/go/pkg/tracing" +) + +// Losing DSH is different from losing the adapter: the live adapter still owns +// the pending task and can confirm process cleanup before settling its failure. +func TestRealDSHApprovalProcessDeathAllowsNextTask(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("DSH_TEST_BIN required") + } + for _, action := range []string{"allow", "reject", "cancel"} { + t.Run(action, func(t *testing.T) { + dir := t.TempDir() + pidFile, marker := filepath.Join(dir, "dsh.pid"), filepath.Join(dir, "executed") + quote := func(s string) string { return "'" + strings.ReplaceAll(s, "'", "'\\''") + "'" } + script := filepath.Join(dir, "dsh") + require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nprintf '%s' \"$$\" > "+quote(pidFile)+"\nexec "+quote(executable)+" \"$@\"\n"), 0700)) + var mu sync.Mutex + var requests []json.RawMessage + model := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var body json.RawMessage + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, "bad request", 400) + return + } + mu.Lock() + requests = append(requests, body) + index := len(requests) + mu.Unlock() + if index == 1 { + args, _ := json.Marshal(map[string]string{ + "command": "printf executed >> " + quote(marker), + "description": "Write a test marker only after approval", + "sandbox_permissions": "danger-full-access", + "justification": "Exercise a pending approval with a local test file.", + }) + writeCompletion(w, map[string]any{"role": "assistant", "tool_calls": []any{map[string]any{ + "index": 0, "id": "pending-write", "type": "function", + "function": map[string]string{"name": "bash", "arguments": string(args)}, + }}}, "tool_calls") + return + } + writeCompletion(w, map[string]string{"role": "assistant", "content": "continued after process loss"}, "stop") + })) + defer model.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock","base_url":%q},"runtime":{"control_plane_url":"http://controller:8083"}}`, model.URL+"/v1"))) + require.NoError(t, err) + dataDir := filepath.Join(dir, "data") + runner, err := New(cfg, script, dataDir, append(os.Environ(), "OPENAI_API_KEY=mock", "DSH_PERMISSION_MODE=workspace-write")) + require.NoError(t, err) + store, err := continuation.New(filepath.Join(dataDir, "adapter"), "dsh-byo", ValidateSessionID) + require.NoError(t, err) + executor, err := NewExecutor(runner, store, tracing.RuntimeTelemetry{}) + require.NoError(t, err) + client, api := newSettlementClient(t, executor, func(task *a2apb.Task) error { + if task.Status.State == a2apb.TaskState_TASK_STATE_INPUT_REQUIRED { + return nil + } + data, err := os.ReadFile(pidFile) + if err != nil { + return err + } + pid, err := strconv.Atoi(string(data)) + if err != nil { + return err + } + if syscall.Kill(pid, 0) != syscall.ESRCH { + return fmt.Errorf("DSH still exists at settlement") + } + if _, err := os.Stat(marker); !os.IsNotExist(err) { + return fmt.Errorf("unapproved tool may have executed: %v", err) + } + return nil + }) + t.Cleanup(func() { + if id := executor.ReservedTaskID(); id != "" { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + req, err := pbconv.ToProtoCancelTaskRequest(&a2atype.CancelTaskRequest{ID: id}) + require.NoError(t, err) + _, err = client.CancelTask(ctx, req) + require.NoError(t, err) + } + }) + ctx, cancel := context.WithTimeout(t.Context(), 60*time.Second) + defer cancel() + contextID := uuid.NewString() + message := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("Request the guarded marker write.")) + message.ContextID = contextID + request, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: message}) + require.NoError(t, err) + first, err := client.SendMessage(ctx, request) + require.NoError(t, err) + task, err := pbconv.FromProtoTask(first.GetTask()) + require.NoError(t, err) + require.Equal(t, a2atype.TaskStateInputRequired, task.Status.State) + select { + case <-api.settled: + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + nativeID, bound, err := store.Load() + require.NoError(t, err) + require.True(t, bound) + data, err := os.ReadFile(pidFile) + require.NoError(t, err) + pid, err := strconv.Atoi(string(data)) + require.NoError(t, err) + require.NoError(t, syscall.Kill(pid, syscall.SIGKILL)) + require.Eventually(t, func() bool { return syscall.Kill(pid, 0) == syscall.ESRCH }, 5*time.Second, 10*time.Millisecond) + want := a2apb.TaskState_TASK_STATE_FAILED + if action == "cancel" { + want = a2apb.TaskState_TASK_STATE_CANCELED + request, err := pbconv.ToProtoCancelTaskRequest(&a2atype.CancelTaskRequest{ID: task.ID}) + require.NoError(t, err) + result, err := client.CancelTask(ctx, request) + require.NoError(t, err) + require.Equal(t, want, result.Status.State) + } else { + approval, err := apia2a.ParseToolApprovalRequest(task.Status.Message) + require.NoError(t, err) + require.NotNil(t, approval) + decision := a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("Approval decision")) + decision.TaskID, decision.ContextID = task.ID, contextID + require.NoError(t, apia2a.AttachHITL(decision, apia2a.ToolApprovalResponse{ + Type: apia2a.HITLTypeToolApprovalResponse, + Approvals: []apia2a.ToolApproval{{ID: approval.Tools[0].ID, Approved: action == "allow"}}, + })) + request, err := pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: decision}) + require.NoError(t, err) + result, err := client.SendMessage(ctx, request) + require.NoError(t, err) + require.Equal(t, want, result.GetTask().Status.State) + } + select { + case settled := <-api.settled: + require.Equal(t, want, settled.Status.State) + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + message = a2atype.NewMessage(a2atype.MessageRoleUser, a2atype.NewTextPart("Continue without executing the interrupted tool.")) + message.ContextID = contextID + request, err = pbconv.ToProtoSendMessageRequest(&a2atype.SendMessageRequest{Message: message}) + require.NoError(t, err) + next, err := client.SendMessage(ctx, request) + require.NoError(t, err) + require.Equal(t, a2apb.TaskState_TASK_STATE_COMPLETED, next.GetTask().Status.State) + require.NotEqual(t, string(task.ID), next.GetTask().Id) + require.Equal(t, contextID, next.GetTask().ContextId) + select { + case <-api.settled: + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + resumedID, _, err := store.Load() + require.NoError(t, err) + require.Equal(t, nativeID, resumedID) + _, err = os.Stat(marker) + require.True(t, os.IsNotExist(err), "pending tool must never be replayed") + mu.Lock() + defer mu.Unlock() + require.Len(t, requests, 2, "answering the lost approval must not start another model turn") + require.Contains(t, string(requests[1]), "Request the guarded marker write.") + }) + } +} diff --git a/go/harness/byo/dsh/internal/bridge/runner.go b/go/harness/byo/dsh/internal/bridge/runner.go index 0b163d5f6c..b78030b0a8 100644 --- a/go/harness/byo/dsh/internal/bridge/runner.go +++ b/go/harness/byo/dsh/internal/bridge/runner.go @@ -309,15 +309,23 @@ var _ runtime.PendingTurn = (*pending)(nil) func (p *pending) Request() runtime.InputRequest { return p.request } func (p *pending) Resume(ctx context.Context, response runtime.InputResponse, sink runtime.EventSink) (out runtime.Outcome, returnErr error) { + decision, ok := response.(*runtime.ApprovalDecision) + if !ok || decision.ID != p.request.ID { + return out, errors.Join(fmt.Errorf("approval decision does not match pending DSH request"), p.process.stop()) + } + select { + case <-p.process.done: + // done closes only after the supervisor confirms descendant cleanup. + // The exit is the failure we report, so preserve cleanup errors without + // replacing this actionable outcome with the expected process exit error. + return runtime.Outcome{Failure: &runtime.Failure{Message: "DSH exited while awaiting approval. The approval could not be applied. Send a new message in this conversation to continue."}}, p.process.cleanup() + default: + } defer func() { if out.Pending == nil { returnErr = errors.Join(returnErr, p.process.stop()) } }() - decision, ok := response.(*runtime.ApprovalDecision) - if !ok || decision.ID != p.request.ID { - return out, fmt.Errorf("approval decision does not match pending DSH request") - } option := p.reject if decision.Approved { option = p.allow @@ -367,6 +375,13 @@ func (p *process) cancel() error { // EOF lets DSH flush persistence. After the grace period, the supervisor kills // DSH and reaps all descendants, including tools in separate process groups. func (p *process) stop() error { + err := p.cleanup() + return errors.Join(err, p.waitErr) +} + +// cleanup always waits for confirmed process-tree cleanup. The caller decides +// whether a nonzero exit is an error or an already classified failed outcome. +func (p *process) cleanup() error { close(p.wire.done) err := p.stdin.Close() if errors.Is(err, os.ErrClosed) || errors.Is(err, io.ErrClosedPipe) { @@ -387,5 +402,5 @@ func (p *process) stop() error { if p.mcp != nil { err = errors.Join(err, p.mcp.close()) } - return errors.Join(err, p.waitErr, os.RemoveAll(p.home)) + return errors.Join(err, os.RemoveAll(p.home)) } diff --git a/go/harness/byo/dsh/internal/bridge/runner_test.go b/go/harness/byo/dsh/internal/bridge/runner_test.go index 4b5d84d8f0..48e6268f88 100644 --- a/go/harness/byo/dsh/internal/bridge/runner_test.go +++ b/go/harness/byo/dsh/internal/bridge/runner_test.go @@ -74,6 +74,26 @@ func TestPermissionResumeAndCancel(t *testing.T) { } } +func TestApprovalAfterConfirmedProcessExitExplainsRecovery(t *testing.T) { + runner := testRunner(t, "approval") + sink := &recordingSink{} + out, err := runner.Run(t.Context(), runtime.Turn{Prompt: "work"}, sink) + require.NoError(t, err) + p := out.Pending.(*pending) + require.NoError(t, p.process.control.Close()) + select { + case <-p.process.done: + case <-time.After(10 * time.Second): + t.Fatal("process cleanup was not confirmed") + } + out, err = p.Resume(t.Context(), &runtime.ApprovalDecision{ID: p.request.ID, Approved: true}, sink) + require.NoError(t, err, "the known process exit is represented by the failed outcome") + require.Nil(t, out.Pending) + require.NotNil(t, out.Failure) + require.Contains(t, out.Failure.Message, "DSH exited while awaiting approval") + require.Contains(t, out.Failure.Message, "Send a new message") +} + func TestActiveCancellationReapsProcessAndAllowsNextTurn(t *testing.T) { r := testRunner(t, "hang") ctx, cancel := context.WithCancel(t.Context()) From cfbd2e238e9144fc3eaae5013cc8f650e7855705 Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Wed, 14 Oct 2026 19:39:53 +0800 Subject: [PATCH 11/12] test(dsh): verify pending call behavior after restart Verify with pinned DSH that session resume records an interrupted tool outcome without restoring its pending approval or running the command. Document the difference between this safety regression and durable approval continuation, and clarify adoption conditions for kagent #3010, #3011 and #3165. AI assistance: implementation and validation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/README.md | 13 ++ .../byo/dsh/internal/bridge/executor.go | 8 ++ .../pending_restart_integration_test.go | 114 ++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 go/harness/byo/dsh/internal/bridge/pending_restart_integration_test.go diff --git a/go/harness/byo/dsh/README.md b/go/harness/byo/dsh/README.md index c9b3412c2a..2e3973ee6f 100644 --- a/go/harness/byo/dsh/README.md +++ b/go/harness/byo/dsh/README.md @@ -68,6 +68,9 @@ As a temporary DSH-only mitigation, cancellation with no live execution owner returns an explicit `TASK_NOT_CANCELABLE` error instead of waiting indefinitely. It leaves the stored task unchanged; it does not certify cleanup or unblock the session's lifecycle operations. +[kagent #3011](https://github.com/kagent-dev/kagent/pull/3011) addresses the shared +executor's empty cancel response. Its missing-owner cancellation does not confirm +DSH descendant cleanup, so merging it alone is not sufficient to remove this guard. Uninterruptible kernel I/O can also delay cleanup. This is not a guarantee against simultaneous process kills or malicious same-UID tools. @@ -93,6 +96,10 @@ from a DATA-only snapshot or process replacement. The shared durable-input work in [kagent #3165](https://github.com/kagent-dev/kagent/pull/3165) is a migration dependency, but DSH must also support resuming the exact pending call without replaying a tool before this adapter can adopt that recovery path. +In DSH 0.2.0-rc.2, native session resume closes the interrupted call with an +unknown-outcome tool result. The approval audit log does not reconstruct the +execution point or the ACP permission response. Saving its request ID and +reissuing the original prompt would therefore not implement approval recovery. Until then, the DSH adapter accepts a send referencing an existing task only when that task owns the live pending approval. It rejects both approval decisions and plain replies to a lost task before the SDK appends history or changes task @@ -187,6 +194,12 @@ task completes in the same native session and A2A context, and the interrupted tool's marker file is never created. The adapter remains alive throughout this test; it does not establish recovery after Actor or adapter replacement. +`TestRealDSHRestartClosesPendingCallWithoutReplay` reconstructs the runner from +the durable directory after terminating DSH without a permission response. It +checks that native resume records an unknown outcome for the original call and +does not execute its command. This is a regression check for safe interruption; +it is not a passing test for durable approval continuation. + The durable-workspace test creates, reads and edits a file with DSH's built-in tools across three fresh adapter instances. It verifies that the native session identity, conversation history and workspace contents survive reconstruction diff --git a/go/harness/byo/dsh/internal/bridge/executor.go b/go/harness/byo/dsh/internal/bridge/executor.go index 208667ce6a..f9a49230ba 100644 --- a/go/harness/byo/dsh/internal/bridge/executor.go +++ b/go/harness/byo/dsh/internal/bridge/executor.go @@ -38,6 +38,10 @@ func NewExecutor(runner *Runner, store runtimea2a.ContinuationStore, telemetry t // append can settle a stored input-required task before Executor.Execute runs. // TODO: replace this rejection with exact pending-call recovery once // https://github.com/kagent-dev/kagent/pull/3165 and DSH support that contract. +// Adoption requires restoring the native execution point, not just the session +// ID: DSH 0.2.0-rc.2 closes interrupted calls with an unknown-outcome result on +// resume. Decisions must be bound to that saved call, and execution with an +// uncommitted result must not be replayed automatically. func (e *Executor) Before(ctx context.Context, _ *a2asrv.CallContext, request *a2asrv.Request) (context.Context, any, error) { if send, ok := request.Payload.(*a2atype.SendMessageRequest); ok && send.Message != nil { message := send.Message @@ -55,6 +59,10 @@ func (e *Executor) Before(ctx context.Context, _ *a2asrv.CallContext, request *a // CANCELED: an absent owner is not proof that its tools have stopped. // TODO: adopt fenced task recovery from // https://github.com/kagent-dev/kagent/issues/3010 when it becomes available. +// https://github.com/kagent-dev/kagent/pull/3011 addresses the empty cancel +// iterator, but its missing-owner CANCELED result does not establish cleanup of +// DSH descendants. Remove this guard only when the shared path confirms that +// cleanup, including an unreachable/replaced Actor and unpublished boundaries. func (e *Executor) Cancel(ctx context.Context, input *a2asrv.ExecutorContext) iter.Seq2[a2atype.Event, error] { return func(yield func(a2atype.Event, error) bool) { emitted := false diff --git a/go/harness/byo/dsh/internal/bridge/pending_restart_integration_test.go b/go/harness/byo/dsh/internal/bridge/pending_restart_integration_test.go new file mode 100644 index 0000000000..ab30e974e3 --- /dev/null +++ b/go/harness/byo/dsh/internal/bridge/pending_restart_integration_test.go @@ -0,0 +1,114 @@ +//go:build linux + +package bridge + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/kagent-dev/kagent/go/harness/byo/dsh/internal/config" + "github.com/kagent-dev/kagent/go/harness/runtime" +) + +// Session resume repairs an interrupted turn; it does not restore its pending +// approval. Keep this capability probe separate from approval-resume acceptance. +func TestRealDSHRestartClosesPendingCallWithoutReplay(t *testing.T) { + executable := os.Getenv("DSH_TEST_BIN") + if executable == "" { + t.Skip("DSH_TEST_BIN required") + } + dir := t.TempDir() + marker := filepath.Join(dir, "must-not-execute") + var mu sync.Mutex + var requests []json.RawMessage + model := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var body json.RawMessage + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + http.Error(w, "invalid request", http.StatusBadRequest) + return + } + mu.Lock() + requests = append(requests, body) + index := len(requests) + mu.Unlock() + if index == 1 { + args, _ := json.Marshal(map[string]string{ + "command": "printf executed >> '" + strings.ReplaceAll(marker, "'", "'\\''") + "'", + "description": "Write after approval", "sandbox_permissions": "danger-full-access", + "justification": "Check approval persistence with a test marker.", + }) + writeCompletion(w, map[string]any{"role": "assistant", "tool_calls": []any{map[string]any{ + "index": 0, "id": "interrupted-write", "type": "function", + "function": map[string]string{"name": "bash", "arguments": string(args)}, + }}}, "tool_calls") + return + } + writeCompletion(w, map[string]string{"role": "assistant", "content": "The old call was interrupted."}, "stop") + })) + defer model.Close() + cfg, err := config.Parse([]byte(fmt.Sprintf(`{"model":{"type":"openai","model":"mock","base_url":%q},"runtime":{"control_plane_url":"http://controller:8083"}}`, model.URL+"/v1"))) + require.NoError(t, err) + environment := append(os.Environ(), "OPENAI_API_KEY=mock", "DSH_PERMISSION_MODE=workspace-write") + runner, err := New(cfg, executable, dir, environment) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 45*time.Second) + defer cancel() + first := &recordingSink{} + out, err := runner.Run(ctx, runtime.Turn{Prompt: "Request the guarded write."}, first) + require.NoError(t, err) + pending, ok := out.Pending.(*pending) + require.True(t, ok) + require.Equal(t, "interrupted-write", pending.request.CallID) + cleanup := sync.OnceValue(pending.process.cleanup) + t.Cleanup(func() { _ = cleanup() }) + // Terminate without sending any permission response or session/cancel. + require.NoError(t, pending.process.control.Close()) + select { + case <-pending.process.done: + case <-ctx.Done(): + t.Fatal(ctx.Err()) + } + require.NoError(t, cleanup()) + + // A fresh adapter can only provide the durable native session ID. It has + // no original ACP promise, request ID, or in-memory PendingTurn to resume. + runner, err = New(cfg, executable, dir, environment) + require.NoError(t, err) + resumed := &recordingSink{} + out, err = runner.Run(ctx, runtime.Turn{Prompt: "Explain the interrupted call without retrying it.", ContinuationID: first.id}, resumed) + require.NoError(t, err) + require.Nil(t, out.Pending, "native resume did not restore the permission request") + require.Equal(t, first.id, resumed.id) + _, err = os.Stat(marker) + require.True(t, os.IsNotExist(err), "unapproved command must not execute") + mu.Lock() + defer mu.Unlock() + require.Len(t, requests, 2) + var second struct { + Messages []struct { + Role string `json:"role"` + ToolCallID string `json:"tool_call_id"` + Content string `json:"content"` + } `json:"messages"` + } + require.NoError(t, json.Unmarshal(requests[1], &second)) + var result string + for _, message := range second.Messages { + if message.Role == "tool" && message.ToolCallID == "interrupted-write" { + result = message.Content + } + } + require.Contains(t, result, "outcome is unknown") + require.Contains(t, result, "Do not retry blindly") +} From fbcc1672494fef2a7d1f2df94bb1cd17cadb7894 Mon Sep 17 00:00:00 2001 From: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> Date: Thu, 15 Oct 2026 13:10:14 +0800 Subject: [PATCH 12/12] docs(dsh): clarify shared recovery prerequisites Record that Go ADK reproduces the shared unpublished-boundary failure and that a deletion escape does not establish pending-call recovery or safe missing-owner cancellation. AI assistance: documentation assisted by OpenAI Codex. Signed-off-by: Junfeng Yu <64075563+Jacob953@users.noreply.github.com> --- go/harness/byo/dsh/internal/bridge/executor.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/go/harness/byo/dsh/internal/bridge/executor.go b/go/harness/byo/dsh/internal/bridge/executor.go index f9a49230ba..4510416e7b 100644 --- a/go/harness/byo/dsh/internal/bridge/executor.go +++ b/go/harness/byo/dsh/internal/bridge/executor.go @@ -63,6 +63,9 @@ func (e *Executor) Before(ctx context.Context, _ *a2asrv.CallContext, request *a // iterator, but its missing-owner CANCELED result does not establish cleanup of // DSH descendants. Remove this guard only when the shared path confirms that // cleanup, including an unreachable/replaced Actor and unpublished boundaries. +// Go ADK also reproduces #3010 case B through the shared TaskStore; this is not +// a DSH-only failure. Allowing Session deletion only provides an escape hatch: +// it does not recover a pending ACP call or make missing-owner cancellation safe. func (e *Executor) Cancel(ctx context.Context, input *a2asrv.ExecutorContext) iter.Seq2[a2atype.Event, error] { return func(yield func(a2atype.Event, error) bool) { emitted := false