drydock-cli 3.0.119__tar.gz → 3.0.121__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.119/drydock_cli.egg-info → drydock_cli-3.0.121}/PKG-INFO +1 -1
- drydock_cli-3.0.121/drydock/builtin_skills/ml-data.md +15 -0
- drydock_cli-3.0.121/drydock/builtin_skills/ml-debug.md +18 -0
- drydock_cli-3.0.121/drydock/builtin_skills/ml-finetune.md +17 -0
- drydock_cli-3.0.121/drydock/builtin_skills/ml-metrics.md +16 -0
- drydock_cli-3.0.121/drydock/builtin_skills/ml-rl.md +16 -0
- drydock_cli-3.0.121/drydock/builtin_skills/ml-train.md +19 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/recipes.py +2 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tools/__init__.py +4 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/SOURCES.txt +6 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/pyproject.toml +1 -1
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_recipes.py +15 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_screenshot.py +12 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_skills.py +5 -1
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/LICENSE +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/NOTICE +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/README.md +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/__init__.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/__main__.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/advisor.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/agent.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/cci.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/cli.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/compaction.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/config.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/detect.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/extract.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/gittools.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/graphrag.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/guards.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/mcp.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/poam.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/providers.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/rmf.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/skills.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/stig.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/suggest.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/app.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tuning.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/web.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/setup.cfg +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_advisor.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_approval.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_back_command.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_crossplatform.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_stop_partial.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_cci.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_compaction.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_config.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_detect.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_edit_replace_all.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_extract.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_gittools.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_glob_edit_edges.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_graphrag_quoted_path.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_mcp.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_overthink_interrupt.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_poam.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_read_index.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_repetition_interrupt.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_rmf.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_stall_retry.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_stig.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_stop.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_subagent.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_suggest.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_todo.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tool_arg_coercion.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tool_arg_coercion_more.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tui.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tuning.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_windows_shell.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_xccdf.py +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ml-data
|
|
3
|
+
description: Organize, prep, split, normalize, or convert a dataset (incl. HDF5/JSON)
|
|
4
|
+
---
|
|
5
|
+
Data-engineering task: $ARGS
|
|
6
|
+
|
|
7
|
+
1. INSPECT first — format (H5/CSV/JSON/images), shapes, dtypes, class balance
|
|
8
|
+
(`np.bincount`), missing values.
|
|
9
|
+
2. Splits → stratified train/val/test; fit any scaler/encoder on TRAIN ONLY and apply
|
|
10
|
+
to val/test (NEVER fit on val/test — that leaks). Use a fixed random_state.
|
|
11
|
+
3. HDF5 ↔ JSON → preserve shapes, dtypes, and attrs; `h5py` for arrays (compression for
|
|
12
|
+
big ones), `arr.tolist()` when a JSON needs the values; keep large arrays in H5 and
|
|
13
|
+
only metadata/paths in JSON.
|
|
14
|
+
4. Save outputs EXACTLY as specified (names, keys, dtypes) and validate by reloading and
|
|
15
|
+
checking shapes/counts.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ml-debug
|
|
3
|
+
description: Diagnose and fix a broken PyTorch training run (NaN loss, not learning, shapes)
|
|
4
|
+
---
|
|
5
|
+
Diagnose and FIX the broken training: $ARGS
|
|
6
|
+
|
|
7
|
+
Be systematic — reproduce first, read the exact symptom, then:
|
|
8
|
+
- Loss NaN/Inf → LR too high (lower it), log/sqrt of ≤0, divide-by-zero, unnormalized
|
|
9
|
+
inputs, or NaNs in data. Add `torch.autograd.set_detect_anomaly(True)` and
|
|
10
|
+
`nn.utils.clip_grad_norm_`.
|
|
11
|
+
- Loss flat / not learning → missing `opt.zero_grad()` or `opt.step()`; wrong loss
|
|
12
|
+
(softmax BEFORE CrossEntropyLoss); LR too low; model not in `train()`; frozen params;
|
|
13
|
+
labels/logits misaligned. Print the loss and a param's grad-norm each step.
|
|
14
|
+
- Shape mismatch → print `.shape` at each layer; CrossEntropyLoss wants logits (N,C) and
|
|
15
|
+
Long targets (N,).
|
|
16
|
+
- Train↑ val↓ → overfitting; regularize / augment / early-stop.
|
|
17
|
+
Overfit a tiny batch first to isolate the bug. Fix, rerun, and confirm it converges and
|
|
18
|
+
meets the target before finishing.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ml-finetune
|
|
3
|
+
description: Fine-tune a model — full or LoRA (peft) — to a target metric
|
|
4
|
+
---
|
|
5
|
+
Fine-tuning task: $ARGS
|
|
6
|
+
|
|
7
|
+
1. Load the base/pretrained model and inspect it (`model.named_modules()`), and load
|
|
8
|
+
the fine-tune data (with a held-out eval split).
|
|
9
|
+
2. Choose the method:
|
|
10
|
+
- LoRA (train ~0.1% of params): `from peft import LoraConfig, get_peft_model`;
|
|
11
|
+
r=8, lora_alpha=16, lora_dropout=0.05, target_modules = the attention linear
|
|
12
|
+
layers you found; `get_peft_model(...)`; call `print_trainable_parameters()` to
|
|
13
|
+
CONFIRM only adapters train. Save with `model.save_pretrained('adapter')`.
|
|
14
|
+
- FULL: train all params with a SMALL LR (2e-5–5e-5), AdamW, a few epochs; freeze
|
|
15
|
+
anything that should stay fixed. `model.save_pretrained(dir)`.
|
|
16
|
+
3. Train, evaluating on the held-out set; small LR + few epochs — don't destroy the
|
|
17
|
+
pretrained features. Report the eval metric and save exactly what's requested.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ml-metrics
|
|
3
|
+
description: Compute a full classification metrics report (accuracy/precision/recall/F1/MCC/ROC-AUC/confusion)
|
|
4
|
+
---
|
|
5
|
+
Compute an evaluation-metrics report for: $ARGS
|
|
6
|
+
|
|
7
|
+
1. Load the ground-truth labels and the predictions (and predicted probabilities /
|
|
8
|
+
scores if ROC-AUC is needed). Confirm shapes and the positive label / class order.
|
|
9
|
+
2. Using scikit-learn compute: accuracy, precision, recall, F1, MCC, ROC-AUC, and the
|
|
10
|
+
confusion matrix. For binary, report the counts TP/FP/TN/FN
|
|
11
|
+
(`tn,fp,fn,tp = confusion_matrix(y_true,y_pred).ravel()`). For multiclass use
|
|
12
|
+
`average='macro'` (and per-class arrays) and `roc_auc_score(..., multi_class='ovr')`.
|
|
13
|
+
3. Save the metrics as JSON with clear keys, and plot the ROC curve
|
|
14
|
+
(`roc_curve` → plot tpr vs fpr) to an image if asked.
|
|
15
|
+
4. Print a readable table. Double-check definitions: precision=TP/(TP+FP),
|
|
16
|
+
recall=TP/(TP+FN), F1=2PR/(P+R), MCC uses all four cells.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ml-rl
|
|
3
|
+
description: Implement and train a reinforcement-learning agent to solve an environment
|
|
4
|
+
---
|
|
5
|
+
Reinforcement-learning task: $ARGS
|
|
6
|
+
|
|
7
|
+
1. Inspect the environment API — `reset()`, `step(action)` return values, the state
|
|
8
|
+
and action spaces. Look at the actual code before coding the agent.
|
|
9
|
+
2. Choose the method:
|
|
10
|
+
- Small discrete states → tabular Q-learning: `Q=np.zeros((nS,nA))`; epsilon-greedy
|
|
11
|
+
action; Bellman update `Q[s,a]+=alpha*(r+gamma*Q[s2].max()-Q[s,a])`; decay epsilon.
|
|
12
|
+
- Large/continuous → a neural policy: DQN (replay buffer + target network) or
|
|
13
|
+
REINFORCE (maximize sum of log_prob(a)*return).
|
|
14
|
+
3. Train until the average episode reward rises and the greedy policy solves the task.
|
|
15
|
+
alpha≈0.5, gamma≈0.95, eps 0.1–0.2 decaying. Save the policy/Q-table exactly as
|
|
16
|
+
asked and verify the greedy policy reaches the goal.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ml-train
|
|
3
|
+
description: Build and train a PyTorch model on a dataset to a target metric
|
|
4
|
+
---
|
|
5
|
+
You are doing a machine-learning TRAINING task: $ARGS
|
|
6
|
+
|
|
7
|
+
Work in this order:
|
|
8
|
+
1. INSPECT the data first — load it, print shapes, dtypes, number of classes, and
|
|
9
|
+
which splits exist (train/val/test). Never assume; look.
|
|
10
|
+
2. BUILD an appropriate model in PyTorch — a CNN for images, an MLP/Transformer for
|
|
11
|
+
vectors/sequences. Keep it small unless the task demands otherwise.
|
|
12
|
+
3. Write a CORRECT training loop: AdamW, CrossEntropyLoss on RAW logits (no softmax),
|
|
13
|
+
`opt.zero_grad()` every step, mini-batches via DataLoader, `model.train()` for
|
|
14
|
+
training and `model.eval()` + `torch.no_grad()` for evaluation, and move BOTH the
|
|
15
|
+
model and each batch to the same device. Seed torch for reproducibility.
|
|
16
|
+
4. Sanity-check: overfit a single tiny batch to near-zero loss first.
|
|
17
|
+
5. Track the train and validation metric each epoch; stop when the target is met.
|
|
18
|
+
6. Produce EXACTLY the artifacts the task asks for (file names, formats, order), then
|
|
19
|
+
re-read the requirements and verify each one before you finish.
|
|
@@ -274,6 +274,8 @@ def retrieve_recipes(task_text: str, k: int = 2) -> list[tuple[str, str]]:
|
|
|
274
274
|
overlap. Empty if nothing scores — never inject irrelevant noise."""
|
|
275
275
|
if not task_text:
|
|
276
276
|
return []
|
|
277
|
+
if not isinstance(task_text, str): # defensive: never crash the agent loop
|
|
278
|
+
task_text = str(task_text)
|
|
277
279
|
words = set(_WORD.findall(task_text.lower()))
|
|
278
280
|
scored = []
|
|
279
281
|
for title, keywords, body in RECIPES:
|
|
@@ -750,6 +750,10 @@ def _capture_screen(out: str) -> str | None:
|
|
|
750
750
|
elif sys.platform == "darwin":
|
|
751
751
|
subprocess.run(["screencapture", "-x", out], capture_output=True, timeout=30)
|
|
752
752
|
else: # Linux/BSD — try grabbers in order of ubiquity (X11 + wayland)
|
|
753
|
+
if not (os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")):
|
|
754
|
+
# Fail fast — a grabber on a headless box blocks until timeout.
|
|
755
|
+
return ("no display ($DISPLAY/$WAYLAND_DISPLAY unset) — cannot capture "
|
|
756
|
+
"the screen on a headless server.")
|
|
753
757
|
grabbers = (["scrot", "-o", out], ["import", "-window", "root", out],
|
|
754
758
|
["gnome-screenshot", "-f", out], ["grim", out],
|
|
755
759
|
["spectacle", "-b", "-n", "-o", out], ["maim", out])
|
|
@@ -30,6 +30,12 @@ drydock/tool_registry.py
|
|
|
30
30
|
drydock/tuning.py
|
|
31
31
|
drydock/web.py
|
|
32
32
|
drydock/builtin_skills/__init__.py
|
|
33
|
+
drydock/builtin_skills/ml-data.md
|
|
34
|
+
drydock/builtin_skills/ml-debug.md
|
|
35
|
+
drydock/builtin_skills/ml-finetune.md
|
|
36
|
+
drydock/builtin_skills/ml-metrics.md
|
|
37
|
+
drydock/builtin_skills/ml-rl.md
|
|
38
|
+
drydock/builtin_skills/ml-train.md
|
|
33
39
|
drydock/builtin_skills/rmf-categorize.md
|
|
34
40
|
drydock/builtin_skills/rmf-control.md
|
|
35
41
|
drydock/builtin_skills/rmf-poam.md
|
|
@@ -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.121"
|
|
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"
|
|
@@ -53,3 +53,18 @@ def test_not_injected_when_disabled():
|
|
|
53
53
|
cfg = {"model": "gemma4", "max_tokens": 8192, "context_limit": 65536, "recipes": False}
|
|
54
54
|
sysp = _run_capture(cfg, "recover the deleted password from launchcode.txt forensic")
|
|
55
55
|
assert "TECHNIQUE RECIPES" not in sysp
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_ml_skills_bundled():
|
|
59
|
+
from drydock.skills import load_skills
|
|
60
|
+
sk = load_skills(".")
|
|
61
|
+
for name in ("ml-train", "ml-metrics", "ml-finetune", "ml-debug", "ml-rl", "ml-data"):
|
|
62
|
+
assert name in sk, f"bundled ML skill /{name} missing"
|
|
63
|
+
assert "MCC" in sk["ml-metrics"].body or "mcc" in sk["ml-metrics"].body.lower()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_retrieve_handles_non_string():
|
|
67
|
+
from drydock.recipes import retrieve_recipes, recipe_context
|
|
68
|
+
for v in (b"train a cnn", ["train", "cnn"], 5, None):
|
|
69
|
+
assert isinstance(retrieve_recipes(v), list) # never raises
|
|
70
|
+
assert isinstance(recipe_context(123), str)
|
|
@@ -57,3 +57,15 @@ def test_macos_uses_screencapture(monkeypatch):
|
|
|
57
57
|
monkeypatch.setattr("subprocess.run", lambda a, **k: calls.setdefault("argv", a))
|
|
58
58
|
tools._capture_screen("/tmp/x.png")
|
|
59
59
|
assert calls["argv"][0] == "screencapture"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_headless_linux_fails_fast(monkeypatch):
|
|
63
|
+
import time
|
|
64
|
+
monkeypatch.setattr(tools, "_IS_WINDOWS", False)
|
|
65
|
+
monkeypatch.setattr("sys.platform", "linux")
|
|
66
|
+
monkeypatch.delenv("DISPLAY", raising=False)
|
|
67
|
+
monkeypatch.delenv("WAYLAND_DISPLAY", raising=False)
|
|
68
|
+
t = time.time()
|
|
69
|
+
err = tools._capture_screen("/tmp/x.png")
|
|
70
|
+
assert time.time() - t < 1.0 # no 30s grabber hang
|
|
71
|
+
assert err and "display" in err.lower()
|
|
@@ -55,7 +55,11 @@ def test_empty_body_skipped(tmp_path):
|
|
|
55
55
|
def test_no_user_or_project_skills_yields_only_builtins(tmp_path):
|
|
56
56
|
# With no user/project skills, only the bundled built-ins (RMF) are present.
|
|
57
57
|
loaded = skills.load_skills(str(tmp_path))
|
|
58
|
-
assert set(loaded) == {
|
|
58
|
+
assert set(loaded) == {
|
|
59
|
+
"rmf-control", "rmf-categorize", "rmf-review", "rmf-poam",
|
|
60
|
+
"stig-assess", "stig-remediate",
|
|
61
|
+
"ml-train", "ml-metrics", "ml-finetune", "ml-debug", "ml-rl", "ml-data",
|
|
62
|
+
}
|
|
59
63
|
|
|
60
64
|
|
|
61
65
|
def test_create_skill_user_scope(tmp_path, monkeypatch):
|
|
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
|
|
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
|