drydock-cli 3.0.74__tar.gz → 3.0.75__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {drydock_cli-3.0.74/drydock_cli.egg-info → drydock_cli-3.0.75}/PKG-INFO +37 -10
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/README.md +36 -9
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tools/__init__.py +23 -4
- {drydock_cli-3.0.74 → drydock_cli-3.0.75/drydock_cli.egg-info}/PKG-INFO +37 -10
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/pyproject.toml +1 -1
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_dispatch.py +11 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/LICENSE +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/NOTICE +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/__init__.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/__main__.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/agent.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/cci.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/cli.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/compaction.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/config.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/detect.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/extract.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/gittools.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/graphrag.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/guards.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/mcp.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/providers.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/rmf.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/skills.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/stig.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tui/app.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/tuning.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock/web.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock_cli.egg-info/SOURCES.txt +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/setup.cfg +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_approval.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_back_command.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_cci.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_compaction.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_config.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_detect.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_extract.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_gittools.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_mcp.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_read_index.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_rmf.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_skills.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_stig.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_stop.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_subagent.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_todo.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_tui.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_tuning.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.0.74 → drydock_cli-3.0.75}/tests/test_xccdf.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drydock-cli
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.75
|
|
4
4
|
Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
|
|
5
5
|
Author: Frank Bobe III
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -91,10 +91,14 @@ Typed into the prompt. The agent also knows these, so you can just **ask it**
|
|
|
91
91
|
| `/mcp` | List connected MCP servers + their tools |
|
|
92
92
|
| `/rmf bootstrap [families]` | Ingest the NIST SP 800-53 catalog (RMF automation) |
|
|
93
93
|
| `/rmf-control` · `/rmf-categorize` · `/rmf-review` · `/rmf-poam` | Bundled RMF skills |
|
|
94
|
+
| `/stig new <xccdf>` | Generate a blank `.ckl` from a DISA STIG benchmark |
|
|
95
|
+
| `/stig <ckl>` · `/stig <ckl> open` | Summarize a checklist · list findings by status |
|
|
96
|
+
| `/stig graph <ckl>` | Ingest a checklist into the RMF graph (auto-links rules→controls via CCI) |
|
|
97
|
+
| `/stig-assess <ckl>` · `/stig-remediate <ckl> <rule>` | Assess a rule vs evidence · write a fix script |
|
|
94
98
|
| `/model` · `/cwd` | Show/set model & endpoint · working directory |
|
|
95
99
|
| `/undo` · `/back` | Revert the last write · rewind the last turn |
|
|
96
|
-
| `/compact` · `/
|
|
97
|
-
| `/help` · `/quit` |
|
|
100
|
+
| `/compact` · `/context [n]` | Shrink context now · view/set the context-window budget |
|
|
101
|
+
| `/status` · `/clear` · `/help` · `/quit` | Session stats · reset · help · exit |
|
|
98
102
|
|
|
99
103
|
### Knowledge base (GraphRAG) — ingesting your documents
|
|
100
104
|
|
|
@@ -107,9 +111,11 @@ Typed into the prompt. The agent also knows these, so you can just **ask it**
|
|
|
107
111
|
|
|
108
112
|
Once built, the agent **automatically** retrieves from it (read-only `Knowledge`
|
|
109
113
|
tool) when a question touches your material. Ingests text formats
|
|
110
|
-
(`.md .txt .py .js .json .yaml .sql …`) **
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
(`.md .txt .py .js .json .yaml .sql …`), **PDF and Word (`.docx`)**, and **STIG
|
|
115
|
+
checklists (`.ckl`/`.cklb`)** — checklists are flattened to per-rule findings so
|
|
116
|
+
you can ask "which findings are open?". `.docx`/`.ckl` need nothing extra; PDF
|
|
117
|
+
uses the `pdftotext` binary (poppler) if present, else `pip install
|
|
118
|
+
drydock-cli[pdf]` (pypdf). The index is a single JSON at
|
|
113
119
|
`<project>/.drydock/graphrag.json` — clean-room, no embeddings.
|
|
114
120
|
|
|
115
121
|
### Custom skills
|
|
@@ -144,6 +150,26 @@ relationships with `GraphQuery` — including **control inheritance** ("which
|
|
|
144
150
|
servers inherit physical controls from their enclave?"). Stdlib in-memory graph,
|
|
145
151
|
no Neo4j.
|
|
146
152
|
|
|
153
|
+
### STIG checklists (DISA `.ckl`/`.cklb`)
|
|
154
|
+
|
|
155
|
+
Take a raw DISA STIG benchmark all the way to a completed, eMASS/STIG-Viewer-
|
|
156
|
+
compatible checklist — entirely local (hostnames, IPs, and findings are CUI):
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
/stig new U_ASD_STIG_V6R1_Manual-xccdf.xml app.ckl # benchmark → blank .ckl
|
|
160
|
+
/graphrag build ./app # pull in the app's evidence
|
|
161
|
+
/loop 286 /stig-assess app.ckl # assess each rule vs evidence
|
|
162
|
+
/stig app.ckl open # list the open findings
|
|
163
|
+
/stig-remediate app.ckl SV-900010r1_rule # write an idempotent fix script
|
|
164
|
+
/stig graph app.ckl # ingest + auto-link rules → NIST controls
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`/stig new` parses the XCCDF benchmark (validated against the full 286-rule
|
|
168
|
+
Application STIG); `/stig-assess` reads your evidence and writes status +
|
|
169
|
+
finding-details back in place; `/stig graph` builds `STIG`/`STIG-Rule` nodes and
|
|
170
|
+
**auto-links each rule to its NIST 800-53 control** through DISA's CCI map
|
|
171
|
+
(`Control —SATISFIED_BY→ rule`), fetched once and cached offline.
|
|
172
|
+
|
|
147
173
|
## Install
|
|
148
174
|
|
|
149
175
|
```bash
|
|
@@ -173,10 +199,11 @@ commands to do the work, showing each as a collapsible tool card.
|
|
|
173
199
|
`◡ Keelhauling… (12s · ↓ 6.2k tokens · thinking with high effort)`
|
|
174
200
|
- Submit while it's working and the prompt **queues** (drains in order)
|
|
175
201
|
- Slash commands: `/model` · `/cwd` · `/undo` (revert last write) · `/back`
|
|
176
|
-
(rewind last turn) · `/status` · `/compact` (shrink context) · `/
|
|
177
|
-
(
|
|
178
|
-
|
|
179
|
-
`/
|
|
202
|
+
(rewind last turn) · `/status` · `/compact` (shrink context) · `/context`
|
|
203
|
+
(view/set the context-window budget) · `/graphrag` (build/query a knowledge
|
|
204
|
+
base) · `/skills` (list your `/<name>` skills) · `/loop` (repeat a prompt) ·
|
|
205
|
+
`/mcp` (list MCP servers) · `/rmf` & `/stig` (NIST 800-53 / DISA STIG
|
|
206
|
+
automation) · `/clear` · `/help` · `/quit`
|
|
180
207
|
|
|
181
208
|
It honors `AGENTS.md` / `DRYDOCK.md` in the working directory for project
|
|
182
209
|
conventions.
|
|
@@ -67,10 +67,14 @@ Typed into the prompt. The agent also knows these, so you can just **ask it**
|
|
|
67
67
|
| `/mcp` | List connected MCP servers + their tools |
|
|
68
68
|
| `/rmf bootstrap [families]` | Ingest the NIST SP 800-53 catalog (RMF automation) |
|
|
69
69
|
| `/rmf-control` · `/rmf-categorize` · `/rmf-review` · `/rmf-poam` | Bundled RMF skills |
|
|
70
|
+
| `/stig new <xccdf>` | Generate a blank `.ckl` from a DISA STIG benchmark |
|
|
71
|
+
| `/stig <ckl>` · `/stig <ckl> open` | Summarize a checklist · list findings by status |
|
|
72
|
+
| `/stig graph <ckl>` | Ingest a checklist into the RMF graph (auto-links rules→controls via CCI) |
|
|
73
|
+
| `/stig-assess <ckl>` · `/stig-remediate <ckl> <rule>` | Assess a rule vs evidence · write a fix script |
|
|
70
74
|
| `/model` · `/cwd` | Show/set model & endpoint · working directory |
|
|
71
75
|
| `/undo` · `/back` | Revert the last write · rewind the last turn |
|
|
72
|
-
| `/compact` · `/
|
|
73
|
-
| `/help` · `/quit` |
|
|
76
|
+
| `/compact` · `/context [n]` | Shrink context now · view/set the context-window budget |
|
|
77
|
+
| `/status` · `/clear` · `/help` · `/quit` | Session stats · reset · help · exit |
|
|
74
78
|
|
|
75
79
|
### Knowledge base (GraphRAG) — ingesting your documents
|
|
76
80
|
|
|
@@ -83,9 +87,11 @@ Typed into the prompt. The agent also knows these, so you can just **ask it**
|
|
|
83
87
|
|
|
84
88
|
Once built, the agent **automatically** retrieves from it (read-only `Knowledge`
|
|
85
89
|
tool) when a question touches your material. Ingests text formats
|
|
86
|
-
(`.md .txt .py .js .json .yaml .sql …`) **
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
(`.md .txt .py .js .json .yaml .sql …`), **PDF and Word (`.docx`)**, and **STIG
|
|
91
|
+
checklists (`.ckl`/`.cklb`)** — checklists are flattened to per-rule findings so
|
|
92
|
+
you can ask "which findings are open?". `.docx`/`.ckl` need nothing extra; PDF
|
|
93
|
+
uses the `pdftotext` binary (poppler) if present, else `pip install
|
|
94
|
+
drydock-cli[pdf]` (pypdf). The index is a single JSON at
|
|
89
95
|
`<project>/.drydock/graphrag.json` — clean-room, no embeddings.
|
|
90
96
|
|
|
91
97
|
### Custom skills
|
|
@@ -120,6 +126,26 @@ relationships with `GraphQuery` — including **control inheritance** ("which
|
|
|
120
126
|
servers inherit physical controls from their enclave?"). Stdlib in-memory graph,
|
|
121
127
|
no Neo4j.
|
|
122
128
|
|
|
129
|
+
### STIG checklists (DISA `.ckl`/`.cklb`)
|
|
130
|
+
|
|
131
|
+
Take a raw DISA STIG benchmark all the way to a completed, eMASS/STIG-Viewer-
|
|
132
|
+
compatible checklist — entirely local (hostnames, IPs, and findings are CUI):
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
/stig new U_ASD_STIG_V6R1_Manual-xccdf.xml app.ckl # benchmark → blank .ckl
|
|
136
|
+
/graphrag build ./app # pull in the app's evidence
|
|
137
|
+
/loop 286 /stig-assess app.ckl # assess each rule vs evidence
|
|
138
|
+
/stig app.ckl open # list the open findings
|
|
139
|
+
/stig-remediate app.ckl SV-900010r1_rule # write an idempotent fix script
|
|
140
|
+
/stig graph app.ckl # ingest + auto-link rules → NIST controls
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`/stig new` parses the XCCDF benchmark (validated against the full 286-rule
|
|
144
|
+
Application STIG); `/stig-assess` reads your evidence and writes status +
|
|
145
|
+
finding-details back in place; `/stig graph` builds `STIG`/`STIG-Rule` nodes and
|
|
146
|
+
**auto-links each rule to its NIST 800-53 control** through DISA's CCI map
|
|
147
|
+
(`Control —SATISFIED_BY→ rule`), fetched once and cached offline.
|
|
148
|
+
|
|
123
149
|
## Install
|
|
124
150
|
|
|
125
151
|
```bash
|
|
@@ -149,10 +175,11 @@ commands to do the work, showing each as a collapsible tool card.
|
|
|
149
175
|
`◡ Keelhauling… (12s · ↓ 6.2k tokens · thinking with high effort)`
|
|
150
176
|
- Submit while it's working and the prompt **queues** (drains in order)
|
|
151
177
|
- Slash commands: `/model` · `/cwd` · `/undo` (revert last write) · `/back`
|
|
152
|
-
(rewind last turn) · `/status` · `/compact` (shrink context) · `/
|
|
153
|
-
(
|
|
154
|
-
|
|
155
|
-
`/
|
|
178
|
+
(rewind last turn) · `/status` · `/compact` (shrink context) · `/context`
|
|
179
|
+
(view/set the context-window budget) · `/graphrag` (build/query a knowledge
|
|
180
|
+
base) · `/skills` (list your `/<name>` skills) · `/loop` (repeat a prompt) ·
|
|
181
|
+
`/mcp` (list MCP servers) · `/rmf` & `/stig` (NIST 800-53 / DISA STIG
|
|
182
|
+
automation) · `/clear` · `/help` · `/quit`
|
|
156
183
|
|
|
157
184
|
It honors `AGENTS.md` / `DRYDOCK.md` in the working directory for project
|
|
158
185
|
conventions.
|
|
@@ -1017,15 +1017,34 @@ _SUBAGENT_SYSTEM = (
|
|
|
1017
1017
|
"tools: Read, Glob, Grep, and Bash (use Bash only to INSPECT — ls, cat, "
|
|
1018
1018
|
"grep, find, git log — never to modify files). Investigate the task you are "
|
|
1019
1019
|
"given, then STOP and reply with a concise, factual summary of what you "
|
|
1020
|
-
"found: concrete file:line references and the key code
|
|
1021
|
-
"
|
|
1020
|
+
"found: concrete file:line references and only the few key code snippets that "
|
|
1021
|
+
"matter, not narration and not whole files. Aim for under ~250 words — the "
|
|
1022
|
+
"main agent only gets this summary (not your tool output), so distill, don't "
|
|
1023
|
+
"dump. Do NOT try to edit or create files — the main agent acts on your findings."
|
|
1022
1024
|
)
|
|
1023
1025
|
|
|
1024
1026
|
|
|
1027
|
+
# A sub-agent's whole job is to keep its investigation OUT of the main agent's
|
|
1028
|
+
# context and hand back only a partition. The system prompt asks for a concise
|
|
1029
|
+
# summary, but a runaway model could still return a wall of text — so cap what
|
|
1030
|
+
# crosses back into the parent's window. ~4000 chars ≈ ~1000 tokens.
|
|
1031
|
+
_SUBAGENT_SUMMARY_CAP = 4000
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
def _cap_summary(text: str) -> str:
|
|
1035
|
+
if len(text) <= _SUBAGENT_SUMMARY_CAP:
|
|
1036
|
+
return text
|
|
1037
|
+
head = text[:_SUBAGENT_SUMMARY_CAP].rsplit("\n", 1)[0] or text[:_SUBAGENT_SUMMARY_CAP]
|
|
1038
|
+
dropped = len(text) - len(head)
|
|
1039
|
+
return (head + f"\n[… sub-agent summary truncated, {dropped} chars dropped to keep it out "
|
|
1040
|
+
"of the main context. Ask a narrower follow-up sub-agent task if you need more.]")
|
|
1041
|
+
|
|
1042
|
+
|
|
1025
1043
|
def _run_subagent(prompt: str, config: dict) -> str:
|
|
1026
1044
|
"""Run one read-only sub-agent to completion and return its final summary.
|
|
1027
1045
|
Shared by `task` (one) and `Dispatch` (many in parallel). Hard-capped; never
|
|
1028
|
-
raises (a sub-agent must not crash the parent turn).
|
|
1046
|
+
raises (a sub-agent must not crash the parent turn). The returned summary is
|
|
1047
|
+
size-capped (_cap_summary) so a sub-agent can never bloat the main context."""
|
|
1029
1048
|
from drydock.agent import run as agent_run, AgentState, TurnDone
|
|
1030
1049
|
|
|
1031
1050
|
sub_state = AgentState()
|
|
@@ -1048,7 +1067,7 @@ def _run_subagent(prompt: str, config: dict) -> str:
|
|
|
1048
1067
|
return f"[sub-agent error: {e}]"
|
|
1049
1068
|
for msg in reversed(sub_state.messages):
|
|
1050
1069
|
if msg.get("role") == "assistant" and (msg.get("content") or "").strip():
|
|
1051
|
-
return msg["content"].strip()
|
|
1070
|
+
return _cap_summary(msg["content"].strip())
|
|
1052
1071
|
return f"[sub-agent finished {steps} step(s) with no summary]"
|
|
1053
1072
|
|
|
1054
1073
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drydock-cli
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.75
|
|
4
4
|
Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
|
|
5
5
|
Author: Frank Bobe III
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -91,10 +91,14 @@ Typed into the prompt. The agent also knows these, so you can just **ask it**
|
|
|
91
91
|
| `/mcp` | List connected MCP servers + their tools |
|
|
92
92
|
| `/rmf bootstrap [families]` | Ingest the NIST SP 800-53 catalog (RMF automation) |
|
|
93
93
|
| `/rmf-control` · `/rmf-categorize` · `/rmf-review` · `/rmf-poam` | Bundled RMF skills |
|
|
94
|
+
| `/stig new <xccdf>` | Generate a blank `.ckl` from a DISA STIG benchmark |
|
|
95
|
+
| `/stig <ckl>` · `/stig <ckl> open` | Summarize a checklist · list findings by status |
|
|
96
|
+
| `/stig graph <ckl>` | Ingest a checklist into the RMF graph (auto-links rules→controls via CCI) |
|
|
97
|
+
| `/stig-assess <ckl>` · `/stig-remediate <ckl> <rule>` | Assess a rule vs evidence · write a fix script |
|
|
94
98
|
| `/model` · `/cwd` | Show/set model & endpoint · working directory |
|
|
95
99
|
| `/undo` · `/back` | Revert the last write · rewind the last turn |
|
|
96
|
-
| `/compact` · `/
|
|
97
|
-
| `/help` · `/quit` |
|
|
100
|
+
| `/compact` · `/context [n]` | Shrink context now · view/set the context-window budget |
|
|
101
|
+
| `/status` · `/clear` · `/help` · `/quit` | Session stats · reset · help · exit |
|
|
98
102
|
|
|
99
103
|
### Knowledge base (GraphRAG) — ingesting your documents
|
|
100
104
|
|
|
@@ -107,9 +111,11 @@ Typed into the prompt. The agent also knows these, so you can just **ask it**
|
|
|
107
111
|
|
|
108
112
|
Once built, the agent **automatically** retrieves from it (read-only `Knowledge`
|
|
109
113
|
tool) when a question touches your material. Ingests text formats
|
|
110
|
-
(`.md .txt .py .js .json .yaml .sql …`) **
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
(`.md .txt .py .js .json .yaml .sql …`), **PDF and Word (`.docx`)**, and **STIG
|
|
115
|
+
checklists (`.ckl`/`.cklb`)** — checklists are flattened to per-rule findings so
|
|
116
|
+
you can ask "which findings are open?". `.docx`/`.ckl` need nothing extra; PDF
|
|
117
|
+
uses the `pdftotext` binary (poppler) if present, else `pip install
|
|
118
|
+
drydock-cli[pdf]` (pypdf). The index is a single JSON at
|
|
113
119
|
`<project>/.drydock/graphrag.json` — clean-room, no embeddings.
|
|
114
120
|
|
|
115
121
|
### Custom skills
|
|
@@ -144,6 +150,26 @@ relationships with `GraphQuery` — including **control inheritance** ("which
|
|
|
144
150
|
servers inherit physical controls from their enclave?"). Stdlib in-memory graph,
|
|
145
151
|
no Neo4j.
|
|
146
152
|
|
|
153
|
+
### STIG checklists (DISA `.ckl`/`.cklb`)
|
|
154
|
+
|
|
155
|
+
Take a raw DISA STIG benchmark all the way to a completed, eMASS/STIG-Viewer-
|
|
156
|
+
compatible checklist — entirely local (hostnames, IPs, and findings are CUI):
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
/stig new U_ASD_STIG_V6R1_Manual-xccdf.xml app.ckl # benchmark → blank .ckl
|
|
160
|
+
/graphrag build ./app # pull in the app's evidence
|
|
161
|
+
/loop 286 /stig-assess app.ckl # assess each rule vs evidence
|
|
162
|
+
/stig app.ckl open # list the open findings
|
|
163
|
+
/stig-remediate app.ckl SV-900010r1_rule # write an idempotent fix script
|
|
164
|
+
/stig graph app.ckl # ingest + auto-link rules → NIST controls
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`/stig new` parses the XCCDF benchmark (validated against the full 286-rule
|
|
168
|
+
Application STIG); `/stig-assess` reads your evidence and writes status +
|
|
169
|
+
finding-details back in place; `/stig graph` builds `STIG`/`STIG-Rule` nodes and
|
|
170
|
+
**auto-links each rule to its NIST 800-53 control** through DISA's CCI map
|
|
171
|
+
(`Control —SATISFIED_BY→ rule`), fetched once and cached offline.
|
|
172
|
+
|
|
147
173
|
## Install
|
|
148
174
|
|
|
149
175
|
```bash
|
|
@@ -173,10 +199,11 @@ commands to do the work, showing each as a collapsible tool card.
|
|
|
173
199
|
`◡ Keelhauling… (12s · ↓ 6.2k tokens · thinking with high effort)`
|
|
174
200
|
- Submit while it's working and the prompt **queues** (drains in order)
|
|
175
201
|
- Slash commands: `/model` · `/cwd` · `/undo` (revert last write) · `/back`
|
|
176
|
-
(rewind last turn) · `/status` · `/compact` (shrink context) · `/
|
|
177
|
-
(
|
|
178
|
-
|
|
179
|
-
`/
|
|
202
|
+
(rewind last turn) · `/status` · `/compact` (shrink context) · `/context`
|
|
203
|
+
(view/set the context-window budget) · `/graphrag` (build/query a knowledge
|
|
204
|
+
base) · `/skills` (list your `/<name>` skills) · `/loop` (repeat a prompt) ·
|
|
205
|
+
`/mcp` (list MCP servers) · `/rmf` & `/stig` (NIST 800-53 / DISA STIG
|
|
206
|
+
automation) · `/clear` · `/help` · `/quit`
|
|
180
207
|
|
|
181
208
|
It honors `AGENTS.md` / `DRYDOCK.md` in the working directory for project
|
|
182
209
|
conventions.
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
# PyPI distribution name is drydock-cli (the established install name, continued
|
|
8
8
|
# from the retired v2 fork); the import package + CLI command stay `drydock`.
|
|
9
9
|
name = "drydock-cli"
|
|
10
|
-
version = "3.0.
|
|
10
|
+
version = "3.0.75"
|
|
11
11
|
description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.11"
|
|
@@ -60,3 +60,14 @@ def test_task_still_works_via_shared_runner(monkeypatch):
|
|
|
60
60
|
monkeypatch.setattr(T, "_run_subagent", lambda p, c: f"summary:{p}")
|
|
61
61
|
assert T.tool_task({"prompt": "explore X"}, {}) == "summary:explore X"
|
|
62
62
|
assert "needs a `prompt`" in T.tool_task({}, {})
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_subagent_summary_is_capped():
|
|
66
|
+
"""A sub-agent's return is size-capped so its investigation can never bloat
|
|
67
|
+
the main agent's context — only a bounded partition crosses back."""
|
|
68
|
+
from drydock.tools import _cap_summary, _SUBAGENT_SUMMARY_CAP
|
|
69
|
+
assert _cap_summary("brief finding") == "brief finding" # short passes through
|
|
70
|
+
big = "\n".join(f"line {i} with some detail" for i in range(2000))
|
|
71
|
+
out = _cap_summary(big)
|
|
72
|
+
assert len(out) < _SUBAGENT_SUMMARY_CAP + 200 # bounded
|
|
73
|
+
assert "truncated" in out and "main context" in out # explains the cut
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|