tau-all-agent 0.1.0

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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/extensions/answer.ts +601 -0
  4. package/extensions/branch-term.ts +405 -0
  5. package/extensions/btw.ts +444 -0
  6. package/extensions/ghostty.ts +301 -0
  7. package/extensions/git-diff-stats.ts +277 -0
  8. package/extensions/git-pr-status.ts +286 -0
  9. package/extensions/insights.ts +2367 -0
  10. package/extensions/interlude.ts +144 -0
  11. package/extensions/loop.ts +529 -0
  12. package/extensions/memory.ts +1889 -0
  13. package/extensions/notify.ts +161 -0
  14. package/extensions/openai-fast.ts +227 -0
  15. package/extensions/openai-verbosity.ts +223 -0
  16. package/extensions/review.ts +4347 -0
  17. package/extensions/sandbox/index.ts +2578 -0
  18. package/extensions/telegram/README.md +81 -0
  19. package/extensions/telegram/daemon.mjs +1942 -0
  20. package/extensions/telegram/index.ts +1073 -0
  21. package/extensions/telegram/message-text.d.mts +1 -0
  22. package/extensions/telegram/message-text.mjs +16 -0
  23. package/extensions/usage/anthropic.ts +198 -0
  24. package/extensions/usage/github-copilot.ts +204 -0
  25. package/extensions/usage/google-gemini-cli.ts +232 -0
  26. package/extensions/usage/index.ts +2310 -0
  27. package/extensions/usage/minimax.ts +208 -0
  28. package/extensions/usage/openai-codex.ts +180 -0
  29. package/extensions/usage/openrouter.ts +168 -0
  30. package/extensions/usage/providers.ts +26 -0
  31. package/extensions/usage/shared.ts +156 -0
  32. package/extensions/usage/types.ts +53 -0
  33. package/extensions/usage/zai.ts +186 -0
  34. package/extensions/websearch/README.md +68 -0
  35. package/extensions/websearch/browser/chromium.ts +330 -0
  36. package/extensions/websearch/browser/discovery.ts +75 -0
  37. package/extensions/websearch/browser/firefox.ts +150 -0
  38. package/extensions/websearch/browser/sqlite.ts +38 -0
  39. package/extensions/websearch/config.ts +76 -0
  40. package/extensions/websearch/index.ts +312 -0
  41. package/extensions/websearch/normalize.ts +155 -0
  42. package/extensions/websearch/providers/anthropic.pi.ts +139 -0
  43. package/extensions/websearch/providers/gemini.browser.ts +185 -0
  44. package/extensions/websearch/providers/gemini.pi.ts +108 -0
  45. package/extensions/websearch/providers/openai-codex.browser.ts +77 -0
  46. package/extensions/websearch/providers/openai-codex.pi.ts +49 -0
  47. package/extensions/websearch/providers/openai-codex.shared.ts +123 -0
  48. package/extensions/websearch/providers/pi-model.shared.ts +86 -0
  49. package/extensions/websearch/providers/search-prompt.shared.ts +17 -0
  50. package/extensions/websearch/providers/shared.ts +76 -0
  51. package/extensions/websearch/types.ts +52 -0
  52. package/extensions/worktree.ts +2223 -0
  53. package/package.json +76 -0
  54. package/skills/browser-tools/SKILL.md +253 -0
  55. package/skills/browser-tools/scripts/browser-content.js +100 -0
  56. package/skills/browser-tools/scripts/browser-cookies.js +33 -0
  57. package/skills/browser-tools/scripts/browser-dismiss-cookies.js +455 -0
  58. package/skills/browser-tools/scripts/browser-eval.js +75 -0
  59. package/skills/browser-tools/scripts/browser-logs-tail.js +89 -0
  60. package/skills/browser-tools/scripts/browser-nav.js +28 -0
  61. package/skills/browser-tools/scripts/browser-net-summary.js +115 -0
  62. package/skills/browser-tools/scripts/browser-pick.js +133 -0
  63. package/skills/browser-tools/scripts/browser-screenshot.js +18 -0
  64. package/skills/browser-tools/scripts/browser-start.js +281 -0
  65. package/skills/browser-tools/scripts/browser-watch.js +321 -0
  66. package/skills/browser-tools/scripts/utils.js +60 -0
  67. package/skills/git-clean-history/SKILL.md +45 -0
  68. package/skills/git-commit/SKILL.md +55 -0
  69. package/skills/homeassistant-ops/SKILL.md +184 -0
  70. package/skills/homeassistant-ops/references/api.md +64 -0
  71. package/skills/homeassistant-ops/references/id_conventions.md +71 -0
  72. package/skills/homeassistant-ops/references/playbook.md +150 -0
  73. package/skills/homeassistant-ops/scripts/ha_ops.js +2942 -0
  74. package/skills/openscad/SKILL.md +149 -0
  75. package/skills/openscad/examples/parametric_box.scad +92 -0
  76. package/skills/openscad/examples/phone_stand.scad +95 -0
  77. package/skills/openscad/scripts/common.sh +49 -0
  78. package/skills/openscad/scripts/export-stl.sh +56 -0
  79. package/skills/openscad/scripts/extract-params.sh +147 -0
  80. package/skills/openscad/scripts/multi-preview.sh +68 -0
  81. package/skills/openscad/scripts/preview.sh +74 -0
  82. package/skills/openscad/scripts/render-with-params.sh +91 -0
  83. package/skills/openscad/scripts/validate.sh +46 -0
  84. package/skills/oracle/SKILL.md +64 -0
  85. package/skills/oracle/scripts/oracle +249 -0
  86. package/skills/oracle/scripts/oracle-bundle +227 -0
  87. package/skills/sentry/SKILL.md +198 -0
  88. package/skills/sentry/lib/auth.js +99 -0
  89. package/skills/sentry/scripts/fetch-event.js +325 -0
  90. package/skills/sentry/scripts/fetch-issue.js +368 -0
  91. package/skills/sentry/scripts/list-issues.js +245 -0
  92. package/skills/sentry/scripts/search-events.js +291 -0
  93. package/skills/sentry/scripts/search-logs.js +234 -0
  94. package/skills/update-changelog/SKILL.md +135 -0
  95. package/skills/web-design/SKILL.md +117 -0
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: openscad
3
+ description: "Create and render OpenSCAD 3D models. Generate preview images from multiple angles, extract customizable parameters, validate syntax, and export STL files for 3D printing platforms like Printables."
4
+ ---
5
+
6
+ # OpenSCAD
7
+
8
+ Create, validate, visually verify, and export OpenSCAD 3D models.
9
+
10
+ ## Requirements
11
+
12
+ The `openscad` executable is available on `PATH` (or discoverable in common locations like `/Applications/OpenSCAD.app` on macOS).
13
+
14
+ ## Scripts
15
+
16
+ This skill ships helper scripts under `scripts/`. Run the commands below from this skill directory.
17
+
18
+ ### Preview generation
19
+
20
+ ```bash
21
+ # Generate a single preview image
22
+ "./scripts/preview.sh" model.scad output.png \
23
+ [--camera=x,y,z,rotx,roty,rotz,distance] [--size=800x600]
24
+
25
+ # Generate multi-angle previews (front, back, left, right, top, iso)
26
+ "./scripts/multi-preview.sh" model.scad output_dir/
27
+ ```
28
+
29
+ ### STL export
30
+
31
+ ```bash
32
+ "./scripts/export-stl.sh" model.scad output.stl [-D 'param=value']
33
+ ```
34
+
35
+ ### Parameter extraction
36
+
37
+ ```bash
38
+ "./scripts/extract-params.sh" model.scad
39
+ ```
40
+
41
+ ### Validation
42
+
43
+ ```bash
44
+ "./scripts/validate.sh" model.scad
45
+ ```
46
+
47
+ ### Render with params from JSON
48
+
49
+ ```bash
50
+ "./scripts/render-with-params.sh" model.scad params.json output.stl
51
+ "./scripts/render-with-params.sh" model.scad params.json output.png
52
+ ```
53
+
54
+ ## Visual validation
55
+
56
+ Always validate models visually after creating or modifying them:
57
+
58
+ 1. Generate multi-angle previews.
59
+ 2. View _each_ generated image with the agent's image viewer (in this environment: the `read` tool).
60
+ 3. Check geometry from multiple perspectives (front/back/left/right/top/iso).
61
+ 4. Iterate until the renders match the intent.
62
+
63
+ Syntax validation alone will not catch common geometry problems (misaligned booleans, missing/floating geometry, inverted geometry, z-fighting, wrong proportions).
64
+
65
+ ## Workflow
66
+
67
+ ### 1) Create a parametric model
68
+
69
+ Put customizable parameters at the top and keep the model code below.
70
+
71
+ ```openscad
72
+ // Customizable parameters
73
+ wall_thickness = 2; // [1:0.5:5] Wall thickness in mm
74
+ width = 50; // [20:100] Width in mm
75
+ height = 30; // [10:80] Height in mm
76
+ rounded = true; // Add rounded corners
77
+
78
+ module main_shape() {
79
+ if (rounded) {
80
+ minkowski() {
81
+ cube([width - 4, width - 4, height - 2]);
82
+ sphere(r = 2);
83
+ }
84
+ } else {
85
+ cube([width, width, height]);
86
+ }
87
+ }
88
+
89
+ difference() {
90
+ main_shape();
91
+ translate([wall_thickness, wall_thickness, wall_thickness])
92
+ scale([1 - 2*wall_thickness/width, 1 - 2*wall_thickness/width, 1])
93
+ main_shape();
94
+ }
95
+ ```
96
+
97
+ Parameter comment formats:
98
+
99
+ - `// [min:max]` numeric range
100
+ - `// [min:step:max]` numeric range with step
101
+ - `// [opt1, opt2, opt3]` dropdown options
102
+ - `// Description` free-form description
103
+
104
+ ### 2) Validate
105
+
106
+ ```bash
107
+ "./scripts/validate.sh" model.scad
108
+ ```
109
+
110
+ ### 3) Render previews (then inspect them)
111
+
112
+ ```bash
113
+ "./scripts/multi-preview.sh" model.scad ./previews/
114
+ ```
115
+
116
+ Use `read` to open each PNG in `./previews/` and confirm the model is correct.
117
+
118
+ ### 4) Export STL
119
+
120
+ ```bash
121
+ "./scripts/export-stl.sh" model.scad output.stl
122
+
123
+ # With parameter overrides:
124
+ "./scripts/export-stl.sh" model.scad output.stl -D 'width=60' -D 'height=40'
125
+ ```
126
+
127
+ ## Camera positions
128
+
129
+ Common camera angles:
130
+
131
+ - Isometric: `--camera=0,0,0,45,0,45,200`
132
+ - Front: `--camera=0,0,0,90,0,0,200`
133
+ - Top: `--camera=0,0,0,0,0,0,200`
134
+ - Right: `--camera=0,0,0,90,0,90,200`
135
+
136
+ Format: `x,y,z,rotx,roty,rotz,distance`
137
+
138
+ ## Printables publishing checklist
139
+
140
+ Typically you need:
141
+
142
+ 1. STL file(s) exported via `export-stl.sh`
143
+ 2. Preview images (at least one strong hero/isometric view plus extra angles)
144
+ 3. A model description covering customizable parameters, print settings, and assembly/use notes
145
+ 4. License/category/tags filled in for discoverability
146
+
147
+ ## Examples
148
+
149
+ Sample models live under `examples/`.
@@ -0,0 +1,92 @@
1
+ // Parametric Box with Lid
2
+ // A customizable storage box for 3D printing
3
+
4
+ // === Box Parameters ===
5
+ width = 60; // [20:200] Width in mm
6
+ depth = 40; // [20:200] Depth in mm
7
+ height = 30; // [10:150] Height in mm
8
+ wall_thickness = 2; // [1:0.5:5] Wall thickness in mm
9
+
10
+ // === Lid Parameters ===
11
+ include_lid = true; // Include a separate lid
12
+ lid_height = 8; // [5:30] Lid height in mm
13
+ lid_tolerance = 0.3; // [0.1:0.1:0.8] Gap for lid fit
14
+
15
+ // === Style Options ===
16
+ corner_radius = 3; // [0:10] Corner rounding radius
17
+ add_grip = true; // Add grip indents to lid
18
+
19
+ // === Internal ===
20
+ $fn = 32; // Smoothness
21
+
22
+ // Rounded box module
23
+ module rounded_box(w, d, h, r) {
24
+ if (r > 0) {
25
+ hull() {
26
+ for (x = [r, w-r]) {
27
+ for (y = [r, d-r]) {
28
+ translate([x, y, 0])
29
+ cylinder(h = h, r = r);
30
+ }
31
+ }
32
+ }
33
+ } else {
34
+ cube([w, d, h]);
35
+ }
36
+ }
37
+
38
+ // Main box body
39
+ module box_body() {
40
+ difference() {
41
+ rounded_box(width, depth, height, corner_radius);
42
+
43
+ // Hollow inside
44
+ translate([wall_thickness, wall_thickness, wall_thickness])
45
+ rounded_box(
46
+ width - 2*wall_thickness,
47
+ depth - 2*wall_thickness,
48
+ height, // Open top
49
+ max(0, corner_radius - wall_thickness)
50
+ );
51
+ }
52
+ }
53
+
54
+ // Lid
55
+ module lid() {
56
+ inner_w = width - 2*wall_thickness - 2*lid_tolerance;
57
+ inner_d = depth - 2*wall_thickness - 2*lid_tolerance;
58
+ lip_height = lid_height * 0.6;
59
+
60
+ difference() {
61
+ union() {
62
+ // Top cap
63
+ rounded_box(width, depth, wall_thickness, corner_radius);
64
+
65
+ // Inner lip
66
+ translate([wall_thickness + lid_tolerance, wall_thickness + lid_tolerance, -lip_height + wall_thickness])
67
+ rounded_box(inner_w, inner_d, lip_height, max(0, corner_radius - wall_thickness));
68
+ }
69
+
70
+ // Grip indents
71
+ if (add_grip) {
72
+ for (x = [width * 0.3, width * 0.7]) {
73
+ translate([x, -1, wall_thickness/2])
74
+ rotate([-90, 0, 0])
75
+ cylinder(h = 5, r = 3, $fn = 16);
76
+ translate([x, depth - 4, wall_thickness/2])
77
+ rotate([-90, 0, 0])
78
+ cylinder(h = 5, r = 3, $fn = 16);
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ // Render
85
+ box_body();
86
+
87
+ if (include_lid) {
88
+ // Position lid next to box for printing
89
+ translate([width + 10, 0, lid_height - wall_thickness])
90
+ rotate([180, 0, 0])
91
+ lid();
92
+ }
@@ -0,0 +1,95 @@
1
+ // Adjustable Phone/Tablet Stand
2
+ // Parametric stand with customizable angle and size
3
+
4
+ // === Device Parameters ===
5
+ device_width = 80; // [50:200] Device width in mm
6
+ device_thickness = 12; // [6:20] Device thickness (with case)
7
+
8
+ // === Stand Parameters ===
9
+ stand_angle = 65; // [45:85] Viewing angle in degrees
10
+ stand_depth = 80; // [50:150] Base depth in mm
11
+ stand_height = 100; // [60:200] Back support height in mm
12
+
13
+ // === Construction ===
14
+ material_thickness = 4; // [2:0.5:8] Material thickness
15
+ slot_depth = 15; // [10:30] How deep device sits in slot
16
+
17
+ // === Features ===
18
+ cable_hole = true; // Add cable pass-through hole
19
+ cable_diameter = 15; // [8:25] Cable hole diameter
20
+ add_feet = true; // Add anti-slip feet
21
+
22
+ // === Quality ===
23
+ $fn = 48;
24
+
25
+ module stand_profile() {
26
+ // 2D profile of the stand side
27
+ polygon([
28
+ [0, 0], // Front bottom
29
+ [stand_depth, 0], // Back bottom
30
+ [stand_depth, material_thickness], // Back bottom inner
31
+ [stand_depth - material_thickness, material_thickness], // Base top back
32
+ [slot_depth + material_thickness, material_thickness], // Base top front (behind slot)
33
+ [slot_depth + material_thickness, slot_depth * tan(90 - stand_angle) + material_thickness], // Slot back
34
+ [material_thickness, slot_depth * tan(90 - stand_angle) + material_thickness + device_thickness / sin(stand_angle)], // Slot front top
35
+ [0, slot_depth * tan(90 - stand_angle) + material_thickness], // Front face bottom of slot
36
+ [0, 0] // Close
37
+ ]);
38
+ }
39
+
40
+ module back_support() {
41
+ // Back angled support
42
+ translate([stand_depth - material_thickness, 0, material_thickness]) {
43
+ rotate([0, -90 + stand_angle, 0]) {
44
+ cube([stand_height, device_width, material_thickness]);
45
+ }
46
+ }
47
+ }
48
+
49
+ module cable_cutout() {
50
+ if (cable_hole) {
51
+ translate([stand_depth/2, device_width/2, -1])
52
+ cylinder(h = material_thickness + 2, d = cable_diameter);
53
+ }
54
+ }
55
+
56
+ module foot() {
57
+ cylinder(h = 2, d1 = 10, d2 = 8);
58
+ }
59
+
60
+ module stand() {
61
+ difference() {
62
+ union() {
63
+ // Left side
64
+ linear_extrude(material_thickness)
65
+ stand_profile();
66
+
67
+ // Right side
68
+ translate([0, device_width - material_thickness, 0])
69
+ linear_extrude(material_thickness)
70
+ stand_profile();
71
+
72
+ // Base plate
73
+ cube([stand_depth, device_width, material_thickness]);
74
+
75
+ // Front lip
76
+ cube([material_thickness, device_width, slot_depth * tan(90 - stand_angle) + material_thickness]);
77
+
78
+ // Back support
79
+ back_support();
80
+ }
81
+
82
+ // Cable hole
83
+ cable_cutout();
84
+ }
85
+
86
+ // Feet
87
+ if (add_feet) {
88
+ translate([10, 10, 0]) foot();
89
+ translate([10, device_width - 10, 0]) foot();
90
+ translate([stand_depth - 10, 10, 0]) foot();
91
+ translate([stand_depth - 10, device_width - 10, 0]) foot();
92
+ }
93
+ }
94
+
95
+ stand();
@@ -0,0 +1,49 @@
1
+ #!/bin/bash
2
+ # Common utilities for OpenSCAD tools
3
+
4
+ # Find OpenSCAD executable
5
+ find_openscad() {
6
+ # Check common locations
7
+ if command -v openscad &> /dev/null; then
8
+ echo "openscad"
9
+ return 0
10
+ fi
11
+
12
+ # macOS Application bundle
13
+ if [ -d "/Applications/OpenSCAD.app" ]; then
14
+ echo "/Applications/OpenSCAD.app/Contents/MacOS/OpenSCAD"
15
+ return 0
16
+ fi
17
+
18
+ # Homebrew on Apple Silicon
19
+ if [ -x "/opt/homebrew/bin/openscad" ]; then
20
+ echo "/opt/homebrew/bin/openscad"
21
+ return 0
22
+ fi
23
+
24
+ # Homebrew on Intel
25
+ if [ -x "/usr/local/bin/openscad" ]; then
26
+ echo "/usr/local/bin/openscad"
27
+ return 0
28
+ fi
29
+
30
+ return 1
31
+ }
32
+
33
+ # Check if OpenSCAD is available
34
+ check_openscad() {
35
+ OPENSCAD=$(find_openscad) || {
36
+ echo "Error: OpenSCAD executable not found."
37
+ echo ""
38
+ echo "Please ensure OpenSCAD is already installed and available as 'openscad' in your PATH,"
39
+ echo "or located in a common location (e.g. /Applications/OpenSCAD.app on macOS)."
40
+ exit 1
41
+ }
42
+ export OPENSCAD
43
+ }
44
+
45
+ # Get version info
46
+ openscad_version() {
47
+ check_openscad
48
+ $OPENSCAD --version 2>&1
49
+ }
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+ # Export OpenSCAD file to STL
3
+ # Usage: export-stl.sh input.scad output.stl [-D 'var=value' ...]
4
+
5
+ set -e
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ source "$SCRIPT_DIR/common.sh"
9
+
10
+ check_openscad
11
+
12
+ if [ $# -lt 2 ]; then
13
+ echo "Usage: $0 input.scad output.stl [-D 'var=value' ...]"
14
+ echo ""
15
+ echo "Examples:"
16
+ echo " $0 box.scad box.stl"
17
+ echo " $0 box.scad box_large.stl -D 'width=80' -D 'height=60'"
18
+ exit 1
19
+ fi
20
+
21
+ INPUT="$1"
22
+ OUTPUT="$2"
23
+ shift 2
24
+
25
+ # Collect -D parameters
26
+ DEFINES=()
27
+ while [ $# -gt 0 ]; do
28
+ case "$1" in
29
+ -D)
30
+ shift
31
+ DEFINES+=("-D" "$1")
32
+ ;;
33
+ *)
34
+ echo "Unknown option: $1"
35
+ exit 1
36
+ ;;
37
+ esac
38
+ shift
39
+ done
40
+
41
+ # Ensure output directory exists
42
+ mkdir -p "$(dirname "$OUTPUT")"
43
+
44
+ echo "Exporting STL: $INPUT -> $OUTPUT"
45
+ if [ ${#DEFINES[@]} -gt 0 ]; then
46
+ echo "Parameters: ${DEFINES[*]}"
47
+ fi
48
+
49
+ $OPENSCAD \
50
+ "${DEFINES[@]}" \
51
+ -o "$OUTPUT" \
52
+ "$INPUT"
53
+
54
+ # Show file info
55
+ SIZE=$(ls -lh "$OUTPUT" | awk '{print $5}')
56
+ echo "STL exported: $OUTPUT ($SIZE)"
@@ -0,0 +1,147 @@
1
+ #!/bin/bash
2
+ # Extract customizable parameters from an OpenSCAD file
3
+ # Usage: extract-params.sh input.scad [--json]
4
+ #
5
+ # Parses parameter declarations with special comments:
6
+ # param = value; // [min:max] Description
7
+ # param = value; // [min:step:max] Description
8
+ # param = value; // [opt1, opt2] Description
9
+ # param = value; // Description only
10
+
11
+ set -e
12
+
13
+ if [ $# -lt 1 ]; then
14
+ echo "Usage: $0 input.scad [--json]"
15
+ exit 1
16
+ fi
17
+
18
+ INPUT="$1"
19
+ JSON_OUTPUT=false
20
+
21
+ if [ "$2" = "--json" ]; then
22
+ JSON_OUTPUT=true
23
+ fi
24
+
25
+ if [ ! -f "$INPUT" ]; then
26
+ echo "Error: File not found: $INPUT"
27
+ exit 1
28
+ fi
29
+
30
+ # Extract parameters using Python for better parsing
31
+ extract_params() {
32
+ python3 -c '
33
+ import sys
34
+ import re
35
+
36
+ filename = sys.argv[1]
37
+ in_block = 0
38
+
39
+ with open(filename, "r") as f:
40
+ for line in f:
41
+ # Track block depth (skip params inside modules/functions)
42
+ in_block += line.count("{") - line.count("}")
43
+ if in_block > 0:
44
+ continue
45
+
46
+ # Match: varname = value; // comment
47
+ match = re.match(r"^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([^;]+);\s*(?://\s*(.*))?", line)
48
+ if not match:
49
+ continue
50
+
51
+ var_name = match.group(1)
52
+ value = match.group(2).strip()
53
+ comment = match.group(3) or ""
54
+
55
+ # Determine type
56
+ if value in ("true", "false"):
57
+ var_type = "boolean"
58
+ elif re.match(r"^-?\d+$", value):
59
+ var_type = "integer"
60
+ elif re.match(r"^-?\d*\.?\d+$", value):
61
+ var_type = "number"
62
+ elif value.startswith("\"") and value.endswith("\""):
63
+ var_type = "string"
64
+ value = value[1:-1] # Remove quotes
65
+ elif value.startswith("["):
66
+ var_type = "array"
67
+ else:
68
+ var_type = "expression"
69
+
70
+ # Parse comment for range/options
71
+ range_val = ""
72
+ options_val = ""
73
+ description = comment
74
+
75
+ range_match = re.match(r"\[([^\]]+)\]\s*(.*)", comment)
76
+ if range_match:
77
+ bracket_content = range_match.group(1)
78
+ description = range_match.group(2)
79
+
80
+ # Check if numeric range (contains :) or options (contains ,)
81
+ if ":" in bracket_content and not "," in bracket_content:
82
+ range_val = bracket_content
83
+ else:
84
+ options_val = bracket_content
85
+
86
+ # Output pipe-delimited
87
+ print(f"{var_name}|{value}|{var_type}|{range_val}|{options_val}|{description}")
88
+ ' "$INPUT"
89
+ }
90
+
91
+ if [ "$JSON_OUTPUT" = true ]; then
92
+ echo "["
93
+ first=true
94
+ while IFS='|' read -r name value type range options description; do
95
+ if [ "$first" = true ]; then
96
+ first=false
97
+ else
98
+ echo ","
99
+ fi
100
+
101
+ # Escape quotes in values
102
+ value=$(echo "$value" | sed 's/"/\\"/g')
103
+ description=$(echo "$description" | sed 's/"/\\"/g')
104
+
105
+ # Build JSON object
106
+ printf ' {\n'
107
+ printf ' "name": "%s",\n' "$name"
108
+ printf ' "value": "%s",\n' "$value"
109
+ printf ' "type": "%s"' "$type"
110
+
111
+ if [ -n "$range" ]; then
112
+ printf ',\n "range": "%s"' "$range"
113
+ fi
114
+ if [ -n "$options" ]; then
115
+ printf ',\n "options": "%s"' "$options"
116
+ fi
117
+ if [ -n "$description" ]; then
118
+ printf ',\n "description": "%s"' "$description"
119
+ fi
120
+ printf '\n }'
121
+ done < <(extract_params)
122
+ echo ""
123
+ echo "]"
124
+ else
125
+ echo "Parameters in: $INPUT"
126
+ echo "==============================================="
127
+ printf "%-20s %-15s %-10s %s\n" "NAME" "VALUE" "TYPE" "CONSTRAINT/DESC"
128
+ echo "-----------------------------------------------"
129
+
130
+ while IFS='|' read -r name value type range options description; do
131
+ constraint=""
132
+ if [ -n "$range" ]; then
133
+ constraint="[$range]"
134
+ elif [ -n "$options" ]; then
135
+ constraint="[$options]"
136
+ fi
137
+ if [ -n "$description" ]; then
138
+ if [ -n "$constraint" ]; then
139
+ constraint="$constraint $description"
140
+ else
141
+ constraint="$description"
142
+ fi
143
+ fi
144
+
145
+ printf "%-20s %-15s %-10s %s\n" "$name" "$value" "$type" "$constraint"
146
+ done < <(extract_params)
147
+ fi
@@ -0,0 +1,68 @@
1
+ #!/bin/bash
2
+ # Generate preview images from multiple angles
3
+ # Usage: multi-preview.sh input.scad output_dir/ [-D 'var=value']
4
+
5
+ set -e
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ source "$SCRIPT_DIR/common.sh"
9
+
10
+ check_openscad
11
+
12
+ if [ $# -lt 2 ]; then
13
+ echo "Usage: $0 input.scad output_dir/ [-D 'var=value' ...]"
14
+ exit 1
15
+ fi
16
+
17
+ INPUT="$1"
18
+ OUTPUT_DIR="$2"
19
+ shift 2
20
+
21
+ # Collect -D parameters
22
+ DEFINES=()
23
+ while [ $# -gt 0 ]; do
24
+ case "$1" in
25
+ -D)
26
+ shift
27
+ DEFINES+=("-D" "$1")
28
+ ;;
29
+ esac
30
+ shift
31
+ done
32
+
33
+ mkdir -p "$OUTPUT_DIR"
34
+
35
+ # Get base name without extension
36
+ BASENAME=$(basename "$INPUT" .scad)
37
+
38
+ echo "Generating multi-angle previews for: $INPUT"
39
+ echo "Output directory: $OUTPUT_DIR"
40
+ echo ""
41
+
42
+ # Define angles as name:camera pairs
43
+ # Camera format: translate_x,translate_y,translate_z,rot_x,rot_y,rot_z,distance
44
+ ANGLES="iso:0,0,0,55,0,25,0
45
+ front:0,0,0,90,0,0,0
46
+ back:0,0,0,90,0,180,0
47
+ left:0,0,0,90,0,90,0
48
+ right:0,0,0,90,0,-90,0
49
+ top:0,0,0,0,0,0,0"
50
+
51
+ echo "$ANGLES" | while IFS=: read -r angle camera; do
52
+ output="$OUTPUT_DIR/${BASENAME}_${angle}.png"
53
+
54
+ echo " Rendering $angle view..."
55
+ $OPENSCAD \
56
+ --camera="$camera" \
57
+ --imgsize="800,600" \
58
+ --colorscheme="Tomorrow Night" \
59
+ --autocenter \
60
+ --viewall \
61
+ "${DEFINES[@]}" \
62
+ -o "$output" \
63
+ "$INPUT" 2>/dev/null
64
+ done
65
+
66
+ echo ""
67
+ echo "Generated previews:"
68
+ ls -la "$OUTPUT_DIR"/${BASENAME}_*.png