deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
A DeepSeek Harness plugin that connects to a
NebulaGraph v5 server and executes ISO-GQL statements, in the spirit of
the ngql console.
The plugin speaks the native NebulaGraph v5 wire protocol (gRPC +
nebula.proto.graph.GraphService) with a pure-JS client — no native
modules, no external gateway. Results come back as structured JSON rows plus
an ngql-style ASCII table render.
nebula_connect), execute GQL on
the same server-side session (nebula_execute), and close it
(nebula_disconnect).prod Nebula" and calls
nebula_connect(instance: "prod"); the profile supplies the parameters.
An instance can be marked as the default, used when no alias is given.
Per-call tool arguments still override the profile.VectorResultTable payload exactly like the official
nebula-go v5 client: scalars, strings, temporal values, lists, sets, maps,
records, vertices, edges, paths, embedding vectors, geography, Any-typed
columns, const vectors, and null bitmaps.nebula_schema): one call runs SHOW GRAPHS,
resolves the target graph (explicit graph= argument, the session working
graph from SESSION SET graph, or the sole graph), then DESC GRAPH TYPE
and returns the graph type's node types and edge types — labels,
primary/multiedge keys, and properties. Read-only: the session working graph
is never changed.nebula_execute result
contains nodes, edges, or paths, the result is projected into a replayable
graph payload and the bundled Web Client plugin renders it as an interactive
AntV G6 graph (drag / zoom / hover),
alongside the normal table output. gql-query-generator skill: the plugin registers a
ctx.skills provider so the agent's skill tool can load NebulaGraph
GQL-writing guidance (reference docs ship in gql-query-generator/references/
and resolve against the packaged directory).nebula_connect takes a
passwordRef (a credential reference / environment variable name), not the
password value. The value is resolved per connection through the DSH
credentials seam (ctx.credentials, falling back to the process
environment) and cleared from memory right after authentication. Tool
arguments, output, and the registry never carry the plaintext.tls: "auto", the default) and fall back to plaintext only when the server
has no TLS listener — the fallback is reported to the caller as a warning.
Set tls: "on" to require TLS (fails if the server does not speak it) or
tls: "off" to force plaintext. CA / client certificate / key / server name
overrides are configurable for private CAs and mutual TLS.| Tool | Purpose |
|---|---|
nebula_connect |
Connect to a graphd and open a session. Arguments: instance (alias of a profile configured in Settings → NebulaGraph), host, port, user, passwordRef, tls, ca, timeoutMs (all optional). Resolution order: explicit instance alias → the default instance (if set) → plugin config; per-call arguments override the profile. The password itself is never an argument — it resolves from passwordRef via the DSH credentials seam / environment. Returns a connectionId (plus instance, viaDefault, warning, and tlsFallback when relevant). |
nebula_execute |
Run one GQL statement on a connection. Arguments: connectionId (required), gql (required), timeoutMs. Returns { ok, columns, rows, numRows, latencyUs, summary?, error? }. |
nebula_schema |
Introspect a graph's schema. Arguments: connectionId (required), graph (optional — defaults to the session working graph, then the sole graph). Runs SHOW GRAPHS + DESC GRAPH TYPE, returns { graphs, graph, nodes, edges, … }. Read-only. |
nebula_disconnect |
Close a connection and release its server-side session. |
The plugin registers a bundled skill provider on ctx.skills named
dsh-nebula that serves the gql-query-generator skill from the packaged
gql-query-generator/ directory. The model can load it through the skill
tool (or a direct user invocation); its references/*.md resolve against the
packaged directory via the skill's resourceBase. The skill body is read
from disk on each load, so editing SKILL.md takes effect without a rebuild
for link-installed plugins.
Typical agent flow:
nebula_connect (host: 192.168.8.6, port: 9669, user: root, passwordRef: NEBULA_PASSWORD)
→ { connectionId: "…", tlsFallback: false }
nebula_execute (connectionId, gql: "SHOW GRAPHS")
nebula_schema (connectionId, graph: "movie")
→ { graphs: […], graph: { name: "movie", graphType: "movie_type", … },
nodes: [ { name: "Actor", labels: [Person], primaryKey: [id], … } ],
edges: [ { name: "Act", source: "Actor", target: "Movie", … } ] }
nebula_execute (connectionId, gql: "SESSION SET graph movie")
nebula_execute (connectionId, gql: "MATCH (n) RETURN n LIMIT 5")
nebula_disconnect (connectionId)
The plugin is an out-of-tree DSH bundle: a plain npm package whose manifest
declares a dsh.bundle patch. Any DSH installation can install it in one
command, from any of these sources (the release tarball is the smoothest):
Runtime compatibility. This revision targets the dsh 0.2.0-rc.2 runtime generation (all
@deepseek-ai/dsh-*packages were unified on that version, and dsh-settings 0.2.0 replaced the settings-namespace API with schema-derived entry forms). The profile loader refuses to mount a bundle whosepeerDependenciesdo not accept the running dsh version; install an older dsh-nebula revision (or its release tarball) for a pre-0.2.0 runtime instead of forcing the gate open withdsh plugin allow-version.
# recommended — the latest release's prebuilt tarball (stable URL, always current)
dsh plugin --profile web add https://github.com/xiajingchun/dsh-nebulagraph-v5/releases/latest/download/dsh-nebula.tgz
# a specific release (versioned, reproducible)
dsh plugin --profile web add https://github.com/xiajingchun/dsh-nebulagraph-v5/releases/download/v0.2.0/dsh-nebula-0.2.0.tgz
# from the npm registry (once published)
dsh plugin --profile web add dsh-nebula
# straight from the git repository (builds from source — see note below)
dsh plugin --profile web add github:xiajingchun/dsh-nebulagraph-v5#v0.2.0
# from a local tarball / checkout while developing
dsh plugin --profile web add /path/to/dsh-nebula-0.2.0.tgz
dsh plugin --profile web add link:/path/to/dsh-nebula
The release tarballs are the pnpm pack output: prebuilt lib/, so the
release and registry installs need no install-time build and no build-script
approval. This runs pnpm add in the profile directory, then appends
dsh-nebula to dsh.profile.bundles because the package declares a
dsh.bundle patch (cordis.patch.yml inserts the plugin row). Restart the
profile (dsh web) for the new bundle to mount.
Git installs build from source. pnpm fetches sources, not built artifacts: it runs the package's
preparescript (herepnpm build), which needs the dev toolchain, and pnpm ≥10 refuses to run that script until it is explicitly allowed — the firstaddfails and prints the package key. Copy that key underallowBuildsin the profile'spnpm-workspace.yamland re-run. Prefer the release tarball or registry installs to avoid this, and pin a commit (github:…/#<sha>) if you do install from git.
nodeLinker: hoisted profiles must approve the protobufjs build script (the
shipped web profile already does).
Every *`vtag push** triggers the GitHub Actions workflow ([.github/workflows/release.yml](.github/workflows/release.yml)): it verifies the tag matchespackage.json's version, installs, runs the tests, packs, and uploads both the versioneddsh-nebula-and a stable dsh-nebula.tgzalias to the release — so releases/latest/download/dsh-nebula.tgz` always points at the newest build:
git tag v0.2.0 && git push origin v0.2.0
Manually (same result, no CI):
pnpm build && pnpm pack # → dsh-nebula-0.2.0.tgz
# attach the tarball to a GitHub release (optionally also as dsh-nebula.tgz)
For an npm release instead:
npm login # once
pnpm publish # runs build + tests via prepublishOnly
The tarball (pnpm pack → dsh-nebula-0.2.0.tgz) is fully self-contained:
compiled lib/, vendored protos, the packaged gql-query-generator/ skill
(including its .feature evidence files), cordis.patch.yml, README, and
LICENSE. It was verified by installing the tarball into a fresh throwaway
profile: the bundle joins dsh.profile.bundles, the module resolves, and the
skill provider lists/loads gql-query-generator with its resource base inside
the installed package.
Plugin config lives in the profile's patch layer (e.g.
~/.dsh/profiles/web/cordis.patch.yml):
- insert:
- id: nebula
name: dsh-nebula
config:
host: 127.0.0.1
port: 9669
user: root
passwordRef: NEBULA_PASSWORD # preferred: credential reference (env var name)
tls: auto # auto | on | off
timeoutMs: 30000
maxConnections: 5
| Field | Default | Meaning |
|---|---|---|
host |
127.0.0.1 |
Default graphd host. |
port |
9669 |
Default graphd gRPC port. |
user |
root |
Default login user name. |
passwordRef |
(none) | Credential reference (environment variable name) resolving to the default password via the DSH credentials seam. Preferred over password — the value never appears in config surfaces, tool arguments, or logs. |
password |
'' |
Default login password (plaintext). Fallback used only when passwordRef is unset; keep it out of shared config files. |
tls |
'auto' |
TLS mode: auto (try TLS, fall back to plaintext when the server has no TLS listener), on (require TLS), off (plaintext only). |
ca |
(none) | CA bundle (PEM) for verifying the server certificate (private / self-signed CAs). |
cert / key |
(none) | Client certificate and private key (PEM) for mutual TLS. The key is config-only and never exposed as a tool argument. |
servername |
(none) | Override the server name used for SNI and certificate verification. |
timeoutMs |
30000 |
Default per-request deadline (ms). |
maxConnections |
5 |
Upper bound on concurrently open connections. |
To use a passwordRef, store the value in the DSH credentials document
(~/.dsh/.credentials.yaml, mode 0600) or the process environment, e.g.:
# ~/.dsh/.credentials.yaml
NEBULA_PASSWORD: s3cr3t
The password is resolved per connection at nebula_connect time and cleared
from memory immediately after authentication succeeds.
When the profile composes a settings provider (the Web GUI does), the plugin
owns a Settings → NebulaGraph page. There you can:
_/-,
≤ 64 chars), host, port, user, passwordRef, TLS mode, per-instance
CA / client cert / key / servername, timeoutMs, and a note.passwordRefs from the same
page: every reference the instances name (plus extra references you add,
e.g. the plugin-config default's) gets a write-only password field and a
clear button. Values are written through the harness credentials RPC
(credentials.set / credentials.unset) and persisted to the DSH
credentials document (~/.dsh/.credentials.yaml). The page only ever shows
whether a value is configured — never the value itself — and inputs always
start blank.passwordRef
(credential reference / environment variable name) is stored, and it is
resolved through the DSH credentials seam at connect time like the
plugin-config default.Since dsh-settings 0.2.0 the section is stored in the plugin's own profile
entry (the instances, defaultInstance, and credentialRefs fields of the
nebula row in cordis.patch.yml) rather than in a separate settings
document: dsh derives each entry's editable form from its Config schema, and
only volatile fields are live-editable, so those three fields are declared
.volatile() there. The plugin registers the page with
settings.configure({ auto: false }) to opt out of the schema-derived
automatic page. Upgrading a pre-0.2.0 installation therefore needs a one-time
move of the old dsh-nebula: section from ~/.dsh/settings.yaml (renamed
settings.yaml.imported by the runtime) into the nebula entry's config:
block; the plugin's instances/defaultInstance/credentialRefs field names
match the old section keys, so the values copy verbatim.
nebula_connect resolution order:
instance: <alias> — an unknown alias is a hard error that lists
the configured aliases;viaDefault: true; a stale default referencing a deleted instance falls
back to plugin config with a warning);cordis.patch.yml).Per-call host/port/user/passwordRef/tls/ca/timeoutMs arguments
still override the resolved profile. A non-auto TLS mode inside a profile is
an enforced transport policy exactly like plugin config: a conflicting tls
tool argument is rejected.
The page is implemented by the plugin's Web Client bundle
(client/NebulaInstancesSection.tsx), which reads and writes the section
through a plugin-owned Web route (/dsh-nebula/api, see
src/instances-api.ts) with the same browser-trust fence as the harness
gateway. The route resolves the entry by the id the Loader records on the
plugin's fiber and reports it back in every view, so the client can filter
forwarded settings/document-updated events for exactly that namespace. A
plugin-owned route is still required because the client bundle cannot know the
profile entry id and because the harness's own settings RPC cannot express the
plugin's cross-field checks (duplicate aliases, empty hosts), which the route
runs before every write. The host reads the same live config references at
connect time (src/instances.ts). Without a settings provider or a web surface
the route simply never mounts and the plugin keeps working on plugin config
alone.
pnpm install
pnpm typecheck
pnpm build # tsc → lib/ + copies vendored protos to lib/proto
pnpm test # decoder unit tests + gRPC integration tests (in-process fake GraphService)
The package is plain ESM ("type": "module") with no runtime dependencies
beyond @grpc/grpc-js, @grpc/proto-loader, and @deepseek-ai/schemastery
(the runtime's schemastery build: only it implements the .volatile() config
fields the settings integration needs).
dsh plugin --profile <name> add link:<checkout> installs this package as a
symlink in the profile, and the profile loader resolves that symlink to its real
path — so every import inside lib/ resolves against this checkout, not
against the profile's node_modules. A checkout without its own installed
dependencies therefore fails to load with
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'schemastery' imported from
.../dsh-nebula/lib/index.js
Run pnpm install && pnpm build in the checkout after any dependency change.
Installing the packed tarball or the git dependency instead gives a real copy
with its dependencies nested beside it, at the cost of live edits.
src/proto/nebula/ are the
official NebulaGraph 5.0 definitions (graph/common/vector) from
nebula-go v5. AuthRequest.auth_info is JSON.stringify({ password }) and
ClientInfo.lang advertises JAVASCRIPT; Status.code == "00000" means
success. The password is sent only inside the one-time Authenticate call
and cleared from the client/registry options immediately after success.tls
mode: on → createSsl (with optional CA / client cert / server-name
override), off → createInsecure, auto → try TLS first, then recreate
the channel with plaintext credentials only when the handshake fails at the
transport level (never on an authentication failure). A plaintext fallback
is surfaced as tlsFallback in the connect output and as a warning line.SESSION CLOSE statement before releasing the channel
(mirroring nebula-go v5 connection.Close()), so the server-side session
is released immediately instead of lingering until its idle timeout.src/decode/ is a faithful TypeScript port of nebula-go v5's
internal/decode (column type schemas, flat/const vector layouts, chunked
strings, node/edge property vectors, path adjacency lists, composite value
encoding).instances / defaultInstance / credentialRefs are
.volatile() fields of the plugin's Config schema, which dsh-settings
≥ 0.2.0 projects into an editable form and commits into the running config's
live references — so a settings save never remounts the plugin. Without a
settings provider the fields keep their schema defaults (an empty section)
and the tools fall back to config exactly as before, while the Web GUI edits
the same entry over the plugin-owned /dsh-nebula/api route. Alias
resolution and validation are pure functions in src/instances.ts, shared
by the tools and the settings surface contract.MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。