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.
Files changed (134) hide show
  1. {drydock_cli-3.0.119/drydock_cli.egg-info → drydock_cli-3.0.121}/PKG-INFO +1 -1
  2. drydock_cli-3.0.121/drydock/builtin_skills/ml-data.md +15 -0
  3. drydock_cli-3.0.121/drydock/builtin_skills/ml-debug.md +18 -0
  4. drydock_cli-3.0.121/drydock/builtin_skills/ml-finetune.md +17 -0
  5. drydock_cli-3.0.121/drydock/builtin_skills/ml-metrics.md +16 -0
  6. drydock_cli-3.0.121/drydock/builtin_skills/ml-rl.md +16 -0
  7. drydock_cli-3.0.121/drydock/builtin_skills/ml-train.md +19 -0
  8. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/recipes.py +2 -0
  9. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tools/__init__.py +4 -0
  10. {drydock_cli-3.0.119 → drydock_cli-3.0.121/drydock_cli.egg-info}/PKG-INFO +1 -1
  11. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/SOURCES.txt +6 -0
  12. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/pyproject.toml +1 -1
  13. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_recipes.py +15 -0
  14. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_screenshot.py +12 -0
  15. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_skills.py +5 -1
  16. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/LICENSE +0 -0
  17. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/NOTICE +0 -0
  18. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/README.md +0 -0
  19. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/__init__.py +0 -0
  20. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/__main__.py +0 -0
  21. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/advisor.py +0 -0
  22. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/agent.py +0 -0
  23. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/bash_safety.py +0 -0
  24. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/__init__.py +0 -0
  25. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-categorize.md +0 -0
  26. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-control.md +0 -0
  27. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-poam.md +0 -0
  28. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/rmf-review.md +0 -0
  29. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/stig-assess.md +0 -0
  30. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/builtin_skills/stig-remediate.md +0 -0
  31. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/cci.py +0 -0
  32. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/cli.py +0 -0
  33. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/compaction.py +0 -0
  34. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/config.py +0 -0
  35. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/detect.py +0 -0
  36. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/extract.py +0 -0
  37. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/gittools.py +0 -0
  38. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/graphrag.py +0 -0
  39. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/guards.py +0 -0
  40. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/loop_detect.py +0 -0
  41. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/mcp.py +0 -0
  42. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/poam.py +0 -0
  43. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/providers.py +0 -0
  44. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/rmf.py +0 -0
  45. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/rmf_graph.py +0 -0
  46. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/skills.py +0 -0
  47. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/stig.py +0 -0
  48. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/suggest.py +0 -0
  49. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tool_registry.py +0 -0
  50. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/__init__.py +0 -0
  51. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/app.py +0 -0
  52. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/approval.py +0 -0
  53. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/messages.py +0 -0
  54. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tui/widgets.py +0 -0
  55. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/tuning.py +0 -0
  56. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock/web.py +0 -0
  57. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/dependency_links.txt +0 -0
  58. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/entry_points.txt +0 -0
  59. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/requires.txt +0 -0
  60. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/drydock_cli.egg-info/top_level.txt +0 -0
  61. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/setup.cfg +0 -0
  62. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_advisor.py +0 -0
  63. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_approval.py +0 -0
  64. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_back_command.py +0 -0
  65. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_background.py +0 -0
  66. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_binary_output.py +0 -0
  67. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_crossplatform.py +0 -0
  68. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_output_bounding.py +0 -0
  69. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_process_group.py +0 -0
  70. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_safety.py +0 -0
  71. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_sanitize.py +0 -0
  72. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_shell.py +0 -0
  73. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_stdin.py +0 -0
  74. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_stop_partial.py +0 -0
  75. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_timeout_network.py +0 -0
  76. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_bash_timeout_param.py +0 -0
  77. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_cci.py +0 -0
  78. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_cli_agents.py +0 -0
  79. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_compact_command.py +0 -0
  80. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_compaction.py +0 -0
  81. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_config.py +0 -0
  82. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_config_migration.py +0 -0
  83. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_context_limit_config.py +0 -0
  84. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_detect.py +0 -0
  85. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_dispatch.py +0 -0
  86. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_e2e_connected.py +0 -0
  87. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_edit_replace_all.py +0 -0
  88. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_empty_response.py +0 -0
  89. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_extract.py +0 -0
  90. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_failure_loop.py +0 -0
  91. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_first_run_setup.py +0 -0
  92. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_gittools.py +0 -0
  93. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_glob_edit_edges.py +0 -0
  94. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_graphify_example.py +0 -0
  95. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_graphrag.py +0 -0
  96. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_graphrag_quoted_path.py +0 -0
  97. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_grep_and_read_robust.py +0 -0
  98. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_guards_and_tools.py +0 -0
  99. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_hallucinated_tools.py +0 -0
  100. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_leaked_tool_call.py +0 -0
  101. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_loop_detect.py +0 -0
  102. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_mcp.py +0 -0
  103. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_oneshot_unreachable.py +0 -0
  104. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_overthink_interrupt.py +0 -0
  105. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_plan_autocontinue.py +0 -0
  106. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_poam.py +0 -0
  107. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_providers_unreachable.py +0 -0
  108. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_read_index.py +0 -0
  109. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_repetition_interrupt.py +0 -0
  110. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_rmf.py +0 -0
  111. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_rmf_graph.py +0 -0
  112. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_rmf_stig_graph.py +0 -0
  113. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_runaway_repetition.py +0 -0
  114. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_server_probe.py +0 -0
  115. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_stall_retry.py +0 -0
  116. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_stig.py +0 -0
  117. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_stop.py +0 -0
  118. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_streaming_newlines.py +0 -0
  119. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_subagent.py +0 -0
  120. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_suggest.py +0 -0
  121. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_system_prompt_help.py +0 -0
  122. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_todo.py +0 -0
  123. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tool_arg_coercion.py +0 -0
  124. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tool_arg_coercion_more.py +0 -0
  125. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tool_arg_parsing.py +0 -0
  126. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tools_undo.py +0 -0
  127. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tui.py +0 -0
  128. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_tuning.py +0 -0
  129. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_viewimage.py +0 -0
  130. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_vision_input.py +0 -0
  131. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_web_tools.py +0 -0
  132. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_windows_shell.py +0 -0
  133. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/tests/test_write_content_coerce.py +0 -0
  134. {drydock_cli-3.0.119 → drydock_cli-3.0.121}/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.119
3
+ Version: 3.0.121
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
@@ -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])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.119
3
+ Version: 3.0.121
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
@@ -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.119"
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) == {"rmf-control", "rmf-categorize", "rmf-review", "rmf-poam", "stig-assess", "stig-remediate"}
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